complex_test.cpp 33 KB

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