]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/math/test/complex_test.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / math / test / complex_test.cpp
1 // (C) Copyright John Maddock 2005.
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #define BOOST_TEST_MAIN
7 #include <boost/test/unit_test.hpp>
8 #include <boost/test/tools/floating_point_comparison.hpp>
9 #include <boost/type_traits/is_same.hpp>
10 #include <boost/type_traits/is_floating_point.hpp>
11 #include <boost/mpl/if.hpp>
12 #include <boost/static_assert.hpp>
13 #include <boost/math/complex.hpp>
14
15 #include <iostream>
16 #include <iomanip>
17 #include <cmath>
18 #include <typeinfo>
19
20 #ifdef BOOST_NO_STDC_NAMESPACE
21 namespace std{ using ::sqrt; using ::tan; using ::tanh; }
22 #endif
23
24 #ifndef VERBOSE
25 #undef BOOST_TEST_MESSAGE
26 #define BOOST_TEST_MESSAGE(x)
27 #endif
28
29 //
30 // check_complex:
31 // Verifies that expected value "a" and found value "b" have a relative error
32 // less than "max_error" epsilons. Note that relative error is calculated for
33 // the complex number as a whole; this means that the error in the real or
34 // imaginary parts alone can be much higher than max_error when the real and
35 // imaginary parts are of very different magnitudes. This is important, because
36 // the Hull et al analysis of the acos and asin algorithms requires that very small
37 // real/imaginary components can be safely ignored if they are negligible compared
38 // to the other component.
39 //
40 template <class T>
41 bool check_complex(const std::complex<T>& a, const std::complex<T>& b, int max_error)
42 {
43 //
44 // a is the expected value, b is what was actually found,
45 // compute | (a-b)/b | and compare with max_error which is the
46 // multiple of E to permit:
47 //
48 bool result = true;
49 static const std::complex<T> zero(0);
50 static const T eps = std::pow(static_cast<T>(std::numeric_limits<T>::radix), static_cast<T>(1 - std::numeric_limits<T>::digits));
51 if(a == zero)
52 {
53 if(b != zero)
54 {
55 if(boost::math::fabs(b) > eps)
56 {
57 result = false;
58 BOOST_ERROR("Expected {0,0} but got: " << b);
59 }
60 else
61 {
62 BOOST_TEST_MESSAGE("Expected {0,0} but got: " << b);
63 }
64 }
65 return result;
66 }
67 else if(b == zero)
68 {
69 if(boost::math::fabs(a) > eps)
70 {
71 BOOST_ERROR("Found {0,0} but expected: " << a);
72 return false;;
73 }
74 else
75 {
76 BOOST_TEST_MESSAGE("Found {0,0} but expected: " << a);
77 }
78 }
79
80 if((boost::math::isnan)(a.real()))
81 {
82 BOOST_ERROR("Found non-finite value for real part: " << a);
83 }
84 if((boost::math::isnan)(a.imag()))
85 {
86 BOOST_ERROR("Found non-finite value for inaginary part: " << a);
87 }
88
89 T rel = boost::math::fabs((b-a)/b) / eps;
90 if( rel > max_error)
91 {
92 result = false;
93 BOOST_ERROR("Error in result exceeded permitted limit of " << max_error << " (actual relative error was " << rel << "e). Found " << b << " expected " << a);
94 }
95 return result;
96 }
97
98 //
99 // test_inverse_trig:
100 // This is nothing more than a sanity check, computes trig(atrig(z))
101 // and compare the result to z. Note that:
102 //
103 // atrig(trig(z)) != z
104 //
105 // for certain z because the inverse trig functions are multi-valued, this
106 // essentially rules this out as a testing method. On the other hand:
107 //
108 // trig(atrig(z))
109 //
110 // can vary compare to z by an arbitrarily large amount. For one thing we
111 // have no control over the implementation of the trig functions, for another
112 // even if both functions were accurate to 1ulp (as accurate as transcendental
113 // number can get, thanks to the "table makers dilemma"), the errors can still
114 // be arbitrarily large - often the inverse trig functions will map a very large
115 // part of the complex domain into a small output domain, so you can never get
116 // back exactly where you started from. Consequently these tests are no more than
117 // sanity checks (just verifies that signs are correct and so on).
118 //
119 template <class T>
120 void test_inverse_trig(T)
121 {
122 using namespace std;
123
124 static const T interval = static_cast<T>(2.0L/128.0L);
125
126 T x, y;
127
128 std::cout << std::setprecision(std::numeric_limits<T>::digits10+2);
129
130 for(x = -1; x <= 1; x += interval)
131 {
132 for(y = -1; y <= 1; y += interval)
133 {
134 // acos:
135 std::complex<T> val(x, y), inter, result;
136 inter = boost::math::acos(val);
137 result = cos(inter);
138 if(!check_complex(val, result, 50))
139 {
140 std::cout << "Error in testing inverse complex cos for type " << typeid(T).name() << std::endl;
141 std::cout << " val= " << val << std::endl;
142 std::cout << " acos(val) = " << inter << std::endl;
143 std::cout << " cos(acos(val)) = " << result << std::endl;
144 }
145 // asin:
146 inter = boost::math::asin(val);
147 result = sin(inter);
148 if(!check_complex(val, result, 5))
149 {
150 std::cout << "Error in testing inverse complex sin for type " << typeid(T).name() << std::endl;
151 std::cout << " val= " << val << std::endl;
152 std::cout << " asin(val) = " << inter << std::endl;
153 std::cout << " sin(asin(val)) = " << result << std::endl;
154 }
155 }
156 }
157
158 static const T interval2 = static_cast<T>(3.0L/256.0L);
159 for(x = -3; x <= 3; x += interval2)
160 {
161 for(y = -3; y <= 3; y += interval2)
162 {
163 // asinh:
164 std::complex<T> val(x, y), inter, result;
165 inter = boost::math::asinh(val);
166 result = sinh(inter);
167 if(!check_complex(val, result, 5))
168 {
169 std::cout << "Error in testing inverse complex sinh for type " << typeid(T).name() << std::endl;
170 std::cout << " val= " << val << std::endl;
171 std::cout << " asinh(val) = " << inter << std::endl;
172 std::cout << " sinh(asinh(val)) = " << result << std::endl;
173 }
174 // acosh:
175 if(!((y == 0) && (x <= 1))) // can't test along the branch cut
176 {
177 inter = boost::math::acosh(val);
178 result = cosh(inter);
179 if(!check_complex(val, result, 60))
180 {
181 std::cout << "Error in testing inverse complex cosh for type " << typeid(T).name() << std::endl;
182 std::cout << " val= " << val << std::endl;
183 std::cout << " acosh(val) = " << inter << std::endl;
184 std::cout << " cosh(acosh(val)) = " << result << std::endl;
185 }
186 }
187 //
188 // There is a problem in testing atan and atanh:
189 // The inverse functions map a large input range to a much
190 // smaller output range, so at the extremes too rather different
191 // inputs may map to the same output value once rounded to N places.
192 // Consequently tan(atan(z)) can suffer from arbitrarily large errors
193 // even if individually they each have a small error bound. On the other
194 // hand we can't test atan(tan(z)) either because atan is multi-valued, so
195 // round-tripping in this direction isn't always possible.
196 // The following heuristic is designed to make the best of a bad job,
197 // using atan(tan(z)) where possible and tan(atan(z)) when it's not.
198 //
199 static const int tanh_error = 20;
200 if((0 != x) && (0 != y) && ((std::fabs(y) < 1) || (std::fabs(x) < 1)))
201 {
202 // atanh:
203 val = boost::math::atanh(val);
204 inter = tanh(val);
205 result = boost::math::atanh(inter);
206 if(!check_complex(val, result, tanh_error))
207 {
208 std::cout << "Error in testing inverse complex tanh for type " << typeid(T).name() << std::endl;
209 std::cout << " val= " << val << std::endl;
210 std::cout << " tanh(val) = " << inter << std::endl;
211 std::cout << " atanh(tanh(val)) = " << result << std::endl;
212 }
213 // atan:
214 if(!((x == 0) && (std::fabs(y) == 1))) // we can't test infinities here
215 {
216 val = std::complex<T>(x, y);
217 val = boost::math::atan(val);
218 inter = tan(val);
219 result = boost::math::atan(inter);
220 if(!check_complex(val, result, tanh_error))
221 {
222 std::cout << "Error in testing inverse complex tan for type " << typeid(T).name() << std::endl;
223 std::cout << " val= " << val << std::endl;
224 std::cout << " tan(val) = " << inter << std::endl;
225 std::cout << " atan(tan(val)) = " << result << std::endl;
226 }
227 }
228 }
229 else
230 {
231 // atanh:
232 inter = boost::math::atanh(val);
233 result = tanh(inter);
234 if(!check_complex(val, result, tanh_error))
235 {
236 std::cout << "Error in testing inverse complex atanh for type " << typeid(T).name() << std::endl;
237 std::cout << " val= " << val << std::endl;
238 std::cout << " atanh(val) = " << inter << std::endl;
239 std::cout << " tanh(atanh(val)) = " << result << std::endl;
240 }
241 // atan:
242 if(!((x == 0) && (std::fabs(y) == 1))) // we can't test infinities here
243 {
244 inter = boost::math::atan(val);
245 result = tan(inter);
246 if(!check_complex(val, result, tanh_error))
247 {
248 std::cout << "Error in testing inverse complex atan for type " << typeid(T).name() << std::endl;
249 std::cout << " val= " << val << std::endl;
250 std::cout << " atan(val) = " << inter << std::endl;
251 std::cout << " tan(atan(val)) = " << result << std::endl;
252 }
253 }
254 }
255 }
256 }
257 }
258
259 //
260 // check_spots:
261 // Various spot values, mostly the C99 special cases (infinites and NAN's).
262 // TODO: add spot checks for the Wolfram spot values.
263 //
264 template <class T>
265 void check_spots(const T&)
266 {
267 typedef std::complex<T> ct;
268 ct result;
269 static const T two = 2.0;
270 T eps = std::pow(two, T(1-std::numeric_limits<T>::digits)); // numeric_limits<>::epsilon way too small to be useful on Darwin.
271 static const T zero = 0;
272 static const T mzero = -zero;
273 static const T one = 1;
274 static const T pi = boost::math::constants::pi<T>();
275 static const T half_pi = boost::math::constants::half_pi<T>();
276 static const T quarter_pi = half_pi / 2;
277 static const T three_quarter_pi = boost::math::constants::three_quarters_pi<T>();
278 T infinity = std::numeric_limits<T>::infinity();
279 bool test_infinity = std::numeric_limits<T>::has_infinity;
280 T nan = 0;
281 bool test_nan = false;
282 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
283 // numeric_limits reports that a quiet NaN is present
284 // but an attempt to access it will terminate the program!!!!
285 if(std::numeric_limits<T>::has_quiet_NaN)
286 nan = std::numeric_limits<T>::quiet_NaN();
287 if((boost::math::isnan)(nan))
288 test_nan = true;
289 #endif
290 #if defined(__DECCXX) && !defined(_IEEE_FP)
291 // Tru64 cxx traps infinities unless the -ieee option is used:
292 test_infinity = false;
293 #endif
294
295 //
296 // C99 spot tests for acos:
297 //
298 result = boost::math::acos(ct(zero));
299 check_complex(ct(half_pi), result, 2);
300
301 result = boost::math::acos(ct(mzero));
302 check_complex(ct(half_pi), result, 2);
303
304 result = boost::math::acos(ct(zero, mzero));
305 check_complex(ct(half_pi), result, 2);
306
307 result = boost::math::acos(ct(mzero, mzero));
308 check_complex(ct(half_pi), result, 2);
309
310 if(test_nan)
311 {
312 result = boost::math::acos(ct(zero,nan));
313 BOOST_CHECK_CLOSE(result.real(), half_pi, eps*200);
314 BOOST_CHECK((boost::math::isnan)(result.imag()));
315
316 result = boost::math::acos(ct(mzero,nan));
317 BOOST_CHECK_CLOSE(result.real(), half_pi, eps*200);
318 BOOST_CHECK((boost::math::isnan)(result.imag()));
319 }
320 if(test_infinity)
321 {
322 result = boost::math::acos(ct(zero, infinity));
323 BOOST_CHECK_CLOSE(result.real(), half_pi, eps*200);
324 BOOST_CHECK(result.imag() == -infinity);
325
326 result = boost::math::acos(ct(zero, -infinity));
327 BOOST_CHECK_CLOSE(result.real(), half_pi, eps*200);
328 BOOST_CHECK(result.imag() == infinity);
329 }
330
331 if(test_nan)
332 {
333 result = boost::math::acos(ct(one, nan));
334 BOOST_CHECK((boost::math::isnan)(result.real()));
335 BOOST_CHECK((boost::math::isnan)(result.imag()));
336 }
337 if(test_infinity)
338 {
339 result = boost::math::acos(ct(-infinity, one));
340 BOOST_CHECK_CLOSE(result.real(), pi, eps*200);
341 BOOST_CHECK(result.imag() == -infinity);
342
343 result = boost::math::acos(ct(infinity, one));
344 BOOST_CHECK(result.real() == 0);
345 BOOST_CHECK(result.imag() == -infinity);
346
347 result = boost::math::acos(ct(-infinity, -one));
348 BOOST_CHECK_CLOSE(result.real(), pi, eps*200);
349 BOOST_CHECK(result.imag() == infinity);
350
351 result = boost::math::acos(ct(infinity, -one));
352 BOOST_CHECK(result.real() == 0);
353 BOOST_CHECK(result.imag() == infinity);
354
355 result = boost::math::acos(ct(-infinity, infinity));
356 BOOST_CHECK_CLOSE(result.real(), three_quarter_pi, eps*200);
357 BOOST_CHECK(result.imag() == -infinity);
358
359 result = boost::math::acos(ct(infinity, infinity));
360 BOOST_CHECK_CLOSE(result.real(), quarter_pi, eps*200);
361 BOOST_CHECK(result.imag() == -infinity);
362
363 result = boost::math::acos(ct(-infinity, -infinity));
364 BOOST_CHECK_CLOSE(result.real(), three_quarter_pi, eps*200);
365 BOOST_CHECK(result.imag() == infinity);
366
367 result = boost::math::acos(ct(infinity, -infinity));
368 BOOST_CHECK_CLOSE(result.real(), quarter_pi, eps*200);
369 BOOST_CHECK(result.imag() == infinity);
370 }
371 if(test_nan)
372 {
373 result = boost::math::acos(ct(infinity, nan));
374 BOOST_CHECK((boost::math::isnan)(result.real()));
375 BOOST_CHECK(std::fabs(result.imag()) == infinity);
376
377 result = boost::math::acos(ct(-infinity, nan));
378 BOOST_CHECK((boost::math::isnan)(result.real()));
379 BOOST_CHECK(std::fabs(result.imag()) == infinity);
380
381 result = boost::math::acos(ct(nan, zero));
382 BOOST_CHECK((boost::math::isnan)(result.real()));
383 BOOST_CHECK((boost::math::isnan)(result.imag()));
384
385 result = boost::math::acos(ct(nan, -zero));
386 BOOST_CHECK((boost::math::isnan)(result.real()));
387 BOOST_CHECK((boost::math::isnan)(result.imag()));
388
389 result = boost::math::acos(ct(nan, one));
390 BOOST_CHECK((boost::math::isnan)(result.real()));
391 BOOST_CHECK((boost::math::isnan)(result.imag()));
392
393 result = boost::math::acos(ct(nan, -one));
394 BOOST_CHECK((boost::math::isnan)(result.real()));
395 BOOST_CHECK((boost::math::isnan)(result.imag()));
396
397 result = boost::math::acos(ct(nan, nan));
398 BOOST_CHECK((boost::math::isnan)(result.real()));
399 BOOST_CHECK((boost::math::isnan)(result.imag()));
400
401 result = boost::math::acos(ct(nan, infinity));
402 BOOST_CHECK((boost::math::isnan)(result.real()));
403 BOOST_CHECK(result.imag() == -infinity);
404
405 result = boost::math::acos(ct(nan, -infinity));
406 BOOST_CHECK((boost::math::isnan)(result.real()));
407 BOOST_CHECK(result.imag() == infinity);
408 }
409 if(boost::math::signbit(mzero))
410 {
411 result = boost::math::acos(ct(-1.25f, zero));
412 BOOST_CHECK(result.real() > 0);
413 BOOST_CHECK(result.imag() < 0);
414 result = boost::math::asin(ct(-1.75f, mzero));
415 BOOST_CHECK(result.real() < 0);
416 BOOST_CHECK(result.imag() < 0);
417 result = boost::math::atan(ct(mzero, -1.75f));
418 BOOST_CHECK(result.real() < 0);
419 BOOST_CHECK(result.imag() < 0);
420
421 result = boost::math::acos(ct(zero, zero));
422 BOOST_CHECK(result.real() > 0);
423 BOOST_CHECK(result.imag() == 0);
424 BOOST_CHECK((boost::math::signbit)(result.imag()));
425 result = boost::math::acos(ct(zero, mzero));
426 BOOST_CHECK(result.real() > 0);
427 BOOST_CHECK(result.imag() == 0);
428 BOOST_CHECK(0 == (boost::math::signbit)(result.imag()));
429 result = boost::math::acos(ct(mzero, zero));
430 BOOST_CHECK(result.real() > 0);
431 BOOST_CHECK(result.imag() == 0);
432 BOOST_CHECK((boost::math::signbit)(result.imag()));
433 result = boost::math::acos(ct(mzero, mzero));
434 BOOST_CHECK(result.real() > 0);
435 BOOST_CHECK(result.imag() == 0);
436 BOOST_CHECK(0 == (boost::math::signbit)(result.imag()));
437 }
438
439 //
440 // C99 spot tests for acosh:
441 //
442 result = boost::math::acosh(ct(zero, zero));
443 BOOST_CHECK(result.real() == 0);
444 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
445
446 result = boost::math::acosh(ct(zero, mzero));
447 BOOST_CHECK(result.real() == 0);
448 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
449
450 result = boost::math::acosh(ct(mzero, zero));
451 BOOST_CHECK(result.real() == 0);
452 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
453
454 result = boost::math::acosh(ct(mzero, mzero));
455 BOOST_CHECK(result.real() == 0);
456 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
457
458 if(test_infinity)
459 {
460 result = boost::math::acosh(ct(one, infinity));
461 BOOST_CHECK(result.real() == infinity);
462 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
463
464 result = boost::math::acosh(ct(one, -infinity));
465 BOOST_CHECK(result.real() == infinity);
466 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
467 }
468
469 if(test_nan)
470 {
471 result = boost::math::acosh(ct(one, nan));
472 BOOST_CHECK((boost::math::isnan)(result.real()));
473 BOOST_CHECK((boost::math::isnan)(result.imag()));
474 }
475 if(test_infinity)
476 {
477 result = boost::math::acosh(ct(-infinity, one));
478 BOOST_CHECK(result.real() == infinity);
479 BOOST_CHECK_CLOSE(result.imag(), pi, eps*200);
480
481 result = boost::math::acosh(ct(infinity, one));
482 BOOST_CHECK(result.real() == infinity);
483 BOOST_CHECK(result.imag() == 0);
484
485 result = boost::math::acosh(ct(-infinity, -one));
486 BOOST_CHECK(result.real() == infinity);
487 BOOST_CHECK_CLOSE(result.imag(), -pi, eps*200);
488
489 result = boost::math::acosh(ct(infinity, -one));
490 BOOST_CHECK(result.real() == infinity);
491 BOOST_CHECK(result.imag() == 0);
492
493 result = boost::math::acosh(ct(-infinity, infinity));
494 BOOST_CHECK(result.real() == infinity);
495 BOOST_CHECK_CLOSE(result.imag(), three_quarter_pi, eps*200);
496
497 result = boost::math::acosh(ct(infinity, infinity));
498 BOOST_CHECK(result.real() == infinity);
499 BOOST_CHECK_CLOSE(result.imag(), quarter_pi, eps*200);
500
501 result = boost::math::acosh(ct(-infinity, -infinity));
502 BOOST_CHECK(result.real() == infinity);
503 BOOST_CHECK_CLOSE(result.imag(), -three_quarter_pi, eps*200);
504
505 result = boost::math::acosh(ct(infinity, -infinity));
506 BOOST_CHECK(result.real() == infinity);
507 BOOST_CHECK_CLOSE(result.imag(), -quarter_pi, eps*200);
508 }
509
510 if(test_nan)
511 {
512 result = boost::math::acosh(ct(infinity, nan));
513 BOOST_CHECK(result.real() == infinity);
514 BOOST_CHECK((boost::math::isnan)(result.imag()));
515
516 result = boost::math::acosh(ct(-infinity, nan));
517 BOOST_CHECK(result.real() == infinity);
518 BOOST_CHECK((boost::math::isnan)(result.imag()));
519
520 result = boost::math::acosh(ct(nan, one));
521 BOOST_CHECK((boost::math::isnan)(result.real()));
522 BOOST_CHECK((boost::math::isnan)(result.imag()));
523
524 result = boost::math::acosh(ct(nan, infinity));
525 BOOST_CHECK(result.real() == infinity);
526 BOOST_CHECK((boost::math::isnan)(result.imag()));
527
528 result = boost::math::acosh(ct(nan, -one));
529 BOOST_CHECK((boost::math::isnan)(result.real()));
530 BOOST_CHECK((boost::math::isnan)(result.imag()));
531
532 result = boost::math::acosh(ct(nan, -infinity));
533 BOOST_CHECK(result.real() == infinity);
534 BOOST_CHECK((boost::math::isnan)(result.imag()));
535
536 result = boost::math::acosh(ct(nan, nan));
537 BOOST_CHECK((boost::math::isnan)(result.real()));
538 BOOST_CHECK((boost::math::isnan)(result.imag()));
539 }
540 if(boost::math::signbit(mzero))
541 {
542 result = boost::math::acosh(ct(-2.5f, zero));
543 BOOST_CHECK(result.real() > 0);
544 BOOST_CHECK(result.imag() > 0);
545 }
546 //
547 // C99 spot checks for asinh:
548 //
549 result = boost::math::asinh(ct(zero, zero));
550 BOOST_CHECK(result.real() == 0);
551 BOOST_CHECK(result.imag() == 0);
552
553 result = boost::math::asinh(ct(mzero, zero));
554 BOOST_CHECK(result.real() == 0);
555 BOOST_CHECK(result.imag() == 0);
556
557 result = boost::math::asinh(ct(zero, mzero));
558 BOOST_CHECK(result.real() == 0);
559 BOOST_CHECK(result.imag() == 0);
560
561 result = boost::math::asinh(ct(mzero, mzero));
562 BOOST_CHECK(result.real() == 0);
563 BOOST_CHECK(result.imag() == 0);
564
565 if(test_infinity)
566 {
567 result = boost::math::asinh(ct(one, infinity));
568 BOOST_CHECK(result.real() == infinity);
569 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
570
571 result = boost::math::asinh(ct(one, -infinity));
572 BOOST_CHECK(result.real() == infinity);
573 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
574
575 result = boost::math::asinh(ct(-one, -infinity));
576 BOOST_CHECK(result.real() == -infinity);
577 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
578
579 result = boost::math::asinh(ct(-one, infinity));
580 BOOST_CHECK(result.real() == -infinity);
581 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
582 }
583
584 if(test_nan)
585 {
586 result = boost::math::asinh(ct(one, nan));
587 BOOST_CHECK((boost::math::isnan)(result.real()));
588 BOOST_CHECK((boost::math::isnan)(result.imag()));
589
590 result = boost::math::asinh(ct(-one, nan));
591 BOOST_CHECK((boost::math::isnan)(result.real()));
592 BOOST_CHECK((boost::math::isnan)(result.imag()));
593
594 result = boost::math::asinh(ct(zero, nan));
595 BOOST_CHECK((boost::math::isnan)(result.real()));
596 BOOST_CHECK((boost::math::isnan)(result.imag()));
597 }
598
599 if(test_infinity)
600 {
601 result = boost::math::asinh(ct(infinity, one));
602 BOOST_CHECK(result.real() == infinity);
603 BOOST_CHECK(result.imag() == 0);
604
605 result = boost::math::asinh(ct(infinity, -one));
606 BOOST_CHECK(result.real() == infinity);
607 BOOST_CHECK(result.imag() == 0);
608
609 result = boost::math::asinh(ct(-infinity, -one));
610 BOOST_CHECK(result.real() == -infinity);
611 BOOST_CHECK(result.imag() == 0);
612
613 result = boost::math::asinh(ct(-infinity, one));
614 BOOST_CHECK(result.real() == -infinity);
615 BOOST_CHECK(result.imag() == 0);
616
617 result = boost::math::asinh(ct(infinity, infinity));
618 BOOST_CHECK(result.real() == infinity);
619 BOOST_CHECK_CLOSE(result.imag(), quarter_pi, eps*200);
620
621 result = boost::math::asinh(ct(infinity, -infinity));
622 BOOST_CHECK(result.real() == infinity);
623 BOOST_CHECK_CLOSE(result.imag(), -quarter_pi, eps*200);
624
625 result = boost::math::asinh(ct(-infinity, -infinity));
626 BOOST_CHECK(result.real() == -infinity);
627 BOOST_CHECK_CLOSE(result.imag(), -quarter_pi, eps*200);
628
629 result = boost::math::asinh(ct(-infinity, infinity));
630 BOOST_CHECK(result.real() == -infinity);
631 BOOST_CHECK_CLOSE(result.imag(), quarter_pi, eps*200);
632 }
633
634 if(test_nan)
635 {
636 result = boost::math::asinh(ct(infinity, nan));
637 BOOST_CHECK(result.real() == infinity);
638 BOOST_CHECK((boost::math::isnan)(result.imag()));
639
640 result = boost::math::asinh(ct(-infinity, nan));
641 BOOST_CHECK(result.real() == -infinity);
642 BOOST_CHECK((boost::math::isnan)(result.imag()));
643
644 result = boost::math::asinh(ct(nan, zero));
645 BOOST_CHECK((boost::math::isnan)(result.real()));
646 BOOST_CHECK(result.imag() == 0);
647
648 result = boost::math::asinh(ct(nan, mzero));
649 BOOST_CHECK((boost::math::isnan)(result.real()));
650 BOOST_CHECK(result.imag() == 0);
651
652 result = boost::math::asinh(ct(nan, one));
653 BOOST_CHECK((boost::math::isnan)(result.real()));
654 BOOST_CHECK((boost::math::isnan)(result.imag()));
655
656 result = boost::math::asinh(ct(nan, -one));
657 BOOST_CHECK((boost::math::isnan)(result.real()));
658 BOOST_CHECK((boost::math::isnan)(result.imag()));
659
660 result = boost::math::asinh(ct(nan, nan));
661 BOOST_CHECK((boost::math::isnan)(result.real()));
662 BOOST_CHECK((boost::math::isnan)(result.imag()));
663
664 result = boost::math::asinh(ct(nan, infinity));
665 BOOST_CHECK(std::fabs(result.real()) == infinity);
666 BOOST_CHECK((boost::math::isnan)(result.imag()));
667
668 result = boost::math::asinh(ct(nan, -infinity));
669 BOOST_CHECK(std::fabs(result.real()) == infinity);
670 BOOST_CHECK((boost::math::isnan)(result.imag()));
671 }
672 if(boost::math::signbit(mzero))
673 {
674 result = boost::math::asinh(ct(zero, 1.5f));
675 BOOST_CHECK(result.real() > 0);
676 BOOST_CHECK(result.imag() > 0);
677 }
678
679 //
680 // C99 special cases for atanh:
681 //
682 result = boost::math::atanh(ct(zero, zero));
683 BOOST_CHECK(result.real() == zero);
684 BOOST_CHECK(result.imag() == zero);
685
686 result = boost::math::atanh(ct(mzero, zero));
687 BOOST_CHECK(result.real() == zero);
688 BOOST_CHECK(result.imag() == zero);
689
690 result = boost::math::atanh(ct(zero, mzero));
691 BOOST_CHECK(result.real() == zero);
692 BOOST_CHECK(result.imag() == zero);
693
694 result = boost::math::atanh(ct(mzero, mzero));
695 BOOST_CHECK(result.real() == zero);
696 BOOST_CHECK(result.imag() == zero);
697
698 if(test_nan)
699 {
700 result = boost::math::atanh(ct(zero, nan));
701 BOOST_CHECK(result.real() == zero);
702 BOOST_CHECK((boost::math::isnan)(result.imag()));
703
704 result = boost::math::atanh(ct(-zero, nan));
705 BOOST_CHECK(result.real() == zero);
706 BOOST_CHECK((boost::math::isnan)(result.imag()));
707 }
708
709 if(test_infinity)
710 {
711 result = boost::math::atanh(ct(one, zero));
712 BOOST_CHECK_EQUAL(result.real(), infinity);
713 BOOST_CHECK_EQUAL(result.imag(), zero);
714
715 result = boost::math::atanh(ct(-one, zero));
716 BOOST_CHECK_EQUAL(result.real(), -infinity);
717 BOOST_CHECK_EQUAL(result.imag(), zero);
718
719 result = boost::math::atanh(ct(-one, -zero));
720 BOOST_CHECK_EQUAL(result.real(), -infinity);
721 BOOST_CHECK_EQUAL(result.imag(), zero);
722
723 result = boost::math::atanh(ct(one, -zero));
724 BOOST_CHECK_EQUAL(result.real(), infinity);
725 BOOST_CHECK_EQUAL(result.imag(), zero);
726
727 result = boost::math::atanh(ct(pi, infinity));
728 BOOST_CHECK_EQUAL(result.real(), zero);
729 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
730
731 result = boost::math::atanh(ct(pi, -infinity));
732 BOOST_CHECK_EQUAL(result.real(), zero);
733 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
734
735 result = boost::math::atanh(ct(-pi, -infinity));
736 BOOST_CHECK_EQUAL(result.real(), zero);
737 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
738
739 result = boost::math::atanh(ct(-pi, infinity));
740 BOOST_CHECK_EQUAL(result.real(), zero);
741 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
742 }
743 if(test_nan)
744 {
745 result = boost::math::atanh(ct(pi, nan));
746 BOOST_CHECK((boost::math::isnan)(result.real()));
747 BOOST_CHECK((boost::math::isnan)(result.imag()));
748
749 result = boost::math::atanh(ct(-pi, nan));
750 BOOST_CHECK((boost::math::isnan)(result.real()));
751 BOOST_CHECK((boost::math::isnan)(result.imag()));
752 }
753
754 if(test_infinity)
755 {
756 result = boost::math::atanh(ct(infinity, pi));
757 BOOST_CHECK(result.real() == zero);
758 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
759
760 result = boost::math::atanh(ct(infinity, -pi));
761 BOOST_CHECK_EQUAL(result.real(), zero);
762 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
763
764 result = boost::math::atanh(ct(-infinity, -pi));
765 BOOST_CHECK_EQUAL(result.real(), zero);
766 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
767
768 result = boost::math::atanh(ct(-infinity, pi));
769 BOOST_CHECK_EQUAL(result.real(), zero);
770 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
771
772 result = boost::math::atanh(ct(infinity, infinity));
773 BOOST_CHECK_EQUAL(result.real(), zero);
774 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
775
776 result = boost::math::atanh(ct(infinity, -infinity));
777 BOOST_CHECK_EQUAL(result.real(), zero);
778 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
779
780 result = boost::math::atanh(ct(-infinity, -infinity));
781 BOOST_CHECK_EQUAL(result.real(), zero);
782 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
783
784 result = boost::math::atanh(ct(-infinity, infinity));
785 BOOST_CHECK_EQUAL(result.real(), zero);
786 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
787 }
788
789 if(test_nan)
790 {
791 result = boost::math::atanh(ct(infinity, nan));
792 BOOST_CHECK(result.real() == 0);
793 BOOST_CHECK((boost::math::isnan)(result.imag()));
794
795 result = boost::math::atanh(ct(-infinity, nan));
796 BOOST_CHECK(result.real() == 0);
797 BOOST_CHECK((boost::math::isnan)(result.imag()));
798
799 result = boost::math::atanh(ct(nan, pi));
800 BOOST_CHECK((boost::math::isnan)(result.real()));
801 BOOST_CHECK((boost::math::isnan)(result.imag()));
802
803 result = boost::math::atanh(ct(nan, -pi));
804 BOOST_CHECK((boost::math::isnan)(result.real()));
805 BOOST_CHECK((boost::math::isnan)(result.imag()));
806
807 result = boost::math::atanh(ct(nan, infinity));
808 BOOST_CHECK(result.real() == 0);
809 BOOST_CHECK_CLOSE(result.imag(), half_pi, eps*200);
810
811 result = boost::math::atanh(ct(nan, -infinity));
812 BOOST_CHECK(result.real() == 0);
813 BOOST_CHECK_CLOSE(result.imag(), -half_pi, eps*200);
814
815 result = boost::math::atanh(ct(nan, nan));
816 BOOST_CHECK((boost::math::isnan)(result.real()));
817 BOOST_CHECK((boost::math::isnan)(result.imag()));
818
819 }
820 if(boost::math::signbit(mzero))
821 {
822 result = boost::math::atanh(ct(-2.0f, mzero));
823 BOOST_CHECK(result.real() < 0);
824 BOOST_CHECK(result.imag() < 0);
825 }
826 }
827
828 //
829 // test_boundaries:
830 // This is an accuracy test, sets the real and imaginary components
831 // of the input argument to various "boundary conditions" that exist
832 // inside the implementation. Then computes the result at double precision
833 // and again at float precision. The double precision result will be
834 // computed using the "regular" code, where as the float precision versions
835 // will calculate the result using the "exceptional value" handlers, so
836 // we end up comparing the values calculated by two different methods.
837 //
838 const float boundaries[] = {
839 0,
840 1,
841 2,
842 (std::numeric_limits<float>::max)(),
843 (std::numeric_limits<float>::min)(),
844 std::numeric_limits<float>::epsilon(),
845 std::sqrt((std::numeric_limits<float>::max)()) / 8,
846 static_cast<float>(4) * std::sqrt((std::numeric_limits<float>::min)()),
847 0.6417F,
848 1.5F,
849 std::sqrt((std::numeric_limits<float>::max)()) / 2,
850 std::sqrt((std::numeric_limits<float>::min)()),
851 1.0F / 0.3F,
852 };
853
854 void do_test_boundaries(float x, float y)
855 {
856 std::complex<float> r1 = boost::math::asin(std::complex<float>(x, y));
857 std::complex<double> dr = boost::math::asin(std::complex<double>(x, y));
858 std::complex<float> r2(static_cast<float>(dr.real()), static_cast<float>(dr.imag()));
859 check_complex(r2, r1, 5);
860 r1 = boost::math::acos(std::complex<float>(x, y));
861 dr = boost::math::acos(std::complex<double>(x, y));
862 r2 = std::complex<float>(std::complex<double>(dr.real(), dr.imag()));
863 check_complex(r2, r1, 5);
864 r1 = boost::math::atanh(std::complex<float>(x, y));
865 dr = boost::math::atanh(std::complex<double>(x, y));
866 r2 = std::complex<float>(std::complex<double>(dr.real(), dr.imag()));
867 check_complex(r2, r1, 5);
868 }
869
870 void test_boundaries(float x, float y)
871 {
872 do_test_boundaries(x, y);
873 do_test_boundaries(-x, y);
874 do_test_boundaries(-x, -y);
875 do_test_boundaries(x, -y);
876 }
877
878 void test_boundaries(float x)
879 {
880 for(unsigned i = 0; i < sizeof(boundaries)/sizeof(float); ++i)
881 {
882 test_boundaries(x, boundaries[i]);
883 test_boundaries(x, boundaries[i] + std::numeric_limits<float>::epsilon()*boundaries[i]);
884 test_boundaries(x, boundaries[i] - std::numeric_limits<float>::epsilon()*boundaries[i]);
885 }
886 }
887
888 void test_boundaries()
889 {
890 for(unsigned i = 0; i < sizeof(boundaries)/sizeof(float); ++i)
891 {
892 test_boundaries(boundaries[i]);
893 test_boundaries(boundaries[i] + std::numeric_limits<float>::epsilon()*boundaries[i]);
894 test_boundaries(boundaries[i] - std::numeric_limits<float>::epsilon()*boundaries[i]);//here
895 }
896 }
897
898
899 BOOST_AUTO_TEST_CASE( test_main )
900 {
901 std::cout << "Running complex trig sanity checks for type float." << std::endl;
902 test_inverse_trig(float(0));
903 std::cout << "Running complex trig sanity checks for type double." << std::endl;
904 test_inverse_trig(double(0));
905 //test_inverse_trig((long double)(0));
906
907 std::cout << "Running complex trig spot checks for type float." << std::endl;
908 check_spots(float(0));
909 std::cout << "Running complex trig spot checks for type double." << std::endl;
910 check_spots(double(0));
911 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
912 std::cout << "Running complex trig spot checks for type long double." << std::endl;
913 check_spots((long double)(0));
914 #endif
915
916 std::cout << "Running complex trig boundary and accuracy tests." << std::endl;
917 test_boundaries();
918 }
919
920
921