Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/math/test/complex_test.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

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