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