quaternion_test.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. // test file for quaternion.hpp
  2. // (C) Copyright Hubert Holin 2001.
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #include <iomanip>
  7. #include <boost/mpl/list.hpp>
  8. #define BOOST_TEST_MAIN
  9. #include <boost/test/unit_test.hpp>
  10. #include <boost/test/unit_test_log.hpp>
  11. #include <boost/multiprecision/cpp_bin_float.hpp>
  12. #include <boost/multiprecision/cpp_dec_float.hpp>
  13. #include <boost/math/quaternion.hpp>
  14. #ifdef BOOST_MSVC
  15. #pragma warning(disable:4127) // conditional expression is constant
  16. #endif
  17. template<typename T>
  18. struct string_type_name;
  19. #define DEFINE_TYPE_NAME(Type) \
  20. template<> struct string_type_name<Type> \
  21. { \
  22. static char const * _() \
  23. { \
  24. return #Type; \
  25. } \
  26. }
  27. DEFINE_TYPE_NAME(float);
  28. DEFINE_TYPE_NAME(double);
  29. DEFINE_TYPE_NAME(long double);
  30. DEFINE_TYPE_NAME(boost::multiprecision::cpp_bin_float_quad);
  31. DEFINE_TYPE_NAME(boost::multiprecision::number<boost::multiprecision::cpp_dec_float<25> >);
  32. #if BOOST_WORKAROUND(BOOST_MSVC, < 1900)
  33. # define CPP_DEC_FLOAT_TEST
  34. #else
  35. # define CPP_DEC_FLOAT_TEST , boost::multiprecision::number<boost::multiprecision::cpp_dec_float<25> >
  36. #endif
  37. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  38. # define LD_TEST , long double
  39. #else
  40. # define LD_TEST
  41. #endif
  42. typedef boost::mpl::list<float,double LD_TEST, boost::multiprecision::cpp_bin_float_quad CPP_DEC_FLOAT_TEST > test_types;
  43. // Apple GCC 4.0 uses the "double double" format for its long double,
  44. // which means that epsilon is VERY small but useless for
  45. // comparisons. So, don't do those comparisons.
  46. #if (defined(__APPLE_CC__) && defined(__GNUC__) && __GNUC__ == 4) || defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)
  47. typedef boost::mpl::list<float,double> near_eps_test_types;
  48. #else
  49. typedef boost::mpl::list<float,double,long double> near_eps_test_types;
  50. #endif
  51. #if BOOST_WORKAROUND(__GNUC__, < 3)
  52. // gcc 2.x ignores function scope using declarations,
  53. // put them in the scope of the enclosing namespace instead:
  54. using ::std::sqrt;
  55. using ::std::atan;
  56. using ::std::log;
  57. using ::std::exp;
  58. using ::std::cos;
  59. using ::std::sin;
  60. using ::std::tan;
  61. using ::std::cosh;
  62. using ::std::sinh;
  63. using ::std::tanh;
  64. using ::std::numeric_limits;
  65. using ::boost::math::abs;
  66. #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
  67. #ifdef BOOST_NO_STDC_NAMESPACE
  68. using ::sqrt;
  69. using ::atan;
  70. using ::log;
  71. using ::exp;
  72. using ::cos;
  73. using ::sin;
  74. using ::tan;
  75. using ::cosh;
  76. using ::sinh;
  77. using ::tanh;
  78. #endif /* BOOST_NO_STDC_NAMESPACE */
  79. #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
  80. using ::boost::math::real;
  81. using ::boost::math::unreal;
  82. using ::boost::math::sup;
  83. using ::boost::math::l1;
  84. using ::boost::math::abs;
  85. using ::boost::math::norm;
  86. using ::boost::math::conj;
  87. using ::boost::math::exp;
  88. using ::boost::math::pow;
  89. using ::boost::math::cos;
  90. using ::boost::math::sin;
  91. using ::boost::math::tan;
  92. using ::boost::math::cosh;
  93. using ::boost::math::sinh;
  94. using ::boost::math::tanh;
  95. using ::boost::math::sinc_pi;
  96. using ::boost::math::sinhc_pi;
  97. #endif /* BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP */
  98. // Provide standard floating point abs() overloads if older Microsoft
  99. // library is used with _MSC_EXTENSIONS defined. This code also works
  100. // for the Intel compiler using the Microsoft library.
  101. #if defined(_MSC_EXTENSIONS) && BOOST_WORKAROUND(_MSC_VER, < 1310)
  102. #if !((__INTEL__ && _WIN32) && BOOST_WORKAROUND(__MWERKS__, >= 0x3201))
  103. inline float abs(float v)
  104. {
  105. return(fabs(v));
  106. }
  107. inline double abs(double v)
  108. {
  109. return(fabs(v));
  110. }
  111. inline long double abs(long double v)
  112. {
  113. return(fabs(v));
  114. }
  115. #endif /* !((__INTEL__ && _WIN32) && BOOST_WORKAROUND(__MWERKS__, >= 0x3201)) */
  116. #endif /* defined(_MSC_EXTENSIONS) && BOOST_WORKAROUND(_MSC_VER, < 1310) */
  117. // explicit (if ludicrous) instanciation
  118. #if !BOOST_WORKAROUND(__GNUC__, < 3)
  119. template class ::boost::math::quaternion<int>;
  120. #else
  121. // gcc doesn't like the absolutely-qualified namespace
  122. template class boost::math::quaternion<int>;
  123. #endif /* !BOOST_WORKAROUND(__GNUC__) */
  124. template <class T>
  125. struct other_type
  126. {
  127. typedef double type;
  128. };
  129. template<>
  130. struct other_type<double>
  131. {
  132. typedef float type;
  133. };
  134. template<>
  135. struct other_type<float>
  136. {
  137. typedef short type;
  138. };
  139. template <class T, class U>
  140. void test_compare(const T& a, const U& b, bool eq)
  141. {
  142. if (eq)
  143. {
  144. BOOST_CHECK_EQUAL(a, b);
  145. BOOST_CHECK((a != b) == false);
  146. BOOST_CHECK_EQUAL(b, a);
  147. BOOST_CHECK((b != a) == false);
  148. }
  149. else
  150. {
  151. BOOST_CHECK_NE(a, b);
  152. BOOST_CHECK((a == b) == false);
  153. BOOST_CHECK_NE(b, a);
  154. BOOST_CHECK((b == a) == false);
  155. }
  156. }
  157. template <class T, class R1, class R2, class R3, class R4>
  158. void check_exact_quaternion_result(const boost::math::quaternion<T>& q, R1 a, R2 b, R3 c, R4 d)
  159. {
  160. BOOST_CHECK_EQUAL(q.R_component_1(), a);
  161. BOOST_CHECK_EQUAL(q.R_component_2(), b);
  162. BOOST_CHECK_EQUAL(q.R_component_3(), c);
  163. BOOST_CHECK_EQUAL(q.R_component_4(), d);
  164. BOOST_CHECK_EQUAL(q.C_component_1(), std::complex<T>(T(a), T(b)));
  165. BOOST_CHECK_EQUAL(q.C_component_2(), std::complex<T>(T(c), T(d)));
  166. }
  167. template <class T, class R1, class R2, class R3, class R4>
  168. void check_approx_quaternion_result(const boost::math::quaternion<T>& q, R1 a, R2 b, R3 c, R4 d, int eps = 10)
  169. {
  170. T tol = std::numeric_limits<T>::epsilon() * eps * 100; // epsilon as a persentage.
  171. using std::abs;
  172. if (abs(a) > tol / 100)
  173. {
  174. BOOST_CHECK_CLOSE(q.R_component_1(), static_cast<T>(a), tol);
  175. }
  176. else
  177. {
  178. BOOST_CHECK_SMALL(q.R_component_1(), tol);
  179. }
  180. if (abs(b) > tol)
  181. {
  182. BOOST_CHECK_CLOSE(q.R_component_2(), static_cast<T>(b), tol);
  183. }
  184. else
  185. {
  186. BOOST_CHECK_SMALL(q.R_component_2(), tol);
  187. }
  188. if (abs(c) > tol)
  189. {
  190. BOOST_CHECK_CLOSE(q.R_component_3(), static_cast<T>(c), tol);
  191. }
  192. else
  193. {
  194. BOOST_CHECK_SMALL(q.R_component_3(), tol);
  195. }
  196. if (abs(d) > tol)
  197. {
  198. BOOST_CHECK_CLOSE(q.R_component_4(), static_cast<T>(d), tol);
  199. }
  200. else
  201. {
  202. BOOST_CHECK_SMALL(q.R_component_4(), tol);
  203. }
  204. }
  205. template <class T>
  206. void check_complex_ops_imp()
  207. {
  208. T tol = std::numeric_limits<T>::epsilon() * 200;
  209. ::std::complex<T> c0(5, 6);
  210. // using constructor "H seen as C^2"
  211. ::boost::math::quaternion<T> q2(c0), q1;
  212. check_exact_quaternion_result(q2, 5, 6, 0, 0);
  213. // using converting assignment operator
  214. q2 = 0;
  215. q2 = c0;
  216. check_exact_quaternion_result(q2, 5, 6, 0, 0);
  217. // using += (const ::std::complex<T> &)
  218. q2 = ::boost::math::quaternion<T>(5, 6, 7, 8);
  219. q2 += c0;
  220. check_exact_quaternion_result(q2, 10, 12, 7, 8);
  221. // using -= (const ::std::complex<T> &)
  222. q2 -= c0;
  223. check_exact_quaternion_result(q2, 5, 6, 7, 8);
  224. // using *= (const ::std::complex<T> &)
  225. q2 *= c0;
  226. check_exact_quaternion_result(q2, -11, 60, 83, -2);
  227. q2 /= c0;
  228. check_approx_quaternion_result(q2, 5, 6, 7, 8);
  229. q2 = ::boost::math::quaternion<T>(4, 5, 7, 8);
  230. // operator +
  231. q1 = c0 + q2;
  232. check_exact_quaternion_result(q1, 9, 11, 7, 8);
  233. q1 = q2 + c0;
  234. check_exact_quaternion_result(q1, 9, 11, 7, 8);
  235. // operator -
  236. q1 = c0 - q2;
  237. check_exact_quaternion_result(q1, 1, 1, -7, -8);
  238. q1 = q2 - c0;
  239. check_exact_quaternion_result(q1, -1, -1, 7, 8);
  240. // using * (const ::std::complex<T> &, const quaternion<T> &)
  241. q1 = c0 * q2;
  242. check_exact_quaternion_result(q1, -10, 49, -13, 82);
  243. // using * (const quaternion<T> &, const ::std::complex<T> &)
  244. q1 = q2 * c0;
  245. check_exact_quaternion_result(q1, -10, 49, 83, -2);
  246. // using / (const ::std::complex<T> &, const quaternion<T> &)
  247. q1 = c0 / q2;
  248. check_approx_quaternion_result(q1, T(25) / 77, -T(1) / 154, T(13) / 154, -T(41) / 77);
  249. q1 *= q2;
  250. BOOST_CHECK_CLOSE(q1.R_component_1(), T(5), tol);
  251. BOOST_CHECK_CLOSE(q1.R_component_2(), T(6), tol);
  252. BOOST_CHECK_SMALL(q1.R_component_3(), tol);
  253. BOOST_CHECK_SMALL(q1.R_component_4(), tol);
  254. // using / (const quaternion<T> &, const ::std::complex<T> &)
  255. q1 = q2 / c0;
  256. check_approx_quaternion_result(q1, T(50) / 61, T(1)/ 61, -T(13) / 61, T(82) / 61);
  257. q1 *= c0;
  258. check_approx_quaternion_result(q1, 4, 5, 7, 8);
  259. q1 = c0;
  260. test_compare(q1, c0, true);
  261. q1 += 1;
  262. test_compare(q1, c0, false);
  263. }
  264. template <class T>
  265. void check_complex_ops() {}
  266. template<>
  267. void check_complex_ops<float>() { check_complex_ops_imp<float>(); }
  268. template<>
  269. void check_complex_ops<double>() { check_complex_ops_imp<double>(); }
  270. template<>
  271. void check_complex_ops<long double>() { check_complex_ops_imp<long double>(); }
  272. BOOST_AUTO_TEST_CASE_TEMPLATE(arithmetic_test, T, test_types)
  273. {
  274. typedef typename other_type<T>::type other_type;
  275. check_complex_ops<T>();
  276. T tol = std::numeric_limits<T>::epsilon() * 200;
  277. // using default constructor
  278. ::boost::math::quaternion<T> q0, q2;
  279. check_exact_quaternion_result(q0, 0, 0, 0, 0);
  280. BOOST_CHECK_EQUAL(q0, 0);
  281. ::boost::math::quaternion<T> qa[2];
  282. check_exact_quaternion_result(qa[0], 0, 0, 0, 0);
  283. check_exact_quaternion_result(qa[1], 0, 0, 0, 0);
  284. BOOST_CHECK_EQUAL(qa[0], 0);
  285. BOOST_CHECK_EQUAL(qa[1], 0.f);
  286. // using constructor "H seen as R^4"
  287. ::boost::math::quaternion<T> q1(1, 2, 3, 4);
  288. check_exact_quaternion_result(q1, 1, 2, 3, 4);
  289. // using untemplated copy constructor
  290. ::boost::math::quaternion<T> q3(q1);
  291. check_exact_quaternion_result(q3, 1, 2, 3, 4);
  292. // using templated copy constructor
  293. ::boost::math::quaternion<other_type> qo(5, 6, 7, 8);
  294. boost::math::quaternion<T> q4(qo);
  295. check_exact_quaternion_result(q4, 5, 6, 7, 8);
  296. // using untemplated assignment operator
  297. q3 = q0;
  298. check_exact_quaternion_result(q0, 0, 0, 0, 0);
  299. //BOOST_CHECK_EQUAL(q3, 0.f);
  300. BOOST_CHECK_EQUAL(q3, q0);
  301. q3 = q4;
  302. check_exact_quaternion_result(q3, 5, 6, 7, 8);
  303. qa[0] = q4;
  304. check_exact_quaternion_result(qa[0], 5, 6, 7, 8);
  305. // using templated assignment operator
  306. q4 = qo;
  307. check_exact_quaternion_result(q4, 5, 6, 7, 8);
  308. other_type f0(7);
  309. T f1(7);
  310. // using converting assignment operator
  311. q2 = f0;
  312. check_exact_quaternion_result(q2, 7, 0, 0, 0);
  313. q2 = 33.;
  314. check_exact_quaternion_result(q2, 33, 0, 0, 0);
  315. // using += (const T &)
  316. q4 += f0;
  317. check_exact_quaternion_result(q4, 12, 6, 7, 8);
  318. // using += (const quaternion<X> &)
  319. q4 += q3;
  320. check_exact_quaternion_result(q4, 17, 12, 14, 16);
  321. // using -= (const T &)
  322. q4 -= f0;
  323. check_exact_quaternion_result(q4, 10, 12, 14, 16);
  324. // using -= (const quaternion<X> &)
  325. q4 -= q3;
  326. check_exact_quaternion_result(q4, 5, 6, 7, 8);
  327. // using *= (const T &)
  328. q4 *= f0;
  329. check_exact_quaternion_result(q4, 35, 42, 49, 56);
  330. // using *= (const quaternion<X> &)
  331. q4 *= q3;
  332. check_exact_quaternion_result(q4, -868, 420, 490, 560);
  333. // using /= (const T &)
  334. q4 /= f0;
  335. check_exact_quaternion_result(q4, -T(868) / 7, T(420) / 7, T(490) / 7, T(560) / 7);
  336. q4 = q3;
  337. q4 /= boost::math::quaternion<T>(9, 4, 6, 2);
  338. check_approx_quaternion_result(q4, T(127) / 137, T(68) / 137, T(13) / 137, T(54) / 137);
  339. q4 *= boost::math::quaternion<T>(9, 4, 6, 2);
  340. check_approx_quaternion_result(q4, 5, 6, 7, 8);
  341. q4 = boost::math::quaternion<T>(34, 56, 20, 2);
  342. // using + (const T &, const quaternion<T> &)
  343. q1 = f1 + q4;
  344. check_exact_quaternion_result(q1, 41, 56, 20, 2);
  345. // using + (const quaternion<T> &, const T &)
  346. q1 = q4 + f1;
  347. check_exact_quaternion_result(q1, 41, 56, 20, 2);
  348. // using + (const T &, const quaternion<T> &)
  349. q1 = f0 + q4;
  350. check_exact_quaternion_result(q1, 41, 56, 20, 2);
  351. // using + (const quaternion<T> &, const T &)
  352. q1 = q4 + f0;
  353. check_exact_quaternion_result(q1, 41, 56, 20, 2);
  354. // using + (const quaternion<T> &,const quaternion<T> &)
  355. q1 = q3 + q4;
  356. check_exact_quaternion_result(q1, 39, 62, 27, 10);
  357. // using - (const T &, const quaternion<T> &)
  358. q1 = f1 - q4;
  359. check_exact_quaternion_result(q1, 7-34, -56, -20, -2);
  360. // using - (const quaternion<T> &, const T &)
  361. q1 = q4 - f1;
  362. check_exact_quaternion_result(q1, 34-7, 56, 20, 2);
  363. // using - (const T &, const quaternion<T> &)
  364. q1 = f0 - q4;
  365. check_exact_quaternion_result(q1, 7-34, -56, -20, -2);
  366. // using - (const quaternion<T> &, const T &)
  367. q1 = q4 - f0;
  368. check_exact_quaternion_result(q1, 34-7, 56, 20, 2);
  369. // using - (const quaternion<T> &,const quaternion<T> &)
  370. q1 = q3 - q4;
  371. check_exact_quaternion_result(q1, -29, -50, -13, 6);
  372. // using * (const T &, const quaternion<T> &)
  373. q1 = f0 * q4;
  374. check_exact_quaternion_result(q1, 238, 392, 140, 14);
  375. // using * (const quaternion<T> &, const T &)
  376. q1 = q4 * f0;
  377. check_exact_quaternion_result(q1, 238, 392, 140, 14);
  378. // using * (const quaternion<T> &,const quaternion<T> &)
  379. q1 = q4 * q3;
  380. check_exact_quaternion_result(q1, -322, 630, -98, 554);
  381. q1 = q3 * q4;
  382. check_exact_quaternion_result(q1, -322, 338, 774, 10);
  383. // using / (const T &, const quaternion<T> &)
  384. q1 = T(f0) / q4;
  385. check_approx_quaternion_result(q1, T(119) / 2348, -T(49) / 587, -T(35) / 1174, -T(7) / 2348);
  386. q1 *= q4;
  387. BOOST_CHECK_CLOSE(q1.R_component_1(), T(7), tol);
  388. BOOST_CHECK_SMALL(q1.R_component_2(), tol);
  389. BOOST_CHECK_SMALL(q1.R_component_3(), tol);
  390. BOOST_CHECK_SMALL(q1.R_component_3(), tol);
  391. // using / (const quaternion<T> &, const T &)
  392. q1 = q4 / T(f0);
  393. check_approx_quaternion_result(q1, T(34) / 7, T(56) / 7, T(20) / 7, T(2) / 7);
  394. // using / (const quaternion<T> &,const quaternion<T> &)
  395. q1 = q4 / q3;
  396. check_approx_quaternion_result(q1, T(331) / 87, -T(35) / 87, T(149) / 87, -T(89) / 29);
  397. q1 *= q3;
  398. check_approx_quaternion_result(q1, 34, 56, 20, 2);
  399. // using + (const quaternion<T> &)
  400. q1 = +q4;
  401. check_exact_quaternion_result(q1, 34, 56, 20, 2);
  402. // using - (const quaternion<T> &)
  403. q1 = -q4;
  404. check_exact_quaternion_result(q1, -34, -56, -20, -2);
  405. // comparisons:
  406. q1 = f0;
  407. test_compare(q1, f0, true);
  408. q1 += 1;
  409. test_compare(q1, f0, false);
  410. q1 = q3;
  411. test_compare(q1, q3, true);
  412. q1 += 1;
  413. test_compare(q1, q3, false);
  414. BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(q4), "(34,56,20,2)");
  415. q1 = boost::lexical_cast<boost::math::quaternion<T> >("(34,56,20,2)");
  416. check_exact_quaternion_result(q1, 34, 56, 20, 2);
  417. q1 = q4 + 1;
  418. q1.swap(q4);
  419. check_exact_quaternion_result(q1, 34, 56, 20, 2);
  420. check_exact_quaternion_result(q4, 35, 56, 20, 2);
  421. swap(q1, q4);
  422. check_exact_quaternion_result(q1, 35, 56, 20, 2);
  423. check_exact_quaternion_result(q4, 34, 56, 20, 2);
  424. BOOST_CHECK_EQUAL(real(q4), 34);
  425. check_exact_quaternion_result(unreal(q1), 0, 56, 20, 2);
  426. BOOST_CHECK_EQUAL(sup(q4), 56);
  427. BOOST_CHECK_EQUAL(sup(-q4), 56);
  428. BOOST_CHECK_EQUAL(l1(q4), 34 + 56 + 20 + 2);
  429. BOOST_CHECK_EQUAL(l1(-q4), 34 + 56 + 20 + 2);
  430. BOOST_CHECK_CLOSE(abs(q4), boost::lexical_cast<T>("68.52736679604725626189080285032080446623"), tol);
  431. BOOST_CHECK_EQUAL(norm(q4), 4696);
  432. check_exact_quaternion_result(conj(q4), 34, -56, -20, -2);
  433. check_approx_quaternion_result(exp(q4), boost::lexical_cast<T>("-572700109350177.2871954597833265926769952"), boost::lexical_cast<T>("104986825963321.656891930274999993423955"), boost::lexical_cast<T>("37495294986900.59174711795535714050855537"), boost::lexical_cast<T>("3749529498690.059174711795535714050855537"), 300);
  434. check_approx_quaternion_result(pow(q4, 3), -321776, -4032, -1440, -144);
  435. check_approx_quaternion_result(sin(q4), boost::lexical_cast<T>("18285331065398556228976865.03309127394107"), boost::lexical_cast<T>("-27602822237164214909853379.68314411086089"), boost::lexical_cast<T>("-9858150798987219610661921.315408611021748"), boost::lexical_cast<T>("-985815079898721961066192.1315408611021748"), 40);
  436. check_approx_quaternion_result(cos(q4), boost::lexical_cast<T>("-29326963088663226843378365.81173441507358"), boost::lexical_cast<T>("-17210331032912252411431342.73890926302336"), boost::lexical_cast<T>("-6146546797468661575511193.835324736794056"), boost::lexical_cast<T>("-614654679746866157551119.3835324736794056"), 40);
  437. if(std::numeric_limits<T>::max_exponent >= std::numeric_limits<double>::max_exponent)
  438. check_approx_quaternion_result(tan(q4), boost::lexical_cast<T>("-3.758831069989140832054627039712718213887e-52"), boost::lexical_cast<T>("0.941209703633940052004990419391011076385"), boost::lexical_cast<T>("0.3361463227264071614303537212110753844232"), boost::lexical_cast<T>("0.03361463227264071614303537212110753844232"), 40);
  439. check_approx_quaternion_result(sinh(q4), boost::lexical_cast<T>("-286350054675088.6435977298916624551903343"), boost::lexical_cast<T>("52493412981660.82844596513750015091043914"), boost::lexical_cast<T>("18747647493450.29587355897767862532515683"), boost::lexical_cast<T>("1874764749345.029587355897767862532515683"), 200);
  440. check_approx_quaternion_result(cosh(q4), boost::lexical_cast<T>("-286350054675088.6435977298916641374866609"), boost::lexical_cast<T>("52493412981660.82844596513749984251351591"), boost::lexical_cast<T>("18747647493450.29587355897767851518339854"), boost::lexical_cast<T>("1874764749345.029587355897767851518339854"), 200);
  441. if(std::numeric_limits<T>::max_exponent >= std::numeric_limits<double>::max_exponent)
  442. check_approx_quaternion_result(tanh(q4), boost::lexical_cast<T>("0.9999999999999999999999999999945544805016"), boost::lexical_cast<T>("-2.075260044344318549117301019071435084233e-30"), boost::lexical_cast<T>("-7.411643015515423389704646496683696729404e-31"), boost::lexical_cast<T>("-7.411643015515423389704646496683696729404e-32"), 200);
  443. #ifndef BOOST_NO_TEMPLATE_TEMPLATES
  444. check_approx_quaternion_result(sinc_pi(q4), boost::lexical_cast<T>("-239180458943182912968898.352151239530846"), boost::lexical_cast<T>("-417903427539587405399855.0577257263862799"), boost::lexical_cast<T>("-149251224121281216214233.9491877594236714"), boost::lexical_cast<T>("-14925122412128121621423.39491877594236714"), 200);
  445. check_approx_quaternion_result(sinhc_pi(q4), boost::lexical_cast<T>("-1366603120232.604666248483234115586439226"), boost::lexical_cast<T>("3794799638667.255581055299959135992677524"), boost::lexical_cast<T>("1355285585238.305564662607128262854527687"), boost::lexical_cast<T>("135528558523.8305564662607128262854527687"), 200);
  446. #endif
  447. //
  448. // Construction variations:
  449. //
  450. T rho = boost::math::constants::root_two<T>() * 2;
  451. T theta = boost::math::constants::pi<T>() / 4;
  452. T phi1 = theta;
  453. T phi2 = theta;
  454. q1 = ::boost::math::spherical(rho, theta, phi1, phi2);
  455. check_approx_quaternion_result(q1, 1, 1, boost::math::constants::root_two<T>(), 2, 10);
  456. T alpha = theta;
  457. q1 = ::boost::math::semipolar(rho, alpha, phi1, phi2);
  458. check_approx_quaternion_result(q1, boost::math::constants::root_two<T>(), boost::math::constants::root_two<T>(), boost::math::constants::root_two<T>(), boost::math::constants::root_two<T>(), 10);
  459. T rho1 = 1;
  460. T rho2 = 2;
  461. T theta1 = 0;
  462. T theta2 = boost::math::constants::half_pi<T>();
  463. q1 = ::boost::math::multipolar(rho1, theta1, rho2, theta2);
  464. check_approx_quaternion_result(q1, 1, 0, 0, 2, 10);
  465. T t = 5;
  466. T radius = boost::math::constants::root_two<T>();
  467. T longitude = boost::math::constants::pi<T>() / 4;
  468. T lattitude = boost::math::constants::pi<T>() / 3;
  469. q1 = ::boost::math::cylindrospherical(t, radius, longitude, lattitude);
  470. check_approx_quaternion_result(q1, 5, 0.5, 0.5, boost::lexical_cast<T>("1.224744871391589049098642037352945695983"), 10);
  471. T r = boost::math::constants::root_two<T>();
  472. T angle = boost::math::constants::pi<T>() / 4;
  473. T h1 = 3;
  474. T h2 = 4;
  475. q1 = ::boost::math::cylindrical(r, angle, h1, h2);
  476. check_approx_quaternion_result(q1, 1, 1, 3, 4, 10);
  477. ::boost::math::quaternion<T> quaternion_1(1);
  478. ::boost::math::quaternion<T> quaternion_i(0, 1);
  479. ::boost::math::quaternion<T> quaternion_j(0, 0, 1);
  480. ::boost::math::quaternion<T> quaternion_k(0, 0, 0, 1);
  481. check_exact_quaternion_result(quaternion_1 * quaternion_1, 1, 0, 0, 0);
  482. check_exact_quaternion_result(quaternion_1 * quaternion_i, 0, 1, 0, 0);
  483. check_exact_quaternion_result(quaternion_1 * quaternion_j, 0, 0, 1, 0);
  484. check_exact_quaternion_result(quaternion_1 * quaternion_k, 0, 0, 0, 1);
  485. check_exact_quaternion_result(quaternion_i * quaternion_1, 0, 1, 0, 0);
  486. check_exact_quaternion_result(quaternion_i * quaternion_i, -1, 0, 0, 0);
  487. check_exact_quaternion_result(quaternion_i * quaternion_j, 0, 0, 0, 1);
  488. check_exact_quaternion_result(quaternion_i * quaternion_k, 0, 0, -1, 0);
  489. check_exact_quaternion_result(quaternion_j * quaternion_1, 0, 0, 1, 0);
  490. check_exact_quaternion_result(quaternion_j * quaternion_i, 0, 0, 0, -1);
  491. check_exact_quaternion_result(quaternion_j * quaternion_j, -1, 0, 0, 0);
  492. check_exact_quaternion_result(quaternion_j * quaternion_k, 0, 1, 0, 0);
  493. check_exact_quaternion_result(quaternion_k * quaternion_1, 0, 0, 0, 1);
  494. check_exact_quaternion_result(quaternion_k * quaternion_i, 0, 0, 1, 0);
  495. check_exact_quaternion_result(quaternion_k * quaternion_j, 0, -1, 0, 0);
  496. check_exact_quaternion_result(quaternion_k * quaternion_k, -1, 0, 0, 0);
  497. }
  498. BOOST_AUTO_TEST_CASE_TEMPLATE(multiplication_test, T, test_types)
  499. {
  500. #if BOOST_WORKAROUND(__GNUC__, < 3)
  501. #else /* BOOST_WORKAROUND(__GNUC__, < 3) */
  502. using ::std::numeric_limits;
  503. using ::boost::math::abs;
  504. #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
  505. BOOST_TEST_MESSAGE("Testing multiplication for "
  506. << string_type_name<T>::_() << ".");
  507. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  508. (abs(::boost::math::quaternion<T>(1,0,0,0)*
  509. ::boost::math::quaternion<T>(1,0,0,0)-static_cast<T>(1)))
  510. (numeric_limits<T>::epsilon()));
  511. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  512. (abs(::boost::math::quaternion<T>(0,1,0,0)*
  513. ::boost::math::quaternion<T>(0,1,0,0)+static_cast<T>(1)))
  514. (numeric_limits<T>::epsilon()));
  515. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  516. (abs(::boost::math::quaternion<T>(0,0,1,0)*
  517. ::boost::math::quaternion<T>(0,0,1,0)+static_cast<T>(1)))
  518. (numeric_limits<T>::epsilon()));
  519. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  520. (abs(::boost::math::quaternion<T>(0,0,0,1)*
  521. ::boost::math::quaternion<T>(0,0,0,1)+static_cast<T>(1)))
  522. (numeric_limits<T>::epsilon()));
  523. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  524. (abs(::boost::math::quaternion<T>(0,1,0,0)*
  525. ::boost::math::quaternion<T>(0,0,1,0)-
  526. ::boost::math::quaternion<T>(0,0,0,1)))
  527. (numeric_limits<T>::epsilon()));
  528. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  529. (abs(::boost::math::quaternion<T>(0,0,1,0)*
  530. ::boost::math::quaternion<T>(0,1,0,0)+
  531. ::boost::math::quaternion<T>(0,0,0,1)))
  532. (numeric_limits<T>::epsilon()));
  533. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  534. (abs(::boost::math::quaternion<T>(0,0,1,0)*
  535. ::boost::math::quaternion<T>(0,0,0,1)-
  536. ::boost::math::quaternion<T>(0,1,0,0)))
  537. (numeric_limits<T>::epsilon()));
  538. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  539. (abs(::boost::math::quaternion<T>(0,0,0,1)*
  540. ::boost::math::quaternion<T>(0,0,1,0)+
  541. ::boost::math::quaternion<T>(0,1,0,0)))
  542. (numeric_limits<T>::epsilon()));
  543. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  544. (abs(::boost::math::quaternion<T>(0,0,0,1)*
  545. ::boost::math::quaternion<T>(0,1,0,0)-
  546. ::boost::math::quaternion<T>(0,0,1,0)))
  547. (numeric_limits<T>::epsilon()));
  548. BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(),
  549. (abs(::boost::math::quaternion<T>(0,1,0,0)*
  550. ::boost::math::quaternion<T>(0,0,0,1)+
  551. ::boost::math::quaternion<T>(0,0,1,0)))
  552. (numeric_limits<T>::epsilon()));
  553. }
  554. BOOST_AUTO_TEST_CASE_TEMPLATE(exp_test, T, test_types)
  555. {
  556. #if BOOST_WORKAROUND(__GNUC__, < 3)
  557. #else /* BOOST_WORKAROUND(__GNUC__, < 3) */
  558. using ::std::numeric_limits;
  559. using ::std::atan;
  560. using ::boost::math::abs;
  561. #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
  562. BOOST_TEST_MESSAGE("Testing exp for "
  563. << string_type_name<T>::_() << ".");
  564. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  565. (abs(exp(::boost::math::quaternion<T>
  566. (0,4*atan(static_cast<T>(1)),0,0))+static_cast<T>(1)))
  567. (2*numeric_limits<T>::epsilon()));
  568. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  569. (abs(exp(::boost::math::quaternion<T>
  570. (0,0,4*atan(static_cast<T>(1)),0))+static_cast<T>(1)))
  571. (2*numeric_limits<T>::epsilon()));
  572. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  573. (abs(exp(::boost::math::quaternion<T>
  574. (0,0,0,4*atan(static_cast<T>(1))))+static_cast<T>(1)))
  575. (2*numeric_limits<T>::epsilon()));
  576. }
  577. BOOST_AUTO_TEST_CASE_TEMPLATE(cos_test, T, test_types)
  578. {
  579. #if BOOST_WORKAROUND(__GNUC__, < 3)
  580. #else /* BOOST_WORKAROUND(__GNUC__, < 3) */
  581. using ::std::numeric_limits;
  582. using ::std::log;
  583. using ::boost::math::abs;
  584. #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
  585. BOOST_TEST_MESSAGE("Testing cos for "
  586. << string_type_name<T>::_() << ".");
  587. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  588. (abs(static_cast<T>(4)*cos(::boost::math::quaternion<T>
  589. (0,log(static_cast<T>(2)),0,0))-static_cast<T>(5)))
  590. (4*numeric_limits<T>::epsilon()));
  591. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  592. (abs(static_cast<T>(4)*cos(::boost::math::quaternion<T>
  593. (0,0,log(static_cast<T>(2)),0))-static_cast<T>(5)))
  594. (4*numeric_limits<T>::epsilon()));
  595. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  596. (abs(static_cast<T>(4)*cos(::boost::math::quaternion<T>
  597. (0,0,0,log(static_cast<T>(2))))-static_cast<T>(5)))
  598. (4*numeric_limits<T>::epsilon()));
  599. }
  600. BOOST_AUTO_TEST_CASE_TEMPLATE(sin_test, T, test_types)
  601. {
  602. #if BOOST_WORKAROUND(__GNUC__, < 3)
  603. #else /* BOOST_WORKAROUND(__GNUC__, < 3) */
  604. using ::std::numeric_limits;
  605. using ::std::log;
  606. using ::boost::math::abs;
  607. #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
  608. BOOST_TEST_MESSAGE("Testing sin for "
  609. << string_type_name<T>::_() << ".");
  610. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  611. (abs(static_cast<T>(4)*sin(::boost::math::quaternion<T>
  612. (0,log(static_cast<T>(2)),0,0))
  613. -::boost::math::quaternion<T>(0,3,0,0)))
  614. (4*numeric_limits<T>::epsilon()));
  615. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  616. (abs(static_cast<T>(4)*sin(::boost::math::quaternion<T>
  617. (0,0,log(static_cast<T>(2)),0))
  618. -::boost::math::quaternion<T>(0,0,3,0)))
  619. (4*numeric_limits<T>::epsilon()));
  620. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  621. (abs(static_cast<T>(4)*sin(::boost::math::quaternion<T>
  622. (0,0,0,log(static_cast<T>(2))))
  623. -::boost::math::quaternion<T>(0,0,0,3)))
  624. (4*numeric_limits<T>::epsilon()));
  625. }
  626. BOOST_AUTO_TEST_CASE_TEMPLATE(cosh_test, T, test_types)
  627. {
  628. #if BOOST_WORKAROUND(__GNUC__, < 3)
  629. #else /* BOOST_WORKAROUND(__GNUC__, < 3) */
  630. using ::std::numeric_limits;
  631. using ::std::atan;
  632. using ::boost::math::abs;
  633. #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
  634. BOOST_TEST_MESSAGE("Testing cosh for "
  635. << string_type_name<T>::_() << ".");
  636. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  637. (abs(cosh(::boost::math::quaternion<T>
  638. (0,4*atan(static_cast<T>(1)),0,0))
  639. +static_cast<T>(1)))
  640. (4*numeric_limits<T>::epsilon()));
  641. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  642. (abs(cosh(::boost::math::quaternion<T>
  643. (0,0,4*atan(static_cast<T>(1)),0))
  644. +static_cast<T>(1)))
  645. (4*numeric_limits<T>::epsilon()));
  646. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  647. (abs(cosh(::boost::math::quaternion<T>
  648. (0,0,0,4*atan(static_cast<T>(1))))
  649. +static_cast<T>(1)))
  650. (4*numeric_limits<T>::epsilon()));
  651. }
  652. BOOST_AUTO_TEST_CASE_TEMPLATE(sinh_test, T, test_types)
  653. {
  654. #if BOOST_WORKAROUND(__GNUC__, < 3)
  655. #else /* BOOST_WORKAROUND(__GNUC__, < 3) */
  656. using ::std::numeric_limits;
  657. using ::std::atan;
  658. using ::boost::math::abs;
  659. #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
  660. BOOST_TEST_MESSAGE("Testing sinh for "
  661. << string_type_name<T>::_() << ".");
  662. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  663. (abs(sinh(::boost::math::quaternion<T>
  664. (0,2*atan(static_cast<T>(1)),0,0))
  665. -::boost::math::quaternion<T>(0,1,0,0)))
  666. (4*numeric_limits<T>::epsilon()));
  667. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  668. (abs(sinh(::boost::math::quaternion<T>
  669. (0,0,2*atan(static_cast<T>(1)),0))
  670. -::boost::math::quaternion<T>(0,0,1,0)))
  671. (4*numeric_limits<T>::epsilon()));
  672. BOOST_CHECK_PREDICATE(::std::less_equal<T>(),
  673. (abs(sinh(::boost::math::quaternion<T>
  674. (0,0,0,2*atan(static_cast<T>(1))))
  675. -::boost::math::quaternion<T>(0,0,0,1)))
  676. (4*numeric_limits<T>::epsilon()));
  677. }