]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
b32b8144 | 14 | #define BOOST_TEST_MAIN |
7c673cae FG |
15 | #include <boost/test/unit_test.hpp> |
16 | #include <boost/test/unit_test_log.hpp> | |
b32b8144 FG |
17 | #include <boost/multiprecision/cpp_bin_float.hpp> |
18 | #include <boost/multiprecision/cpp_dec_float.hpp> | |
7c673cae FG |
19 | |
20 | #include <boost/math/quaternion.hpp> | |
21 | ||
b32b8144 FG |
22 | #ifdef BOOST_MSVC |
23 | #pragma warning(disable:4127) // conditional expression is constant | |
24 | #endif | |
25 | ||
7c673cae FG |
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); | |
b32b8144 FG |
41 | DEFINE_TYPE_NAME(boost::multiprecision::cpp_bin_float_quad); |
42 | DEFINE_TYPE_NAME(boost::multiprecision::number<boost::multiprecision::cpp_dec_float<25> >); | |
7c673cae | 43 | |
b32b8144 FG |
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 | |
7c673cae | 49 | #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS |
b32b8144 | 50 | # define LD_TEST , long double |
7c673cae | 51 | #else |
b32b8144 | 52 | # define LD_TEST |
7c673cae FG |
53 | #endif |
54 | ||
b32b8144 FG |
55 | |
56 | typedef boost::mpl::list<float,double LD_TEST, boost::multiprecision::cpp_bin_float_quad CPP_DEC_FLOAT_TEST > test_types; | |
57 | ||
7c673cae FG |
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)) | |
125 | inline float abs(float v) | |
126 | { | |
127 | return(fabs(v)); | |
128 | } | |
129 | ||
130 | inline double abs(double v) | |
131 | { | |
132 | return(fabs(v)); | |
133 | } | |
134 | ||
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 | ||
b32b8144 FG |
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 | }; | |
7c673cae FG |
166 | |
167 | ||
b32b8144 FG |
168 | template <class T, class U> |
169 | void test_compare(const T& a, const U& b, bool eq) | |
7c673cae | 170 | { |
b32b8144 FG |
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> | |
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> | |
199 | void check_approx_quaternion_result(const boost::math::quaternion<T>& q, R1 a, R2 b, R3 c, R4 d, int eps = 10) | |
200 | { | |
f67539c2 | 201 | T tol = std::numeric_limits<T>::epsilon() * eps * 100; // epsilon as a percentage. |
b32b8144 FG |
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> | |
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> | |
312 | void check_complex_ops() {} | |
313 | ||
314 | template<> | |
315 | void check_complex_ops<float>() { check_complex_ops_imp<float>(); } | |
316 | template<> | |
317 | void check_complex_ops<double>() { check_complex_ops_imp<double>(); } | |
318 | template<> | |
319 | void check_complex_ops<long double>() { check_complex_ops_imp<long double>(); } | |
320 | ||
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 | ||
7c673cae | 391 | // using *= (const T &) |
b32b8144 FG |
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); | |
7c673cae | 536 | #endif |
b32b8144 FG |
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; | |
f67539c2 TL |
558 | T latitude = boost::math::constants::pi<T>() / 3; |
559 | q1 = ::boost::math::cylindrospherical(t, radius, longitude, latitude); | |
b32b8144 FG |
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); | |
7c673cae FG |
591 | } |
592 | ||
b32b8144 | 593 | BOOST_AUTO_TEST_CASE_TEMPLATE(multiplication_test, T, test_types) |
7c673cae FG |
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 | ||
b32b8144 | 664 | BOOST_AUTO_TEST_CASE_TEMPLATE(exp_test, T, test_types) |
7c673cae FG |
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 | ||
b32b8144 | 696 | BOOST_AUTO_TEST_CASE_TEMPLATE(cos_test, T, test_types) |
7c673cae FG |
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 | ||
b32b8144 | 728 | BOOST_AUTO_TEST_CASE_TEMPLATE(sin_test, T, test_types) |
7c673cae FG |
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 | ||
b32b8144 | 763 | BOOST_AUTO_TEST_CASE_TEMPLATE(cosh_test, T, test_types) |
7c673cae FG |
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 | ||
b32b8144 | 798 | BOOST_AUTO_TEST_CASE_TEMPLATE(sinh_test, T, test_types) |
7c673cae FG |
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 |