]>
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 | ||
1e59de90 | 22 | #ifdef _MSC_VER |
b32b8144 FG |
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; | |
1e59de90 TL |
400 | if(std::numeric_limits<T>::radix == 2) |
401 | check_exact_quaternion_result(q4, -T(868) / 7, T(420) / 7, T(490) / 7, T(560) / 7); | |
402 | else | |
403 | // cpp_dec_float division is still inextact / not rounded: | |
404 | check_approx_quaternion_result(q4, -T(868) / 7, T(420) / 7, T(490) / 7, T(560) / 7); | |
b32b8144 FG |
405 | |
406 | q4 = q3; | |
407 | q4 /= boost::math::quaternion<T>(9, 4, 6, 2); | |
408 | check_approx_quaternion_result(q4, T(127) / 137, T(68) / 137, T(13) / 137, T(54) / 137); | |
409 | q4 *= boost::math::quaternion<T>(9, 4, 6, 2); | |
410 | check_approx_quaternion_result(q4, 5, 6, 7, 8); | |
411 | ||
412 | q4 = boost::math::quaternion<T>(34, 56, 20, 2); | |
413 | // using + (const T &, const quaternion<T> &) | |
414 | q1 = f1 + q4; | |
415 | check_exact_quaternion_result(q1, 41, 56, 20, 2); | |
416 | ||
417 | // using + (const quaternion<T> &, const T &) | |
418 | q1 = q4 + f1; | |
419 | check_exact_quaternion_result(q1, 41, 56, 20, 2); | |
420 | ||
421 | // using + (const T &, const quaternion<T> &) | |
422 | q1 = f0 + q4; | |
423 | check_exact_quaternion_result(q1, 41, 56, 20, 2); | |
424 | ||
425 | // using + (const quaternion<T> &, const T &) | |
426 | q1 = q4 + f0; | |
427 | check_exact_quaternion_result(q1, 41, 56, 20, 2); | |
428 | ||
429 | // using + (const quaternion<T> &,const quaternion<T> &) | |
430 | q1 = q3 + q4; | |
431 | check_exact_quaternion_result(q1, 39, 62, 27, 10); | |
432 | ||
433 | // using - (const T &, const quaternion<T> &) | |
434 | q1 = f1 - q4; | |
435 | check_exact_quaternion_result(q1, 7-34, -56, -20, -2); | |
436 | ||
437 | // using - (const quaternion<T> &, const T &) | |
438 | q1 = q4 - f1; | |
439 | check_exact_quaternion_result(q1, 34-7, 56, 20, 2); | |
440 | ||
441 | // using - (const T &, const quaternion<T> &) | |
442 | q1 = f0 - q4; | |
443 | check_exact_quaternion_result(q1, 7-34, -56, -20, -2); | |
444 | ||
445 | // using - (const quaternion<T> &, const T &) | |
446 | q1 = q4 - f0; | |
447 | check_exact_quaternion_result(q1, 34-7, 56, 20, 2); | |
448 | ||
449 | // using - (const quaternion<T> &,const quaternion<T> &) | |
450 | q1 = q3 - q4; | |
451 | check_exact_quaternion_result(q1, -29, -50, -13, 6); | |
452 | ||
453 | // using * (const T &, const quaternion<T> &) | |
454 | q1 = f0 * q4; | |
455 | check_exact_quaternion_result(q1, 238, 392, 140, 14); | |
456 | ||
457 | // using * (const quaternion<T> &, const T &) | |
458 | q1 = q4 * f0; | |
459 | check_exact_quaternion_result(q1, 238, 392, 140, 14); | |
460 | ||
461 | // using * (const quaternion<T> &,const quaternion<T> &) | |
462 | q1 = q4 * q3; | |
463 | check_exact_quaternion_result(q1, -322, 630, -98, 554); | |
464 | q1 = q3 * q4; | |
465 | check_exact_quaternion_result(q1, -322, 338, 774, 10); | |
466 | ||
467 | // using / (const T &, const quaternion<T> &) | |
468 | q1 = T(f0) / q4; | |
469 | check_approx_quaternion_result(q1, T(119) / 2348, -T(49) / 587, -T(35) / 1174, -T(7) / 2348); | |
470 | q1 *= q4; | |
471 | BOOST_CHECK_CLOSE(q1.R_component_1(), T(7), tol); | |
472 | BOOST_CHECK_SMALL(q1.R_component_2(), tol); | |
473 | BOOST_CHECK_SMALL(q1.R_component_3(), tol); | |
474 | BOOST_CHECK_SMALL(q1.R_component_3(), tol); | |
475 | ||
476 | // using / (const quaternion<T> &, const T &) | |
477 | q1 = q4 / T(f0); | |
478 | check_approx_quaternion_result(q1, T(34) / 7, T(56) / 7, T(20) / 7, T(2) / 7); | |
479 | ||
480 | // using / (const quaternion<T> &,const quaternion<T> &) | |
481 | q1 = q4 / q3; | |
482 | check_approx_quaternion_result(q1, T(331) / 87, -T(35) / 87, T(149) / 87, -T(89) / 29); | |
483 | q1 *= q3; | |
484 | check_approx_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 | // using - (const quaternion<T> &) | |
491 | q1 = -q4; | |
492 | check_exact_quaternion_result(q1, -34, -56, -20, -2); | |
493 | ||
494 | // comparisons: | |
495 | q1 = f0; | |
496 | test_compare(q1, f0, true); | |
497 | q1 += 1; | |
498 | test_compare(q1, f0, false); | |
499 | q1 = q3; | |
500 | test_compare(q1, q3, true); | |
501 | q1 += 1; | |
502 | test_compare(q1, q3, false); | |
503 | ||
1e59de90 | 504 | #ifndef BOOST_MATH_STANDALONE |
b32b8144 FG |
505 | BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(q4), "(34,56,20,2)"); |
506 | q1 = boost::lexical_cast<boost::math::quaternion<T> >("(34,56,20,2)"); | |
507 | check_exact_quaternion_result(q1, 34, 56, 20, 2); | |
508 | ||
509 | q1 = q4 + 1; | |
510 | q1.swap(q4); | |
511 | check_exact_quaternion_result(q1, 34, 56, 20, 2); | |
512 | check_exact_quaternion_result(q4, 35, 56, 20, 2); | |
513 | swap(q1, q4); | |
514 | check_exact_quaternion_result(q1, 35, 56, 20, 2); | |
515 | check_exact_quaternion_result(q4, 34, 56, 20, 2); | |
516 | ||
517 | BOOST_CHECK_EQUAL(real(q4), 34); | |
518 | check_exact_quaternion_result(unreal(q1), 0, 56, 20, 2); | |
519 | BOOST_CHECK_EQUAL(sup(q4), 56); | |
520 | BOOST_CHECK_EQUAL(sup(-q4), 56); | |
521 | BOOST_CHECK_EQUAL(l1(q4), 34 + 56 + 20 + 2); | |
522 | BOOST_CHECK_EQUAL(l1(-q4), 34 + 56 + 20 + 2); | |
523 | BOOST_CHECK_CLOSE(abs(q4), boost::lexical_cast<T>("68.52736679604725626189080285032080446623"), tol); | |
524 | BOOST_CHECK_EQUAL(norm(q4), 4696); | |
525 | check_exact_quaternion_result(conj(q4), 34, -56, -20, -2); | |
526 | 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); | |
527 | check_approx_quaternion_result(pow(q4, 3), -321776, -4032, -1440, -144); | |
528 | 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); | |
529 | 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); | |
530 | if(std::numeric_limits<T>::max_exponent >= std::numeric_limits<double>::max_exponent) | |
531 | 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); | |
532 | ||
533 | 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); | |
534 | 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); | |
535 | if(std::numeric_limits<T>::max_exponent >= std::numeric_limits<double>::max_exponent) | |
536 | 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); | |
537 | ||
538 | #ifndef BOOST_NO_TEMPLATE_TEMPLATES | |
539 | 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); | |
540 | 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 | 541 | #endif |
1e59de90 | 542 | #endif // BOOST_MATH_STANDALONE |
b32b8144 FG |
543 | // |
544 | // Construction variations: | |
545 | // | |
546 | T rho = boost::math::constants::root_two<T>() * 2; | |
547 | T theta = boost::math::constants::pi<T>() / 4; | |
548 | T phi1 = theta; | |
549 | T phi2 = theta; | |
550 | q1 = ::boost::math::spherical(rho, theta, phi1, phi2); | |
551 | check_approx_quaternion_result(q1, 1, 1, boost::math::constants::root_two<T>(), 2, 10); | |
552 | T alpha = theta; | |
553 | q1 = ::boost::math::semipolar(rho, alpha, phi1, phi2); | |
554 | 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); | |
555 | T rho1 = 1; | |
556 | T rho2 = 2; | |
557 | T theta1 = 0; | |
558 | T theta2 = boost::math::constants::half_pi<T>(); | |
559 | q1 = ::boost::math::multipolar(rho1, theta1, rho2, theta2); | |
560 | check_approx_quaternion_result(q1, 1, 0, 0, 2, 10); | |
561 | T t = 5; | |
562 | T radius = boost::math::constants::root_two<T>(); | |
563 | T longitude = boost::math::constants::pi<T>() / 4; | |
f67539c2 TL |
564 | T latitude = boost::math::constants::pi<T>() / 3; |
565 | q1 = ::boost::math::cylindrospherical(t, radius, longitude, latitude); | |
1e59de90 TL |
566 | |
567 | #ifndef BOOST_MATH_STANDALONE | |
b32b8144 | 568 | check_approx_quaternion_result(q1, 5, 0.5, 0.5, boost::lexical_cast<T>("1.224744871391589049098642037352945695983"), 10); |
1e59de90 TL |
569 | #endif |
570 | ||
b32b8144 FG |
571 | T r = boost::math::constants::root_two<T>(); |
572 | T angle = boost::math::constants::pi<T>() / 4; | |
573 | T h1 = 3; | |
574 | T h2 = 4; | |
575 | q1 = ::boost::math::cylindrical(r, angle, h1, h2); | |
576 | check_approx_quaternion_result(q1, 1, 1, 3, 4, 10); | |
577 | ||
578 | ::boost::math::quaternion<T> quaternion_1(1); | |
579 | ::boost::math::quaternion<T> quaternion_i(0, 1); | |
580 | ::boost::math::quaternion<T> quaternion_j(0, 0, 1); | |
581 | ::boost::math::quaternion<T> quaternion_k(0, 0, 0, 1); | |
582 | check_exact_quaternion_result(quaternion_1 * quaternion_1, 1, 0, 0, 0); | |
583 | check_exact_quaternion_result(quaternion_1 * quaternion_i, 0, 1, 0, 0); | |
584 | check_exact_quaternion_result(quaternion_1 * quaternion_j, 0, 0, 1, 0); | |
585 | check_exact_quaternion_result(quaternion_1 * quaternion_k, 0, 0, 0, 1); | |
586 | ||
587 | check_exact_quaternion_result(quaternion_i * quaternion_1, 0, 1, 0, 0); | |
588 | check_exact_quaternion_result(quaternion_i * quaternion_i, -1, 0, 0, 0); | |
589 | check_exact_quaternion_result(quaternion_i * quaternion_j, 0, 0, 0, 1); | |
590 | check_exact_quaternion_result(quaternion_i * quaternion_k, 0, 0, -1, 0); | |
591 | ||
592 | check_exact_quaternion_result(quaternion_j * quaternion_1, 0, 0, 1, 0); | |
593 | check_exact_quaternion_result(quaternion_j * quaternion_i, 0, 0, 0, -1); | |
594 | check_exact_quaternion_result(quaternion_j * quaternion_j, -1, 0, 0, 0); | |
595 | check_exact_quaternion_result(quaternion_j * quaternion_k, 0, 1, 0, 0); | |
596 | ||
597 | check_exact_quaternion_result(quaternion_k * quaternion_1, 0, 0, 0, 1); | |
598 | check_exact_quaternion_result(quaternion_k * quaternion_i, 0, 0, 1, 0); | |
599 | check_exact_quaternion_result(quaternion_k * quaternion_j, 0, -1, 0, 0); | |
600 | check_exact_quaternion_result(quaternion_k * quaternion_k, -1, 0, 0, 0); | |
7c673cae FG |
601 | } |
602 | ||
b32b8144 | 603 | BOOST_AUTO_TEST_CASE_TEMPLATE(multiplication_test, T, test_types) |
7c673cae FG |
604 | { |
605 | #if BOOST_WORKAROUND(__GNUC__, < 3) | |
606 | #else /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
607 | using ::std::numeric_limits; | |
608 | ||
609 | using ::boost::math::abs; | |
610 | #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
611 | ||
612 | ||
613 | BOOST_TEST_MESSAGE("Testing multiplication for " | |
614 | << string_type_name<T>::_() << "."); | |
615 | ||
616 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
617 | (abs(::boost::math::quaternion<T>(1,0,0,0)* | |
618 | ::boost::math::quaternion<T>(1,0,0,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,1,0,0)* | |
623 | ::boost::math::quaternion<T>(0,1,0,0)+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,0,1,0)* | |
628 | ::boost::math::quaternion<T>(0,0,1,0)+static_cast<T>(1))) | |
629 | (numeric_limits<T>::epsilon())); | |
630 | ||
631 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
632 | (abs(::boost::math::quaternion<T>(0,0,0,1)* | |
633 | ::boost::math::quaternion<T>(0,0,0,1)+static_cast<T>(1))) | |
634 | (numeric_limits<T>::epsilon())); | |
635 | ||
636 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
637 | (abs(::boost::math::quaternion<T>(0,1,0,0)* | |
638 | ::boost::math::quaternion<T>(0,0,1,0)- | |
639 | ::boost::math::quaternion<T>(0,0,0,1))) | |
640 | (numeric_limits<T>::epsilon())); | |
641 | ||
642 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
643 | (abs(::boost::math::quaternion<T>(0,0,1,0)* | |
644 | ::boost::math::quaternion<T>(0,1,0,0)+ | |
645 | ::boost::math::quaternion<T>(0,0,0,1))) | |
646 | (numeric_limits<T>::epsilon())); | |
647 | ||
648 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
649 | (abs(::boost::math::quaternion<T>(0,0,1,0)* | |
650 | ::boost::math::quaternion<T>(0,0,0,1)- | |
651 | ::boost::math::quaternion<T>(0,1,0,0))) | |
652 | (numeric_limits<T>::epsilon())); | |
653 | ||
654 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
655 | (abs(::boost::math::quaternion<T>(0,0,0,1)* | |
656 | ::boost::math::quaternion<T>(0,0,1,0)+ | |
657 | ::boost::math::quaternion<T>(0,1,0,0))) | |
658 | (numeric_limits<T>::epsilon())); | |
659 | ||
660 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
661 | (abs(::boost::math::quaternion<T>(0,0,0,1)* | |
662 | ::boost::math::quaternion<T>(0,1,0,0)- | |
663 | ::boost::math::quaternion<T>(0,0,1,0))) | |
664 | (numeric_limits<T>::epsilon())); | |
665 | ||
666 | BOOST_REQUIRE_PREDICATE(::std::less_equal<T>(), | |
667 | (abs(::boost::math::quaternion<T>(0,1,0,0)* | |
668 | ::boost::math::quaternion<T>(0,0,0,1)+ | |
669 | ::boost::math::quaternion<T>(0,0,1,0))) | |
670 | (numeric_limits<T>::epsilon())); | |
671 | } | |
672 | ||
673 | ||
b32b8144 | 674 | BOOST_AUTO_TEST_CASE_TEMPLATE(exp_test, T, test_types) |
7c673cae FG |
675 | { |
676 | #if BOOST_WORKAROUND(__GNUC__, < 3) | |
677 | #else /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
678 | using ::std::numeric_limits; | |
679 | ||
680 | using ::std::atan; | |
681 | ||
682 | using ::boost::math::abs; | |
683 | #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
684 | ||
685 | ||
686 | BOOST_TEST_MESSAGE("Testing exp for " | |
687 | << string_type_name<T>::_() << "."); | |
688 | ||
689 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
690 | (abs(exp(::boost::math::quaternion<T> | |
691 | (0,4*atan(static_cast<T>(1)),0,0))+static_cast<T>(1))) | |
692 | (2*numeric_limits<T>::epsilon())); | |
693 | ||
694 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
695 | (abs(exp(::boost::math::quaternion<T> | |
696 | (0,0,4*atan(static_cast<T>(1)),0))+static_cast<T>(1))) | |
697 | (2*numeric_limits<T>::epsilon())); | |
698 | ||
699 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
700 | (abs(exp(::boost::math::quaternion<T> | |
701 | (0,0,0,4*atan(static_cast<T>(1))))+static_cast<T>(1))) | |
702 | (2*numeric_limits<T>::epsilon())); | |
703 | } | |
704 | ||
705 | ||
b32b8144 | 706 | BOOST_AUTO_TEST_CASE_TEMPLATE(cos_test, T, test_types) |
7c673cae FG |
707 | { |
708 | #if BOOST_WORKAROUND(__GNUC__, < 3) | |
709 | #else /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
710 | using ::std::numeric_limits; | |
711 | ||
712 | using ::std::log; | |
713 | ||
714 | using ::boost::math::abs; | |
715 | #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
716 | ||
717 | ||
718 | BOOST_TEST_MESSAGE("Testing cos for " | |
719 | << string_type_name<T>::_() << "."); | |
720 | ||
721 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
722 | (abs(static_cast<T>(4)*cos(::boost::math::quaternion<T> | |
723 | (0,log(static_cast<T>(2)),0,0))-static_cast<T>(5))) | |
724 | (4*numeric_limits<T>::epsilon())); | |
725 | ||
726 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
727 | (abs(static_cast<T>(4)*cos(::boost::math::quaternion<T> | |
728 | (0,0,log(static_cast<T>(2)),0))-static_cast<T>(5))) | |
729 | (4*numeric_limits<T>::epsilon())); | |
730 | ||
731 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
732 | (abs(static_cast<T>(4)*cos(::boost::math::quaternion<T> | |
733 | (0,0,0,log(static_cast<T>(2))))-static_cast<T>(5))) | |
734 | (4*numeric_limits<T>::epsilon())); | |
735 | } | |
736 | ||
737 | ||
b32b8144 | 738 | BOOST_AUTO_TEST_CASE_TEMPLATE(sin_test, T, test_types) |
7c673cae FG |
739 | { |
740 | #if BOOST_WORKAROUND(__GNUC__, < 3) | |
741 | #else /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
742 | using ::std::numeric_limits; | |
743 | ||
744 | using ::std::log; | |
745 | ||
746 | using ::boost::math::abs; | |
747 | #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
748 | ||
749 | ||
750 | BOOST_TEST_MESSAGE("Testing sin for " | |
751 | << string_type_name<T>::_() << "."); | |
752 | ||
753 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
754 | (abs(static_cast<T>(4)*sin(::boost::math::quaternion<T> | |
755 | (0,log(static_cast<T>(2)),0,0)) | |
756 | -::boost::math::quaternion<T>(0,3,0,0))) | |
757 | (4*numeric_limits<T>::epsilon())); | |
758 | ||
759 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
760 | (abs(static_cast<T>(4)*sin(::boost::math::quaternion<T> | |
761 | (0,0,log(static_cast<T>(2)),0)) | |
762 | -::boost::math::quaternion<T>(0,0,3,0))) | |
763 | (4*numeric_limits<T>::epsilon())); | |
764 | ||
765 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
766 | (abs(static_cast<T>(4)*sin(::boost::math::quaternion<T> | |
767 | (0,0,0,log(static_cast<T>(2)))) | |
768 | -::boost::math::quaternion<T>(0,0,0,3))) | |
769 | (4*numeric_limits<T>::epsilon())); | |
770 | } | |
771 | ||
772 | ||
b32b8144 | 773 | BOOST_AUTO_TEST_CASE_TEMPLATE(cosh_test, T, test_types) |
7c673cae FG |
774 | { |
775 | #if BOOST_WORKAROUND(__GNUC__, < 3) | |
776 | #else /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
777 | using ::std::numeric_limits; | |
778 | ||
779 | using ::std::atan; | |
780 | ||
781 | using ::boost::math::abs; | |
782 | #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
783 | ||
784 | ||
785 | BOOST_TEST_MESSAGE("Testing cosh for " | |
786 | << string_type_name<T>::_() << "."); | |
787 | ||
788 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
789 | (abs(cosh(::boost::math::quaternion<T> | |
790 | (0,4*atan(static_cast<T>(1)),0,0)) | |
791 | +static_cast<T>(1))) | |
792 | (4*numeric_limits<T>::epsilon())); | |
793 | ||
794 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
795 | (abs(cosh(::boost::math::quaternion<T> | |
796 | (0,0,4*atan(static_cast<T>(1)),0)) | |
797 | +static_cast<T>(1))) | |
798 | (4*numeric_limits<T>::epsilon())); | |
799 | ||
800 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
801 | (abs(cosh(::boost::math::quaternion<T> | |
802 | (0,0,0,4*atan(static_cast<T>(1)))) | |
803 | +static_cast<T>(1))) | |
804 | (4*numeric_limits<T>::epsilon())); | |
805 | } | |
806 | ||
807 | ||
b32b8144 | 808 | BOOST_AUTO_TEST_CASE_TEMPLATE(sinh_test, T, test_types) |
7c673cae FG |
809 | { |
810 | #if BOOST_WORKAROUND(__GNUC__, < 3) | |
811 | #else /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
812 | using ::std::numeric_limits; | |
813 | ||
814 | using ::std::atan; | |
815 | ||
816 | using ::boost::math::abs; | |
817 | #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */ | |
818 | ||
819 | ||
820 | BOOST_TEST_MESSAGE("Testing sinh for " | |
821 | << string_type_name<T>::_() << "."); | |
822 | ||
823 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
824 | (abs(sinh(::boost::math::quaternion<T> | |
825 | (0,2*atan(static_cast<T>(1)),0,0)) | |
826 | -::boost::math::quaternion<T>(0,1,0,0))) | |
827 | (4*numeric_limits<T>::epsilon())); | |
828 | ||
829 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
830 | (abs(sinh(::boost::math::quaternion<T> | |
831 | (0,0,2*atan(static_cast<T>(1)),0)) | |
832 | -::boost::math::quaternion<T>(0,0,1,0))) | |
833 | (4*numeric_limits<T>::epsilon())); | |
834 | ||
835 | BOOST_CHECK_PREDICATE(::std::less_equal<T>(), | |
836 | (abs(sinh(::boost::math::quaternion<T> | |
837 | (0,0,0,2*atan(static_cast<T>(1)))) | |
838 | -::boost::math::quaternion<T>(0,0,0,1))) | |
839 | (4*numeric_limits<T>::epsilon())); | |
840 | } | |
841 |