<T>LAPACK 0.1.1
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
lassq.hpp
Go to the documentation of this file.
1
8//
9// Copyright (c) 2021-2023, University of Colorado Denver. All rights reserved.
10//
11// This file is part of <T>LAPACK.
12// <T>LAPACK is free software: you can redistribute it and/or modify it under
13// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
14
15#ifndef TLAPACK_LASSQ_HH
16#define TLAPACK_LASSQ_HH
17
20
21namespace tlapack {
22
48template <class abs_f, TLAPACK_VECTOR vector_t>
49void lassq(const vector_t& x,
52 abs_f absF)
53{
55 using idx_t = size_type<vector_t>;
56
57 // constants
58 const idx_t n = size(x);
59
60 // constants
61 const real_t zero(0);
62 const real_t one(1);
67
68 // quick return
69 if (isnan(scale) || isnan(sumsq)) return;
70
71 if (sumsq == zero) scale = one;
72 if (scale == zero) {
73 scale = one;
74 sumsq = zero;
75 }
76
77 // quick return
78 if (n <= 0) return;
79
80 // Compute the sum of squares in 3 accumulators:
81 // abig -- sums of squares scaled down to avoid overflow
82 // asml -- sums of squares scaled up to avoid underflow
83 // amed -- sums of squares that do not require scaling
84 // The thresholds and multipliers are
85 // tbig -- values bigger than this are scaled down by sbig
86 // tsml -- values smaller than this are scaled up by ssml
87
91
92 for (idx_t i = 0; i < n; ++i) {
93 real_t ax = absF(x[i]);
94 if (ax > tbig)
95 abig += (ax * sbig) * (ax * sbig);
96 else if (ax < tsml) {
97 if (abig == zero) asml += (ax * ssml) * (ax * ssml);
98 }
99 else
100 amed += ax * ax;
101 }
102
103 // Put the existing sum of squares into one of the accumulators
104 if (sumsq > zero) {
105 real_t ax = scale * sqrt(sumsq);
106 if (ax > tbig) {
107 if (scale > one) {
108 scale *= sbig;
109 abig += scale * (scale * sumsq);
110 }
111 else {
112 // sumsq > tbig^2 => (sbig * (sbig * sumsq)) is representable
113 abig += scale * (scale * (sbig * (sbig * sumsq)));
114 }
115 }
116 else if (ax < tsml) {
117 if (abig == zero) {
118 if (scale < one) {
119 scale *= ssml;
120 asml += scale * (scale * sumsq);
121 }
122 else {
123 // sumsq < tsml^2 => (ssml * (ssml * sumsq)) is
124 // representable
125 asml += scale * (scale * (ssml * (ssml * sumsq)));
126 }
127 }
128 }
129 else {
130 amed += scale * (scale * sumsq);
131 }
132 }
133
134 // Combine abig and amed or amed and asml if
135 // more than one accumulator was used.
136
137 if (abig > zero) {
138 // Combine abig and amed if abig > 0
139 if (amed > zero || isnan(amed)) abig += (amed * sbig) * sbig;
140 scale = one / sbig;
141 sumsq = abig;
142 }
143 else if (asml > zero) {
144 // Combine amed and asml if asml > 0
145 if (amed > zero || isnan(amed)) {
146 amed = sqrt(amed);
147 asml = sqrt(asml) / ssml;
148
150 if (asml > amed) {
151 ymin = amed;
152 ymax = asml;
153 }
154 else {
155 ymin = asml;
156 ymax = amed;
157 }
158
159 scale = one;
160 sumsq = (ymax * ymax) * (one + (ymin / ymax) * (ymin / ymax));
161 }
162 else {
163 scale = one / ssml;
164 sumsq = asml;
165 }
166 }
167 else {
168 // Otherwise all values are mid-range or zero
169 scale = one;
170 sumsq = amed;
171 }
172}
173
191template <TLAPACK_VECTOR vector_t>
192void lassq(const vector_t& x,
195{
196 using T = type_t<vector_t>;
197 return lassq(x, scale, sumsq,
198 // Lambda function that returns the absolute value using abs :
199 [](const T& x) { return abs(x); });
200}
201
202} // namespace tlapack
203
204#endif // TLAPACK_LASSQ_HH
constexpr bool isnan(const T &x) noexcept
Extends std::isnan() to complex numbers.
Definition utils.hpp:125
void lassq(const vector_t &x, real_type< type_t< vector_t > > &scale, real_type< type_t< vector_t > > &sumsq, abs_f absF)
Updates a sum of squares represented in scaled form.
Definition lassq.hpp:49
typename traits::real_type_traits< Types..., int >::type real_type
The common real type of the list of types.
Definition scalar_type_traits.hpp:113