4 #include "BenchTimer.h"
9 EIGEN_DONT_INLINE typename
T::Scalar
sqsumNorm(T
& v
)
15 EIGEN_DONT_INLINE typename
T::Scalar
stableNorm(T
& v
)
17 return v
.stableNorm();
21 EIGEN_DONT_INLINE typename
T::Scalar
hypotNorm(T
& v
)
27 EIGEN_DONT_INLINE typename
T::Scalar
blueNorm(T
& v
)
33 EIGEN_DONT_INLINE typename
T::Scalar
lapackNorm(T
& v
)
35 typedef typename
T::Scalar Scalar
;
41 Scalar ax
= std::abs(v
.coeff(i
));
44 ssq
+= numext::abs2(ax
/scale
);
48 ssq
= Scalar(1) + ssq
* numext::abs2(scale
/ax
);
52 return scale
* std::sqrt(ssq
);
56 EIGEN_DONT_INLINE typename
T::Scalar
twopassNorm(T
& v
)
58 typedef typename
T::Scalar Scalar
;
59 Scalar s
= v
.array().abs().maxCoeff();
60 return s
*(v
/s
).norm();
64 EIGEN_DONT_INLINE typename
T::Scalar
bl2passNorm(T
& v
)
66 return v
.stableNorm();
70 EIGEN_DONT_INLINE typename
T::Scalar
divacNorm(T
& v
)
74 v(i
) = v(2*i
)*v(2*i
) + v(2*i
+1)*v(2*i
+1);
79 v(i
) = v(2*i
) + v(2*i
+1);
82 return std::sqrt(v(0));
87 #ifdef EIGEN_VECTORIZE
88 Packet4f
plt(const Packet4f
& a
, Packet4f
& b
) { return _mm_cmplt_ps(a
,b
); }
89 Packet2d
plt(const Packet2d
& a
, Packet2d
& b
) { return _mm_cmplt_pd(a
,b
); }
91 Packet4f
pandnot(const Packet4f
& a
, Packet4f
& b
) { return _mm_andnot_ps(a
,b
); }
92 Packet2d
pandnot(const Packet2d
& a
, Packet2d
& b
) { return _mm_andnot_pd(a
,b
); }
98 EIGEN_DONT_INLINE typename
T::Scalar
pblueNorm(const T
& v
)
100 #ifndef EIGEN_VECTORIZE
103 typedef typename
T::Scalar Scalar
;
106 static Scalar b1
, b2
, s1m
, s2m
, overfl
, rbig
, relerr
;
111 int nbig
, ibeta
, it
, iemin
, iemax
, iexp
;
114 nbig
= std::numeric_limits
<int>::max(); // largest integer
115 ibeta
= std::numeric_limits
<Scalar
>::radix
; //NumTraits<Scalar>::Base; // base for floating-point numbers
116 it
= std::numeric_limits
<Scalar
>::digits
; //NumTraits<Scalar>::Mantissa; // number of base-beta digits in mantissa
117 iemin
= std::numeric_limits
<Scalar
>::min_exponent
; // minimum exponent
118 iemax
= std::numeric_limits
<Scalar
>::max_exponent
; // maximum exponent
119 rbig
= std::numeric_limits
<Scalar
>::max(); // largest floating-point number
121 // Check the basic machine-dependent constants.
122 if(iemin
> 1 - 2*it
|| 1+it
>iemax
|| (it
==2 && ibeta
<5)
123 || (it
<=4 && ibeta
<= 3 ) || it
<2)
125 eigen_assert(false && "the algorithm cannot be guaranteed on this computer");
127 iexp
= -((1-iemin
)/2);
128 b1
= std::pow(ibeta
, iexp
); // lower boundary of midrange
129 iexp
= (iemax
+ 1 - it
)/2;
130 b2
= std::pow(ibeta
,iexp
); // upper boundary of midrange
133 s1m
= std::pow(ibeta
,iexp
); // scaling factor for lower range
134 iexp
= - ((iemax
+it
)/2);
135 s2m
= std::pow(ibeta
,iexp
); // scaling factor for upper range
137 overfl
= rbig
*s2m
; // overfow boundary for abig
138 eps
= std::pow(ibeta
, 1-it
);
139 relerr
= std::sqrt(eps
); // tolerance for neglecting asml
140 abig
= 1.0/eps
- 1.0;
141 if (Scalar(nbig
)>abig
) nmax
= abig
; // largest safe n
145 typedef typename
internal::packet_traits
<Scalar
>::type Packet
;
146 const int ps
= internal::packet_traits
<Scalar
>::size
;
147 Packet pasml
= internal::pset1
<Packet
>(Scalar(0));
148 Packet pamed
= internal::pset1
<Packet
>(Scalar(0));
149 Packet pabig
= internal::pset1
<Packet
>(Scalar(0));
150 Packet ps2m
= internal::pset1
<Packet
>(s2m
);
151 Packet ps1m
= internal::pset1
<Packet
>(s1m
);
152 Packet pb2
= internal::pset1
<Packet
>(b2
);
153 Packet pb1
= internal::pset1
<Packet
>(b1
);
154 for(int j
=0; j
<v
.size(); j
+=ps
)
156 Packet ax
= internal::pabs(v
.template packet
<Aligned
>(j
));
157 Packet ax_s2m
= internal::pmul(ax
,ps2m
);
158 Packet ax_s1m
= internal::pmul(ax
,ps1m
);
159 Packet maskBig
= internal::plt(pb2
,ax
);
160 Packet maskSml
= internal::plt(ax
,pb1
);
162 // Packet maskMed = internal::pand(maskSml,maskBig);
163 // Packet scale = internal::pset1(Scalar(0));
164 // scale = internal::por(scale, internal::pand(maskBig,ps2m));
165 // scale = internal::por(scale, internal::pand(maskSml,ps1m));
166 // scale = internal::por(scale, internal::pandnot(internal::pset1(Scalar(1)),maskMed));
167 // ax = internal::pmul(ax,scale);
168 // ax = internal::pmul(ax,ax);
169 // pabig = internal::padd(pabig, internal::pand(maskBig, ax));
170 // pasml = internal::padd(pasml, internal::pand(maskSml, ax));
171 // pamed = internal::padd(pamed, internal::pandnot(ax,maskMed));
174 pabig
= internal::padd(pabig
, internal::pand(maskBig
, internal::pmul(ax_s2m
,ax_s2m
)));
175 pasml
= internal::padd(pasml
, internal::pand(maskSml
, internal::pmul(ax_s1m
,ax_s1m
)));
176 pamed
= internal::padd(pamed
, internal::pandnot(internal::pmul(ax
,ax
),internal::pand(maskSml
,maskBig
)));
178 Scalar abig
= internal::predux(pabig
);
179 Scalar asml
= internal::predux(pasml
);
180 Scalar amed
= internal::predux(pamed
);
183 abig
= std::sqrt(abig
);
186 eigen_assert(false && "overflow");
192 amed
= std::sqrt(amed
);
200 else if(asml
> Scalar(0))
202 if (amed
> Scalar(0))
204 abig
= std::sqrt(amed
);
205 amed
= std::sqrt(asml
) / s1m
;
209 return std::sqrt(asml
)/s1m
;
214 return std::sqrt(amed
);
216 asml
= std::min(abig
, amed
);
217 abig
= std::max(abig
, amed
);
218 if(asml
<= abig
*relerr
)
221 return abig
* std::sqrt(Scalar(1) + numext::abs2(asml
/abig
));
225 #define BENCH_PERF(NRM) { \
226 float af = 0; double ad = 0; std::complex<float> ac = 0; \
227 Eigen::BenchTimer tf, td, tcf; tf.reset(); td.reset(); tcf.reset();\
228 for (int k=0; k<tries; ++k) { \
230 for (int i=0; i<iters; ++i) { af += NRM(vf); } \
233 for (int k=0; k<tries; ++k) { \
235 for (int i=0; i<iters; ++i) { ad += NRM(vd); } \
238 /*for (int k=0; k<std::max(1,tries/3); ++k) { \
240 for (int i=0; i<iters; ++i) { ac += NRM(vcf); } \
243 std::cout << #NRM << "\t" << tf.value() << " " << td.value() << " " << tcf.value() << "\n"; \
246 void check_accuracy(double basef
, double based
, int s
)
248 double yf
= basef
* std::abs(internal::random
<double>());
249 double yd
= based
* std::abs(internal::random
<double>());
250 VectorXf vf
= VectorXf::Ones(s
) * yf
;
251 VectorXd vd
= VectorXd::Ones(s
) * yd
;
253 std::cout
<< "reference\t" << std::sqrt(double(s
))*yf
<< "\t" << std::sqrt(double(s
))*yd
<< "\n";
254 std::cout
<< "sqsumNorm\t" << sqsumNorm(vf
) << "\t" << sqsumNorm(vd
) << "\n";
255 std::cout
<< "hypotNorm\t" << hypotNorm(vf
) << "\t" << hypotNorm(vd
) << "\n";
256 std::cout
<< "blueNorm\t" << blueNorm(vf
) << "\t" << blueNorm(vd
) << "\n";
257 std::cout
<< "pblueNorm\t" << pblueNorm(vf
) << "\t" << pblueNorm(vd
) << "\n";
258 std::cout
<< "lapackNorm\t" << lapackNorm(vf
) << "\t" << lapackNorm(vd
) << "\n";
259 std::cout
<< "twopassNorm\t" << twopassNorm(vf
) << "\t" << twopassNorm(vd
) << "\n";
260 std::cout
<< "bl2passNorm\t" << bl2passNorm(vf
) << "\t" << bl2passNorm(vd
) << "\n";
263 void check_accuracy_var(int ef0
, int ef1
, int ed0
, int ed1
, int s
)
267 for (int i
=0; i
<s
; ++i
)
269 vf
[i
] = std::abs(internal::random
<double>()) * std::pow(double(10), internal::random
<int>(ef0
,ef1
));
270 vd
[i
] = std::abs(internal::random
<double>()) * std::pow(double(10), internal::random
<int>(ed0
,ed1
));
273 //std::cout << "reference\t" << internal::sqrt(double(s))*yf << "\t" << internal::sqrt(double(s))*yd << "\n";
274 std::cout
<< "sqsumNorm\t" << sqsumNorm(vf
) << "\t" << sqsumNorm(vd
) << "\t" << sqsumNorm(vf
.cast
<long double>()) << "\t" << sqsumNorm(vd
.cast
<long double>()) << "\n";
275 std::cout
<< "hypotNorm\t" << hypotNorm(vf
) << "\t" << hypotNorm(vd
) << "\t" << hypotNorm(vf
.cast
<long double>()) << "\t" << hypotNorm(vd
.cast
<long double>()) << "\n";
276 std::cout
<< "blueNorm\t" << blueNorm(vf
) << "\t" << blueNorm(vd
) << "\t" << blueNorm(vf
.cast
<long double>()) << "\t" << blueNorm(vd
.cast
<long double>()) << "\n";
277 std::cout
<< "pblueNorm\t" << pblueNorm(vf
) << "\t" << pblueNorm(vd
) << "\t" << blueNorm(vf
.cast
<long double>()) << "\t" << blueNorm(vd
.cast
<long double>()) << "\n";
278 std::cout
<< "lapackNorm\t" << lapackNorm(vf
) << "\t" << lapackNorm(vd
) << "\t" << lapackNorm(vf
.cast
<long double>()) << "\t" << lapackNorm(vd
.cast
<long double>()) << "\n";
279 std::cout
<< "twopassNorm\t" << twopassNorm(vf
) << "\t" << twopassNorm(vd
) << "\t" << twopassNorm(vf
.cast
<long double>()) << "\t" << twopassNorm(vd
.cast
<long double>()) << "\n";
280 // std::cout << "bl2passNorm\t" << bl2passNorm(vf) << "\t" << bl2passNorm(vd) << "\t" << bl2passNorm(vf.cast<long double>()) << "\t" << bl2passNorm(vd.cast<long double>()) << "\n";
283 int main(int argc
, char** argv
)
287 double y
= 1.1345743233455785456788e12
* internal::random
<double>();
288 VectorXf v
= VectorXf::Ones(1024) * y
;
292 double basef_ok
= 1.1345743233455785456788e15
;
293 double based_ok
= 1.1345743233455785456788e95
;
295 double basef_under
= 1.1345743233455785456788e-27;
296 double based_under
= 1.1345743233455785456788e-303;
298 double basef_over
= 1.1345743233455785456788e+27;
299 double based_over
= 1.1345743233455785456788e+302;
301 std::cout
.precision(20);
303 std::cerr
<< "\nNo under/overflow:\n";
304 check_accuracy(basef_ok
, based_ok
, s
);
306 std::cerr
<< "\nUnderflow:\n";
307 check_accuracy(basef_under
, based_under
, s
);
309 std::cerr
<< "\nOverflow:\n";
310 check_accuracy(basef_over
, based_over
, s
);
312 std::cerr
<< "\nVarying (over):\n";
313 for (int k
=0; k
<1; ++k
)
315 check_accuracy_var(20,27,190,302,s
);
319 std::cerr
<< "\nVarying (under):\n";
320 for (int k
=0; k
<1; ++k
)
322 check_accuracy_var(-27,20,-302,-190,s
);
327 std::cout
.precision(4);
328 int s1
= 1024*1024*32;
329 std::cerr
<< "Performance (out of cache, " << s1
<< "):\n";
332 VectorXf vf
= VectorXf::Random(s1
) * y
;
333 VectorXd vd
= VectorXd::Random(s1
) * y
;
334 VectorXcf vcf
= VectorXcf::Random(s1
) * y
;
335 BENCH_PERF(sqsumNorm
);
336 BENCH_PERF(stableNorm
);
337 BENCH_PERF(blueNorm
);
338 BENCH_PERF(pblueNorm
);
339 BENCH_PERF(lapackNorm
);
340 BENCH_PERF(hypotNorm
);
341 BENCH_PERF(twopassNorm
);
342 BENCH_PERF(bl2passNorm
);
345 std::cerr
<< "\nPerformance (in cache, " << 512 << "):\n";
348 VectorXf vf
= VectorXf::Random(512) * y
;
349 VectorXd vd
= VectorXd::Random(512) * y
;
350 VectorXcf vcf
= VectorXcf::Random(512) * y
;
351 BENCH_PERF(sqsumNorm
);
352 BENCH_PERF(stableNorm
);
353 BENCH_PERF(blueNorm
);
354 BENCH_PERF(pblueNorm
);
355 BENCH_PERF(lapackNorm
);
356 BENCH_PERF(hypotNorm
);
357 BENCH_PERF(twopassNorm
);
358 BENCH_PERF(bl2passNorm
);