BLAS++ 2024.05.31
BLAS C++ API
Loading...
Searching...
No Matches
rotg.hh
1// Copyright (c) 2017-2023, University of Tennessee. All rights reserved.
2// SPDX-License-Identifier: BSD-3-Clause
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
5
6#ifndef BLAS_ROTG_HH
7#define BLAS_ROTG_HH
8
9#include "blas/util.hh"
10
11#include <limits>
12
13namespace blas {
14
15// =============================================================================
45
46template <typename TA, typename TB>
47void rotg(
48 TA *a,
49 TB *b,
50 blas::real_type<TA, TB> *c,
51 blas::real_type<TA, TB> *s )
52{
53 typedef real_type<TA, TB> real_t;
54 using std::abs;
55
56 // Constants
57 const real_t one = 1;
58 const real_t zero = 0;
59
60 // Scaling constants
61 const real_t safmin = safe_min<real_t>();
62 const real_t safmax = safe_max<real_t>();
63
64 // Norms
65 const real_t anorm = abs(*a);
66 const real_t bnorm = abs(*b);
67
68 // quick return
69 if (bnorm == zero) {
70 *c = one;
71 *s = zero;
72 *b = TB( 0.0 );
73 }
74 else if (anorm == zero) {
75 *c = zero;
76 *s = one;
77 *a = *b;
78 *b = TB( 1.0 );
79 }
80 else {
81 real_t scl = min( safmax, max(safmin, anorm, bnorm) );
82 real_t sigma = (anorm > bnorm)
83 ? sgn(*a)
84 : sgn(*b);
85 real_t r = sigma * scl * sqrt( (*a/scl) * (*a/scl) + (*b/scl) * (*b/scl) );
86 *c = *a / r;
87 *s = *b / r;
88 *a = r;
89 if (anorm > bnorm)
90 *b = *s;
91 else if (*c != zero)
92 *b = one / *c;
93 else
94 *b = one;
95 }
96}
97
98// =============================================================================
128
129template <typename TA, typename TB>
130void rotg(
131 std::complex<TA> *a,
132 std::complex<TB> *b,
133 blas::real_type<TA, TB> *c,
134 blas::complex_type<TA, TB> *s )
135{
136 typedef real_type<TA, TB> real_t;
137 typedef complex_type<TA, TB> scalar_t;
138 using std::abs;
139
140 #define BLAS_ABSSQ(t_) real(t_)*real(t_) + imag(t_)*imag(t_)
141
142 // Constants
143 const real_t r_one = 1;
144 const real_t r_zero = 0;
145 const scalar_t zero = 0;
146 const std::complex<TA> zero_ta = 0;
147 const std::complex<TB> zero_tb = 0;
148
149 // Scaling constants
150 const real_t safmin = safe_min<real_t>();
151 const real_t safmax = safe_max<real_t>();
152 const real_t rtmin = root_min<real_t>();
153 const real_t rtmax = root_max<real_t>();
154
155 // quick return
156 if (*b == zero_tb) {
157 *c = r_one;
158 *s = zero;
159 return;
160 }
161
162 if (*a == zero_ta) {
163 *c = r_zero;
164 real_t g1 = max( abs(real(*b)), abs(imag(*b)) );
165 if (g1 > rtmin && g1 < rtmax) {
166 // Use unscaled algorithm
167 real_t g2 = BLAS_ABSSQ( *b );
168 real_t d = sqrt( g2 );
169 *s = conj( *b ) / d;
170 *a = d;
171 }
172 else {
173 // Use scaled algorithm
174 real_t u = min( safmax, max( safmin, g1 ) );
175 real_t uu = r_one / u;
176 scalar_t gs = (*b)*uu;
177 real_t g2 = BLAS_ABSSQ( gs );
178 real_t d = sqrt( g2 );
179 *s = conj( gs ) / d;
180 *a = d*u;
181 }
182 }
183 else {
184 real_t f1 = max( abs(real(*a)), abs(imag(*a)) );
185 real_t g1 = max( abs(real(*b)), abs(imag(*b)) );
186 if (f1 > rtmin && f1 < rtmax
187 && g1 > rtmin && g1 < rtmax) {
188 // Use unscaled algorithm
189 real_t f2 = BLAS_ABSSQ( *a );
190 real_t g2 = BLAS_ABSSQ( *b );
191 real_t h2 = f2 + g2;
192 real_t d = ( f2 > rtmin && h2 < rtmax )
193 ? sqrt( f2*h2 )
194 : sqrt( f2 )*sqrt( h2 );
195 real_t p = r_one / d;
196 *c = f2*p;
197 *s = conj( *b )*( (*a)*p );
198 *a *= h2*p;
199 }
200 else {
201 // Use scaled algorithm
202 real_t u = min( safmax, max( safmin, f1, g1 ) );
203 real_t uu = r_one / u;
204 scalar_t gs = (*b)*uu;
205 real_t g2 = BLAS_ABSSQ( gs );
206 real_t f2, h2, w;
207 scalar_t fs;
208 if (f1*uu < rtmin) {
209 // a is not well-scaled when scaled by g1.
210 real_t v = min( safmax, max( safmin, f1 ) );
211 real_t vv = r_one / v;
212 w = v * uu;
213 fs = (*a)*vv;
214 f2 = BLAS_ABSSQ( fs );
215 h2 = f2*w*w + g2;
216 }
217 else {
218 // Otherwise use the same scaling for a and b.
219 w = r_one;
220 fs = (*a)*uu;
221 f2 = BLAS_ABSSQ( fs );
222 h2 = f2 + g2;
223 }
224 real_t d = ( f2 > rtmin && h2 < rtmax )
225 ? sqrt( f2*h2 )
226 : sqrt( f2 )*sqrt( h2 );
227 real_t p = r_one / d;
228 *c = ( f2*p )*w;
229 *s = conj( gs )*( fs*p );
230 *a = ( fs*( h2*p ) )*u;
231 }
232 }
233
234 #undef BLAS_ABSSQ
235}
236
237} // namespace blas
238
239#endif // #ifndef BLAS_ROTG_HH
void rotg(TA *a, TB *b, blas::real_type< TA, TB > *c, blas::real_type< TA, TB > *s)
Construct plane rotation that eliminates b, such that:
Definition rotg.hh:47