1 // boost quaternion.hpp header file
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)
8 // See http://www.boost.org for updates, documentation, and revision history.
10 #ifndef BOOST_QUATERNION_HPP
11 #define BOOST_QUATERNION_HPP
15 #include <iosfwd> // for the "<<" and ">>" operators
16 #include <sstream> // for the "<<" operator
18 #include <boost/config.hpp> // for BOOST_NO_STD_LOCALE
19 #include <boost/detail/workaround.hpp>
20 #ifndef BOOST_NO_STD_LOCALE
21 #include <locale> // for the "<<" operator
22 #endif /* BOOST_NO_STD_LOCALE */
28 #include <boost/math/special_functions/sinc.hpp> // for the Sinus cardinal
29 #include <boost/math/special_functions/sinhc.hpp> // for the Hyperbolic Sinus cardinal
36 #if BOOST_WORKAROUND(__GNUC__, < 3)
37 // gcc 2.95.x uses expression templates for valarray calculations, but
38 // the result is not conforming. We need BOOST_GET_VALARRAY to get an
39 // actual valarray result when we need to call a member function
40 #define BOOST_GET_VALARRAY(T,x) ::std::valarray<T>(x)
41 // gcc 2.95.x has an "std::ios" class that is similar to
42 // "std::ios_base", so we just use a #define
43 #define BOOST_IOS_BASE ::std::ios
44 // gcc 2.x ignores function scope using declarations,
45 // put them in the scope of the enclosing namespace instead:
46 using ::std::valarray;
52 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
54 #define BOOST_QUATERNION_ACCESSOR_GENERATOR(type) \
60 quaternion<type> unreal() const \
62 return(quaternion<type>(static_cast<type>(0),b,c,d)); \
65 type R_component_1() const \
70 type R_component_2() const \
75 type R_component_3() const \
80 type R_component_4() const \
85 ::std::complex<type> C_component_1() const \
87 return(::std::complex<type>(a,b)); \
90 ::std::complex<type> C_component_2() const \
92 return(::std::complex<type>(c,d)); \
96 #define BOOST_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(type) \
97 template<typename X> \
98 quaternion<type> & operator = (quaternion<X> const & a_affecter) \
100 a = static_cast<type>(a_affecter.R_component_1()); \
101 b = static_cast<type>(a_affecter.R_component_2()); \
102 c = static_cast<type>(a_affecter.R_component_3()); \
103 d = static_cast<type>(a_affecter.R_component_4()); \
108 quaternion<type> & operator = (quaternion<type> const & a_affecter) \
118 quaternion<type> & operator = (type const & a_affecter) \
122 b = c = d = static_cast<type>(0); \
127 quaternion<type> & operator = (::std::complex<type> const & a_affecter) \
129 a = a_affecter.real(); \
130 b = a_affecter.imag(); \
132 c = d = static_cast<type>(0); \
138 #define BOOST_QUATERNION_MEMBER_DATA_GENERATOR(type) \
150 typedef T value_type;
153 // constructor for H seen as R^4
154 // (also default constructor)
156 explicit quaternion( T const & requested_a = T(),
157 T const & requested_b = T(),
158 T const & requested_c = T(),
159 T const & requested_d = T())
169 // constructor for H seen as C^2
171 explicit quaternion( ::std::complex<T> const & z0,
172 ::std::complex<T> const & z1 = ::std::complex<T>())
182 // UNtemplated copy constructor
183 // (this is taken care of by the compiler itself)
186 // templated copy constructor
189 explicit quaternion(quaternion<X> const & a_recopier)
190 : a(static_cast<T>(a_recopier.R_component_1())),
191 b(static_cast<T>(a_recopier.R_component_2())),
192 c(static_cast<T>(a_recopier.R_component_3())),
193 d(static_cast<T>(a_recopier.R_component_4()))
200 // (this is taken care of by the compiler itself)
205 // Note: Like complex number, quaternions do have a meaningful notion of "real part",
206 // but unlike them there is no meaningful notion of "imaginary part".
207 // Instead there is an "unreal part" which itself is a quaternion, and usually
208 // nothing simpler (as opposed to the complex number case).
209 // However, for practicallity, there are accessors for the other components
210 // (these are necessary for the templated copy constructor, for instance).
212 BOOST_QUATERNION_ACCESSOR_GENERATOR(T)
214 // assignment operators
216 BOOST_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(T)
218 // other assignment-related operators
220 // NOTE: Quaternion multiplication is *NOT* commutative;
221 // symbolically, "q *= rhs;" means "q = q * rhs;"
222 // and "q /= rhs;" means "q = q * inverse_of(rhs);"
224 quaternion<T> & operator += (T const & rhs)
226 T at = a + rhs; // exception guard
234 quaternion<T> & operator += (::std::complex<T> const & rhs)
236 T at = a + rhs.real(); // exception guard
237 T bt = b + rhs.imag(); // exception guard
247 quaternion<T> & operator += (quaternion<X> const & rhs)
249 T at = a + static_cast<T>(rhs.R_component_1()); // exception guard
250 T bt = b + static_cast<T>(rhs.R_component_2()); // exception guard
251 T ct = c + static_cast<T>(rhs.R_component_3()); // exception guard
252 T dt = d + static_cast<T>(rhs.R_component_4()); // exception guard
264 quaternion<T> & operator -= (T const & rhs)
266 T at = a - rhs; // exception guard
274 quaternion<T> & operator -= (::std::complex<T> const & rhs)
276 T at = a - rhs.real(); // exception guard
277 T bt = b - rhs.imag(); // exception guard
287 quaternion<T> & operator -= (quaternion<X> const & rhs)
289 T at = a - static_cast<T>(rhs.R_component_1()); // exception guard
290 T bt = b - static_cast<T>(rhs.R_component_2()); // exception guard
291 T ct = c - static_cast<T>(rhs.R_component_3()); // exception guard
292 T dt = d - static_cast<T>(rhs.R_component_4()); // exception guard
303 quaternion<T> & operator *= (T const & rhs)
305 T at = a * rhs; // exception guard
306 T bt = b * rhs; // exception guard
307 T ct = c * rhs; // exception guard
308 T dt = d * rhs; // exception guard
319 quaternion<T> & operator *= (::std::complex<T> const & rhs)
339 quaternion<T> & operator *= (quaternion<X> const & rhs)
341 T ar = static_cast<T>(rhs.R_component_1());
342 T br = static_cast<T>(rhs.R_component_2());
343 T cr = static_cast<T>(rhs.R_component_3());
344 T dr = static_cast<T>(rhs.R_component_4());
346 T at = +a*ar-b*br-c*cr-d*dr;
347 T bt = +a*br+b*ar+c*dr-d*cr; //(a*br+ar*b)+(c*dr-cr*d);
348 T ct = +a*cr-b*dr+c*ar+d*br; //(a*cr+ar*c)+(d*br-dr*b);
349 T dt = +a*dr+b*cr-c*br+d*ar; //(a*dr+ar*d)+(b*cr-br*c);
361 quaternion<T> & operator /= (T const & rhs)
363 T at = a / rhs; // exception guard
364 T bt = b / rhs; // exception guard
365 T ct = c / rhs; // exception guard
366 T dt = d / rhs; // exception guard
377 quaternion<T> & operator /= (::std::complex<T> const & rhs)
382 T denominator = ar*ar+br*br;
384 T at = (+a*ar+b*br)/denominator; //(a*ar+b*br)/denominator;
385 T bt = (-a*br+b*ar)/denominator; //(ar*b-a*br)/denominator;
386 T ct = (+c*ar-d*br)/denominator; //(ar*c-d*br)/denominator;
387 T dt = (+c*br+d*ar)/denominator; //(ar*d+br*c)/denominator;
399 quaternion<T> & operator /= (quaternion<X> const & rhs)
401 T ar = static_cast<T>(rhs.R_component_1());
402 T br = static_cast<T>(rhs.R_component_2());
403 T cr = static_cast<T>(rhs.R_component_3());
404 T dr = static_cast<T>(rhs.R_component_4());
406 T denominator = ar*ar+br*br+cr*cr+dr*dr;
408 T at = (+a*ar+b*br+c*cr+d*dr)/denominator; //(a*ar+b*br+c*cr+d*dr)/denominator;
409 T bt = (-a*br+b*ar-c*dr+d*cr)/denominator; //((ar*b-a*br)+(cr*d-c*dr))/denominator;
410 T ct = (-a*cr+b*dr+c*ar-d*br)/denominator; //((ar*c-a*cr)+(dr*b-d*br))/denominator;
411 T dt = (-a*dr-b*cr+c*br+d*ar)/denominator; //((ar*d-a*dr)+(br*c-b*cr))/denominator;
424 BOOST_QUATERNION_MEMBER_DATA_GENERATOR(T)
432 // declaration of quaternion specialization
434 template<> class quaternion<float>;
435 template<> class quaternion<double>;
436 template<> class quaternion<long double>;
439 // helper templates for converting copy constructors (declaration)
444 template< typename T,
447 quaternion<T> quaternion_type_converter(quaternion<U> const & rhs);
451 // implementation of quaternion specialization
454 #define BOOST_QUATERNION_CONSTRUCTOR_GENERATOR(type) \
455 explicit quaternion( type const & requested_a = static_cast<type>(0), \
456 type const & requested_b = static_cast<type>(0), \
457 type const & requested_c = static_cast<type>(0), \
458 type const & requested_d = static_cast<type>(0)) \
466 explicit quaternion( ::std::complex<type> const & z0, \
467 ::std::complex<type> const & z1 = ::std::complex<type>()) \
476 #define BOOST_QUATERNION_MEMBER_ADD_GENERATOR_1(type) \
477 quaternion<type> & operator += (type const & rhs) \
484 #define BOOST_QUATERNION_MEMBER_ADD_GENERATOR_2(type) \
485 quaternion<type> & operator += (::std::complex<type> const & rhs) \
493 #define BOOST_QUATERNION_MEMBER_ADD_GENERATOR_3(type) \
494 template<typename X> \
495 quaternion<type> & operator += (quaternion<X> const & rhs) \
497 a += static_cast<type>(rhs.R_component_1()); \
498 b += static_cast<type>(rhs.R_component_2()); \
499 c += static_cast<type>(rhs.R_component_3()); \
500 d += static_cast<type>(rhs.R_component_4()); \
505 #define BOOST_QUATERNION_MEMBER_SUB_GENERATOR_1(type) \
506 quaternion<type> & operator -= (type const & rhs) \
513 #define BOOST_QUATERNION_MEMBER_SUB_GENERATOR_2(type) \
514 quaternion<type> & operator -= (::std::complex<type> const & rhs) \
522 #define BOOST_QUATERNION_MEMBER_SUB_GENERATOR_3(type) \
523 template<typename X> \
524 quaternion<type> & operator -= (quaternion<X> const & rhs) \
526 a -= static_cast<type>(rhs.R_component_1()); \
527 b -= static_cast<type>(rhs.R_component_2()); \
528 c -= static_cast<type>(rhs.R_component_3()); \
529 d -= static_cast<type>(rhs.R_component_4()); \
534 #define BOOST_QUATERNION_MEMBER_MUL_GENERATOR_1(type) \
535 quaternion<type> & operator *= (type const & rhs) \
545 #define BOOST_QUATERNION_MEMBER_MUL_GENERATOR_2(type) \
546 quaternion<type> & operator *= (::std::complex<type> const & rhs) \
548 type ar = rhs.real(); \
549 type br = rhs.imag(); \
551 type at = +a*ar-b*br; \
552 type bt = +a*br+b*ar; \
553 type ct = +c*ar+d*br; \
554 type dt = -c*br+d*ar; \
564 #define BOOST_QUATERNION_MEMBER_MUL_GENERATOR_3(type) \
565 template<typename X> \
566 quaternion<type> & operator *= (quaternion<X> const & rhs) \
568 type ar = static_cast<type>(rhs.R_component_1()); \
569 type br = static_cast<type>(rhs.R_component_2()); \
570 type cr = static_cast<type>(rhs.R_component_3()); \
571 type dr = static_cast<type>(rhs.R_component_4()); \
573 type at = +a*ar-b*br-c*cr-d*dr; \
574 type bt = +a*br+b*ar+c*dr-d*cr; \
575 type ct = +a*cr-b*dr+c*ar+d*br; \
576 type dt = +a*dr+b*cr-c*br+d*ar; \
586 // There is quite a lot of repetition in the code below. This is intentional.
587 // The last conditional block is the normal form, and the others merely
588 // consist of workarounds for various compiler deficiencies. Hopefuly, when
589 // more compilers are conformant and we can retire support for those that are
590 // not, we will be able to remove the clutter. This is makes the situation
591 // (painfully) explicit.
593 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR_1(type) \
594 quaternion<type> & operator /= (type const & rhs) \
604 #if defined(__GNUC__) && (__GNUC__ < 3)
605 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR_2(type) \
606 quaternion<type> & operator /= (::std::complex<type> const & rhs) \
608 using ::std::valarray; \
610 valarray<type> tr(2); \
612 tr[0] = rhs.real(); \
613 tr[1] = rhs.imag(); \
615 type mixam = (BOOST_GET_VALARRAY(type,static_cast<type>(1)/abs(tr)).max)(); \
619 valarray<type> tt(4); \
621 tt[0] = +a*tr[0]+b*tr[1]; \
622 tt[1] = -a*tr[1]+b*tr[0]; \
623 tt[2] = +c*tr[0]-d*tr[1]; \
624 tt[3] = +c*tr[1]+d*tr[0]; \
628 tt *= (mixam/tr.sum()); \
637 #elif defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
638 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR_2(type) \
639 quaternion<type> & operator /= (::std::complex<type> const & rhs) \
641 using ::std::valarray; \
644 valarray<type> tr(2); \
646 tr[0] = rhs.real(); \
647 tr[1] = rhs.imag(); \
649 type mixam = static_cast<type>(1)/(abs(tr).max)(); \
653 valarray<type> tt(4); \
655 tt[0] = +a*tr[0]+b*tr[1]; \
656 tt[1] = -a*tr[1]+b*tr[0]; \
657 tt[2] = +c*tr[0]-d*tr[1]; \
658 tt[3] = +c*tr[1]+d*tr[0]; \
662 tt *= (mixam/tr.sum()); \
672 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR_2(type) \
673 quaternion<type> & operator /= (::std::complex<type> const & rhs) \
675 using ::std::valarray; \
677 valarray<type> tr(2); \
679 tr[0] = rhs.real(); \
680 tr[1] = rhs.imag(); \
682 type mixam = static_cast<type>(1)/(abs(tr).max)(); \
686 valarray<type> tt(4); \
688 tt[0] = +a*tr[0]+b*tr[1]; \
689 tt[1] = -a*tr[1]+b*tr[0]; \
690 tt[2] = +c*tr[0]-d*tr[1]; \
691 tt[3] = +c*tr[1]+d*tr[0]; \
695 tt *= (mixam/tr.sum()); \
704 #endif /* defined(__GNUC__) && (__GNUC__ < 3) */ /* BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP */
706 #if defined(__GNUC__) && (__GNUC__ < 3)
707 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR_3(type) \
708 template<typename X> \
709 quaternion<type> & operator /= (quaternion<X> const & rhs) \
711 using ::std::valarray; \
713 valarray<type> tr(4); \
715 tr[0] = static_cast<type>(rhs.R_component_1()); \
716 tr[1] = static_cast<type>(rhs.R_component_2()); \
717 tr[2] = static_cast<type>(rhs.R_component_3()); \
718 tr[3] = static_cast<type>(rhs.R_component_4()); \
720 type mixam = (BOOST_GET_VALARRAY(type,static_cast<type>(1)/abs(tr)).max)(); \
724 valarray<type> tt(4); \
726 tt[0] = +a*tr[0]+b*tr[1]+c*tr[2]+d*tr[3]; \
727 tt[1] = -a*tr[1]+b*tr[0]-c*tr[3]+d*tr[2]; \
728 tt[2] = -a*tr[2]+b*tr[3]+c*tr[0]-d*tr[1]; \
729 tt[3] = -a*tr[3]-b*tr[2]+c*tr[1]+d*tr[0]; \
733 tt *= (mixam/tr.sum()); \
742 #elif defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
743 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR_3(type) \
744 template<typename X> \
745 quaternion<type> & operator /= (quaternion<X> const & rhs) \
747 using ::std::valarray; \
750 valarray<type> tr(4); \
752 tr[0] = static_cast<type>(rhs.R_component_1()); \
753 tr[1] = static_cast<type>(rhs.R_component_2()); \
754 tr[2] = static_cast<type>(rhs.R_component_3()); \
755 tr[3] = static_cast<type>(rhs.R_component_4()); \
757 type mixam = static_cast<type>(1)/(abs(tr).max)(); \
761 valarray<type> tt(4); \
763 tt[0] = +a*tr[0]+b*tr[1]+c*tr[2]+d*tr[3]; \
764 tt[1] = -a*tr[1]+b*tr[0]-c*tr[3]+d*tr[2]; \
765 tt[2] = -a*tr[2]+b*tr[3]+c*tr[0]-d*tr[1]; \
766 tt[3] = -a*tr[3]-b*tr[2]+c*tr[1]+d*tr[0]; \
770 tt *= (mixam/tr.sum()); \
780 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR_3(type) \
781 template<typename X> \
782 quaternion<type> & operator /= (quaternion<X> const & rhs) \
784 using ::std::valarray; \
786 valarray<type> tr(4); \
788 tr[0] = static_cast<type>(rhs.R_component_1()); \
789 tr[1] = static_cast<type>(rhs.R_component_2()); \
790 tr[2] = static_cast<type>(rhs.R_component_3()); \
791 tr[3] = static_cast<type>(rhs.R_component_4()); \
793 type mixam = static_cast<type>(1)/(abs(tr).max)(); \
797 valarray<type> tt(4); \
799 tt[0] = +a*tr[0]+b*tr[1]+c*tr[2]+d*tr[3]; \
800 tt[1] = -a*tr[1]+b*tr[0]-c*tr[3]+d*tr[2]; \
801 tt[2] = -a*tr[2]+b*tr[3]+c*tr[0]-d*tr[1]; \
802 tt[3] = -a*tr[3]-b*tr[2]+c*tr[1]+d*tr[0]; \
806 tt *= (mixam/tr.sum()); \
815 #endif /* defined(__GNUC__) && (__GNUC__ < 3) */ /* BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP */
817 #define BOOST_QUATERNION_MEMBER_ADD_GENERATOR(type) \
818 BOOST_QUATERNION_MEMBER_ADD_GENERATOR_1(type) \
819 BOOST_QUATERNION_MEMBER_ADD_GENERATOR_2(type) \
820 BOOST_QUATERNION_MEMBER_ADD_GENERATOR_3(type)
822 #define BOOST_QUATERNION_MEMBER_SUB_GENERATOR(type) \
823 BOOST_QUATERNION_MEMBER_SUB_GENERATOR_1(type) \
824 BOOST_QUATERNION_MEMBER_SUB_GENERATOR_2(type) \
825 BOOST_QUATERNION_MEMBER_SUB_GENERATOR_3(type)
827 #define BOOST_QUATERNION_MEMBER_MUL_GENERATOR(type) \
828 BOOST_QUATERNION_MEMBER_MUL_GENERATOR_1(type) \
829 BOOST_QUATERNION_MEMBER_MUL_GENERATOR_2(type) \
830 BOOST_QUATERNION_MEMBER_MUL_GENERATOR_3(type)
832 #define BOOST_QUATERNION_MEMBER_DIV_GENERATOR(type) \
833 BOOST_QUATERNION_MEMBER_DIV_GENERATOR_1(type) \
834 BOOST_QUATERNION_MEMBER_DIV_GENERATOR_2(type) \
835 BOOST_QUATERNION_MEMBER_DIV_GENERATOR_3(type)
837 #define BOOST_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(type) \
838 BOOST_QUATERNION_MEMBER_ADD_GENERATOR(type) \
839 BOOST_QUATERNION_MEMBER_SUB_GENERATOR(type) \
840 BOOST_QUATERNION_MEMBER_MUL_GENERATOR(type) \
841 BOOST_QUATERNION_MEMBER_DIV_GENERATOR(type)
845 class quaternion<float>
849 typedef float value_type;
851 BOOST_QUATERNION_CONSTRUCTOR_GENERATOR(float)
853 // UNtemplated copy constructor
854 // (this is taken care of by the compiler itself)
856 // explicit copy constructors (precision-loosing converters)
858 explicit quaternion(quaternion<double> const & a_recopier)
860 *this = detail::quaternion_type_converter<float, double>(a_recopier);
863 explicit quaternion(quaternion<long double> const & a_recopier)
865 *this = detail::quaternion_type_converter<float, long double>(a_recopier);
869 // (this is taken care of by the compiler itself)
873 // Note: Like complex number, quaternions do have a meaningful notion of "real part",
874 // but unlike them there is no meaningful notion of "imaginary part".
875 // Instead there is an "unreal part" which itself is a quaternion, and usually
876 // nothing simpler (as opposed to the complex number case).
877 // However, for practicallity, there are accessors for the other components
878 // (these are necessary for the templated copy constructor, for instance).
880 BOOST_QUATERNION_ACCESSOR_GENERATOR(float)
882 // assignment operators
884 BOOST_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(float)
886 // other assignment-related operators
888 // NOTE: Quaternion multiplication is *NOT* commutative;
889 // symbolically, "q *= rhs;" means "q = q * rhs;"
890 // and "q /= rhs;" means "q = q * inverse_of(rhs);"
892 BOOST_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(float)
897 BOOST_QUATERNION_MEMBER_DATA_GENERATOR(float)
906 class quaternion<double>
910 typedef double value_type;
912 BOOST_QUATERNION_CONSTRUCTOR_GENERATOR(double)
914 // UNtemplated copy constructor
915 // (this is taken care of by the compiler itself)
917 // converting copy constructor
919 explicit quaternion(quaternion<float> const & a_recopier)
921 *this = detail::quaternion_type_converter<double, float>(a_recopier);
924 // explicit copy constructors (precision-loosing converters)
926 explicit quaternion(quaternion<long double> const & a_recopier)
928 *this = detail::quaternion_type_converter<double, long double>(a_recopier);
932 // (this is taken care of by the compiler itself)
936 // Note: Like complex number, quaternions do have a meaningful notion of "real part",
937 // but unlike them there is no meaningful notion of "imaginary part".
938 // Instead there is an "unreal part" which itself is a quaternion, and usually
939 // nothing simpler (as opposed to the complex number case).
940 // However, for practicallity, there are accessors for the other components
941 // (these are necessary for the templated copy constructor, for instance).
943 BOOST_QUATERNION_ACCESSOR_GENERATOR(double)
945 // assignment operators
947 BOOST_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(double)
949 // other assignment-related operators
951 // NOTE: Quaternion multiplication is *NOT* commutative;
952 // symbolically, "q *= rhs;" means "q = q * rhs;"
953 // and "q /= rhs;" means "q = q * inverse_of(rhs);"
955 BOOST_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(double)
960 BOOST_QUATERNION_MEMBER_DATA_GENERATOR(double)
969 class quaternion<long double>
973 typedef long double value_type;
975 BOOST_QUATERNION_CONSTRUCTOR_GENERATOR(long double)
977 // UNtemplated copy constructor
978 // (this is taken care of by the compiler itself)
980 // converting copy constructors
982 explicit quaternion(quaternion<float> const & a_recopier)
984 *this = detail::quaternion_type_converter<long double, float>(a_recopier);
987 explicit quaternion(quaternion<double> const & a_recopier)
989 *this = detail::quaternion_type_converter<long double, double>(a_recopier);
993 // (this is taken care of by the compiler itself)
997 // Note: Like complex number, quaternions do have a meaningful notion of "real part",
998 // but unlike them there is no meaningful notion of "imaginary part".
999 // Instead there is an "unreal part" which itself is a quaternion, and usually
1000 // nothing simpler (as opposed to the complex number case).
1001 // However, for practicallity, there are accessors for the other components
1002 // (these are necessary for the templated copy constructor, for instance).
1004 BOOST_QUATERNION_ACCESSOR_GENERATOR(long double)
1006 // assignment operators
1008 BOOST_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR(long double)
1010 // other assignment-related operators
1012 // NOTE: Quaternion multiplication is *NOT* commutative;
1013 // symbolically, "q *= rhs;" means "q = q * rhs;"
1014 // and "q /= rhs;" means "q = q * inverse_of(rhs);"
1016 BOOST_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR(long double)
1021 BOOST_QUATERNION_MEMBER_DATA_GENERATOR(long double)
1029 #undef BOOST_QUATERNION_MEMBER_ALGEBRAIC_GENERATOR
1030 #undef BOOST_QUATERNION_MEMBER_ADD_GENERATOR
1031 #undef BOOST_QUATERNION_MEMBER_SUB_GENERATOR
1032 #undef BOOST_QUATERNION_MEMBER_MUL_GENERATOR
1033 #undef BOOST_QUATERNION_MEMBER_DIV_GENERATOR
1034 #undef BOOST_QUATERNION_MEMBER_ADD_GENERATOR_1
1035 #undef BOOST_QUATERNION_MEMBER_ADD_GENERATOR_2
1036 #undef BOOST_QUATERNION_MEMBER_ADD_GENERATOR_3
1037 #undef BOOST_QUATERNION_MEMBER_SUB_GENERATOR_1
1038 #undef BOOST_QUATERNION_MEMBER_SUB_GENERATOR_2
1039 #undef BOOST_QUATERNION_MEMBER_SUB_GENERATOR_3
1040 #undef BOOST_QUATERNION_MEMBER_MUL_GENERATOR_1
1041 #undef BOOST_QUATERNION_MEMBER_MUL_GENERATOR_2
1042 #undef BOOST_QUATERNION_MEMBER_MUL_GENERATOR_3
1043 #undef BOOST_QUATERNION_MEMBER_DIV_GENERATOR_1
1044 #undef BOOST_QUATERNION_MEMBER_DIV_GENERATOR_2
1045 #undef BOOST_QUATERNION_MEMBER_DIV_GENERATOR_3
1047 #undef BOOST_QUATERNION_CONSTRUCTOR_GENERATOR
1050 #undef BOOST_QUATERNION_MEMBER_ASSIGNMENT_GENERATOR
1052 #undef BOOST_QUATERNION_MEMBER_DATA_GENERATOR
1054 #undef BOOST_QUATERNION_ACCESSOR_GENERATOR
1059 #define BOOST_QUATERNION_OPERATOR_GENERATOR_BODY(op) \
1061 quaternion<T> res(lhs); \
1066 #define BOOST_QUATERNION_OPERATOR_GENERATOR_1_L(op) \
1067 template<typename T> \
1068 inline quaternion<T> operator op (T const & lhs, quaternion<T> const & rhs) \
1069 BOOST_QUATERNION_OPERATOR_GENERATOR_BODY(op)
1071 #define BOOST_QUATERNION_OPERATOR_GENERATOR_1_R(op) \
1072 template<typename T> \
1073 inline quaternion<T> operator op (quaternion<T> const & lhs, T const & rhs) \
1074 BOOST_QUATERNION_OPERATOR_GENERATOR_BODY(op)
1076 #define BOOST_QUATERNION_OPERATOR_GENERATOR_2_L(op) \
1077 template<typename T> \
1078 inline quaternion<T> operator op (::std::complex<T> const & lhs, quaternion<T> const & rhs) \
1079 BOOST_QUATERNION_OPERATOR_GENERATOR_BODY(op)
1081 #define BOOST_QUATERNION_OPERATOR_GENERATOR_2_R(op) \
1082 template<typename T> \
1083 inline quaternion<T> operator op (quaternion<T> const & lhs, ::std::complex<T> const & rhs) \
1084 BOOST_QUATERNION_OPERATOR_GENERATOR_BODY(op)
1086 #define BOOST_QUATERNION_OPERATOR_GENERATOR_3(op) \
1087 template<typename T> \
1088 inline quaternion<T> operator op (quaternion<T> const & lhs, quaternion<T> const & rhs) \
1089 BOOST_QUATERNION_OPERATOR_GENERATOR_BODY(op)
1091 #define BOOST_QUATERNION_OPERATOR_GENERATOR(op) \
1092 BOOST_QUATERNION_OPERATOR_GENERATOR_1_L(op) \
1093 BOOST_QUATERNION_OPERATOR_GENERATOR_1_R(op) \
1094 BOOST_QUATERNION_OPERATOR_GENERATOR_2_L(op) \
1095 BOOST_QUATERNION_OPERATOR_GENERATOR_2_R(op) \
1096 BOOST_QUATERNION_OPERATOR_GENERATOR_3(op)
1099 BOOST_QUATERNION_OPERATOR_GENERATOR(+)
1100 BOOST_QUATERNION_OPERATOR_GENERATOR(-)
1101 BOOST_QUATERNION_OPERATOR_GENERATOR(*)
1102 BOOST_QUATERNION_OPERATOR_GENERATOR(/)
1105 #undef BOOST_QUATERNION_OPERATOR_GENERATOR
1107 #undef BOOST_QUATERNION_OPERATOR_GENERATOR_1_L
1108 #undef BOOST_QUATERNION_OPERATOR_GENERATOR_1_R
1109 #undef BOOST_QUATERNION_OPERATOR_GENERATOR_2_L
1110 #undef BOOST_QUATERNION_OPERATOR_GENERATOR_2_R
1111 #undef BOOST_QUATERNION_OPERATOR_GENERATOR_3
1113 #undef BOOST_QUATERNION_OPERATOR_GENERATOR_BODY
1116 template<typename T>
1117 inline quaternion<T> operator + (quaternion<T> const & q)
1123 template<typename T>
1124 inline quaternion<T> operator - (quaternion<T> const & q)
1126 return(quaternion<T>(-q.R_component_1(),-q.R_component_2(),-q.R_component_3(),-q.R_component_4()));
1130 template<typename T>
1131 inline bool operator == (T const & lhs, quaternion<T> const & rhs)
1134 (rhs.R_component_1() == lhs)&&
1135 (rhs.R_component_2() == static_cast<T>(0))&&
1136 (rhs.R_component_3() == static_cast<T>(0))&&
1137 (rhs.R_component_4() == static_cast<T>(0))
1142 template<typename T>
1143 inline bool operator == (quaternion<T> const & lhs, T const & rhs)
1146 (lhs.R_component_1() == rhs)&&
1147 (lhs.R_component_2() == static_cast<T>(0))&&
1148 (lhs.R_component_3() == static_cast<T>(0))&&
1149 (lhs.R_component_4() == static_cast<T>(0))
1154 template<typename T>
1155 inline bool operator == (::std::complex<T> const & lhs, quaternion<T> const & rhs)
1158 (rhs.R_component_1() == lhs.real())&&
1159 (rhs.R_component_2() == lhs.imag())&&
1160 (rhs.R_component_3() == static_cast<T>(0))&&
1161 (rhs.R_component_4() == static_cast<T>(0))
1166 template<typename T>
1167 inline bool operator == (quaternion<T> const & lhs, ::std::complex<T> const & rhs)
1170 (lhs.R_component_1() == rhs.real())&&
1171 (lhs.R_component_2() == rhs.imag())&&
1172 (lhs.R_component_3() == static_cast<T>(0))&&
1173 (lhs.R_component_4() == static_cast<T>(0))
1178 template<typename T>
1179 inline bool operator == (quaternion<T> const & lhs, quaternion<T> const & rhs)
1182 (rhs.R_component_1() == lhs.R_component_1())&&
1183 (rhs.R_component_2() == lhs.R_component_2())&&
1184 (rhs.R_component_3() == lhs.R_component_3())&&
1185 (rhs.R_component_4() == lhs.R_component_4())
1190 #define BOOST_QUATERNION_NOT_EQUAL_GENERATOR \
1192 return(!(lhs == rhs)); \
1195 template<typename T>
1196 inline bool operator != (T const & lhs, quaternion<T> const & rhs)
1197 BOOST_QUATERNION_NOT_EQUAL_GENERATOR
1199 template<typename T>
1200 inline bool operator != (quaternion<T> const & lhs, T const & rhs)
1201 BOOST_QUATERNION_NOT_EQUAL_GENERATOR
1203 template<typename T>
1204 inline bool operator != (::std::complex<T> const & lhs, quaternion<T> const & rhs)
1205 BOOST_QUATERNION_NOT_EQUAL_GENERATOR
1207 template<typename T>
1208 inline bool operator != (quaternion<T> const & lhs, ::std::complex<T> const & rhs)
1209 BOOST_QUATERNION_NOT_EQUAL_GENERATOR
1211 template<typename T>
1212 inline bool operator != (quaternion<T> const & lhs, quaternion<T> const & rhs)
1213 BOOST_QUATERNION_NOT_EQUAL_GENERATOR
1215 #undef BOOST_QUATERNION_NOT_EQUAL_GENERATOR
1218 // Note: we allow the following formats, whith a, b, c, and d reals
1220 // (a), (a,b), (a,b,c), (a,b,c,d)
1221 // (a,(c)), (a,(c,d)), ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b),(c,d))
1222 #if BOOST_WORKAROUND(__GNUC__, < 3)
1223 template<typename T>
1224 std::istream & operator >> ( ::std::istream & is,
1227 template<typename T, typename charT, class traits>
1228 ::std::basic_istream<charT,traits> & operator >> ( ::std::basic_istream<charT,traits> & is,
1230 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1232 #if BOOST_WORKAROUND(__GNUC__, < 3)
1234 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1236 #ifdef BOOST_NO_STD_LOCALE
1238 const ::std::ctype<charT> & ct = ::std::use_facet< ::std::ctype<charT> >(is.getloc());
1239 #endif /* BOOST_NO_STD_LOCALE */
1246 ::std::complex<T> u = ::std::complex<T>();
1247 ::std::complex<T> v = ::std::complex<T>();
1252 is >> ch; // get the first lexeme
1254 if (!is.good()) goto finish;
1256 #ifdef BOOST_NO_STD_LOCALE
1259 cc = ct.narrow(ch, char());
1260 #endif /* BOOST_NO_STD_LOCALE */
1262 if (cc == '(') // read "(", possible: (a), (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d)), ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
1264 is >> ch; // get the second lexeme
1266 if (!is.good()) goto finish;
1268 #ifdef BOOST_NO_STD_LOCALE
1271 cc = ct.narrow(ch, char());
1272 #endif /* BOOST_NO_STD_LOCALE */
1274 if (cc == '(') // read "((", possible: ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
1278 is >> u; // we extract the first and second components
1282 if (!is.good()) goto finish;
1284 is >> ch; // get the next lexeme
1286 if (!is.good()) goto finish;
1288 #ifdef BOOST_NO_STD_LOCALE
1291 cc = ct.narrow(ch, char());
1292 #endif /* BOOST_NO_STD_LOCALE */
1294 if (cc == ')') // format: ((a)) or ((a,b))
1296 q = quaternion<T>(a,b);
1298 else if (cc == ',') // read "((a)," or "((a,b),", possible: ((a),c), ((a),(c)), ((a),(c,d)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
1300 is >> v; // we extract the third and fourth components
1304 if (!is.good()) goto finish;
1306 is >> ch; // get the last lexeme
1308 if (!is.good()) goto finish;
1310 #ifdef BOOST_NO_STD_LOCALE
1313 cc = ct.narrow(ch, char());
1314 #endif /* BOOST_NO_STD_LOCALE */
1316 if (cc == ')') // format: ((a),c), ((a),(c)), ((a),(c,d)), ((a,b),c), ((a,b),(c)) or ((a,b,),(c,d,))
1318 q = quaternion<T>(a,b,c,d);
1322 #if BOOST_WORKAROUND(__GNUC__, < 3)
1323 is.setstate(::std::ios::failbit);
1325 is.setstate(::std::ios_base::failbit);
1326 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1331 #if BOOST_WORKAROUND(__GNUC__, < 3)
1332 is.setstate(::std::ios::failbit);
1334 is.setstate(::std::ios_base::failbit);
1335 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1338 else // read "(a", possible: (a), (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
1342 is >> a; // we extract the first component
1344 if (!is.good()) goto finish;
1346 is >> ch; // get the third lexeme
1348 if (!is.good()) goto finish;
1350 #ifdef BOOST_NO_STD_LOCALE
1353 cc = ct.narrow(ch, char());
1354 #endif /* BOOST_NO_STD_LOCALE */
1356 if (cc == ')') // format: (a)
1358 q = quaternion<T>(a);
1360 else if (cc == ',') // read "(a,", possible: (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
1362 is >> ch; // get the fourth lexeme
1364 if (!is.good()) goto finish;
1366 #ifdef BOOST_NO_STD_LOCALE
1369 cc = ct.narrow(ch, char());
1370 #endif /* BOOST_NO_STD_LOCALE */
1372 if (cc == '(') // read "(a,(", possible: (a,(c)), (a,(c,d))
1376 is >> v; // we extract the third and fourth component
1381 if (!is.good()) goto finish;
1383 is >> ch; // get the ninth lexeme
1385 if (!is.good()) goto finish;
1387 #ifdef BOOST_NO_STD_LOCALE
1390 cc = ct.narrow(ch, char());
1391 #endif /* BOOST_NO_STD_LOCALE */
1393 if (cc == ')') // format: (a,(c)) or (a,(c,d))
1395 q = quaternion<T>(a,b,c,d);
1399 #if BOOST_WORKAROUND(__GNUC__, < 3)
1400 is.setstate(::std::ios::failbit);
1402 is.setstate(::std::ios_base::failbit);
1403 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1406 else // read "(a,b", possible: (a,b), (a,b,c), (a,b,c,d)
1410 is >> b; // we extract the second component
1412 if (!is.good()) goto finish;
1414 is >> ch; // get the fifth lexeme
1416 if (!is.good()) goto finish;
1418 #ifdef BOOST_NO_STD_LOCALE
1421 cc = ct.narrow(ch, char());
1422 #endif /* BOOST_NO_STD_LOCALE */
1424 if (cc == ')') // format: (a,b)
1426 q = quaternion<T>(a,b);
1428 else if (cc == ',') // read "(a,b,", possible: (a,b,c), (a,b,c,d)
1430 is >> c; // we extract the third component
1432 if (!is.good()) goto finish;
1434 is >> ch; // get the seventh lexeme
1436 if (!is.good()) goto finish;
1438 #ifdef BOOST_NO_STD_LOCALE
1441 cc = ct.narrow(ch, char());
1442 #endif /* BOOST_NO_STD_LOCALE */
1444 if (cc == ')') // format: (a,b,c)
1446 q = quaternion<T>(a,b,c);
1448 else if (cc == ',') // read "(a,b,c,", possible: (a,b,c,d)
1450 is >> d; // we extract the fourth component
1452 if (!is.good()) goto finish;
1454 is >> ch; // get the ninth lexeme
1456 if (!is.good()) goto finish;
1458 #ifdef BOOST_NO_STD_LOCALE
1461 cc = ct.narrow(ch, char());
1462 #endif /* BOOST_NO_STD_LOCALE */
1464 if (cc == ')') // format: (a,b,c,d)
1466 q = quaternion<T>(a,b,c,d);
1470 #if BOOST_WORKAROUND(__GNUC__, < 3)
1471 is.setstate(::std::ios::failbit);
1473 is.setstate(::std::ios_base::failbit);
1474 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1479 #if BOOST_WORKAROUND(__GNUC__, < 3)
1480 is.setstate(::std::ios::failbit);
1482 is.setstate(::std::ios_base::failbit);
1483 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1488 #if BOOST_WORKAROUND(__GNUC__, < 3)
1489 is.setstate(::std::ios::failbit);
1491 is.setstate(::std::ios_base::failbit);
1492 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1498 #if BOOST_WORKAROUND(__GNUC__, < 3)
1499 is.setstate(::std::ios::failbit);
1501 is.setstate(::std::ios_base::failbit);
1502 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1510 is >> a; // we extract the first component
1512 if (!is.good()) goto finish;
1514 q = quaternion<T>(a);
1522 #if BOOST_WORKAROUND(__GNUC__, < 3)
1523 template<typename T>
1524 ::std::ostream & operator << ( ::std::ostream & os,
1525 quaternion<T> const & q)
1527 template<typename T, typename charT, class traits>
1528 ::std::basic_ostream<charT,traits> & operator << ( ::std::basic_ostream<charT,traits> & os,
1529 quaternion<T> const & q)
1530 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1532 #if BOOST_WORKAROUND(__GNUC__, < 3)
1533 ::std::ostringstream s;
1535 ::std::basic_ostringstream<charT,traits> s;
1536 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1538 s.flags(os.flags());
1539 #ifdef BOOST_NO_STD_LOCALE
1541 s.imbue(os.getloc());
1542 #endif /* BOOST_NO_STD_LOCALE */
1543 s.precision(os.precision());
1545 s << '(' << q.R_component_1() << ','
1546 << q.R_component_2() << ','
1547 << q.R_component_3() << ','
1548 << q.R_component_4() << ')';
1550 return os << s.str();
1556 template<typename T>
1557 inline T real(quaternion<T> const & q)
1563 template<typename T>
1564 inline quaternion<T> unreal(quaternion<T> const & q)
1570 #define BOOST_QUATERNION_VALARRAY_LOADER \
1571 using ::std::valarray; \
1573 valarray<T> temp(4); \
1575 temp[0] = q.R_component_1(); \
1576 temp[1] = q.R_component_2(); \
1577 temp[2] = q.R_component_3(); \
1578 temp[3] = q.R_component_4();
1581 template<typename T>
1582 inline T sup(quaternion<T> const & q)
1584 #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
1586 #endif /* BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP */
1588 BOOST_QUATERNION_VALARRAY_LOADER
1590 #if BOOST_WORKAROUND(__GNUC__, < 3)
1591 return((BOOST_GET_VALARRAY(T, abs(temp)).max)());
1593 return((abs(temp).max)());
1594 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1598 template<typename T>
1599 inline T l1(quaternion<T> const & q)
1601 #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
1603 #endif /* BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP */
1605 BOOST_QUATERNION_VALARRAY_LOADER
1607 #if BOOST_WORKAROUND(__GNUC__, < 3)
1608 return(BOOST_GET_VALARRAY(T, abs(temp)).sum());
1610 return(abs(temp).sum());
1611 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1615 template<typename T>
1616 inline T abs(quaternion<T> const & q)
1618 #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
1620 #endif /* BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP */
1624 BOOST_QUATERNION_VALARRAY_LOADER
1626 #if BOOST_WORKAROUND(__GNUC__, < 3)
1627 T maxim = (BOOST_GET_VALARRAY(T, abs(temp)).max)(); // overflow protection
1629 T maxim = (abs(temp).max)(); // overflow protection
1630 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1632 if (maxim == static_cast<T>(0))
1638 T mixam = static_cast<T>(1)/maxim; // prefer multiplications over divisions
1644 return(maxim*sqrt(temp.sum()));
1647 //return(sqrt(norm(q)));
1651 #undef BOOST_QUATERNION_VALARRAY_LOADER
1654 // Note: This is the Cayley norm, not the Euclidian norm...
1656 template<typename T>
1657 inline T norm(quaternion<T>const & q)
1659 return(real(q*conj(q)));
1663 template<typename T>
1664 inline quaternion<T> conj(quaternion<T> const & q)
1666 return(quaternion<T>( +q.R_component_1(),
1669 -q.R_component_4()));
1673 template<typename T>
1674 inline quaternion<T> spherical( T const & rho,
1682 //T a = cos(theta)*cos(phi1)*cos(phi2);
1683 //T b = sin(theta)*cos(phi1)*cos(phi2);
1684 //T c = sin(phi1)*cos(phi2);
1687 T courrant = static_cast<T>(1);
1691 courrant *= cos(phi2);
1693 T c = sin(phi1)*courrant;
1695 courrant *= cos(phi1);
1697 T b = sin(theta)*courrant;
1698 T a = cos(theta)*courrant;
1700 return(rho*quaternion<T>(a,b,c,d));
1704 template<typename T>
1705 inline quaternion<T> semipolar( T const & rho,
1713 T a = cos(alpha)*cos(theta1);
1714 T b = cos(alpha)*sin(theta1);
1715 T c = sin(alpha)*cos(theta2);
1716 T d = sin(alpha)*sin(theta2);
1718 return(rho*quaternion<T>(a,b,c,d));
1722 template<typename T>
1723 inline quaternion<T> multipolar( T const & rho1,
1731 T a = rho1*cos(theta1);
1732 T b = rho1*sin(theta1);
1733 T c = rho2*cos(theta2);
1734 T d = rho2*sin(theta2);
1736 return(quaternion<T>(a,b,c,d));
1740 template<typename T>
1741 inline quaternion<T> cylindrospherical( T const & t,
1743 T const & longitude,
1751 T b = radius*cos(longitude)*cos(latitude);
1752 T c = radius*sin(longitude)*cos(latitude);
1753 T d = radius*sin(latitude);
1755 return(quaternion<T>(t,b,c,d));
1759 template<typename T>
1760 inline quaternion<T> cylindrical(T const & r,
1771 return(quaternion<T>(a,b,h1,h2));
1776 // (please see the documentation)
1779 template<typename T>
1780 inline quaternion<T> exp(quaternion<T> const & q)
1785 using ::boost::math::sinc_pi;
1789 T z = abs(unreal(q));
1793 return(u*quaternion<T>(cos(z),
1794 w*q.R_component_2(), w*q.R_component_3(),
1795 w*q.R_component_4()));
1799 template<typename T>
1800 inline quaternion<T> cos(quaternion<T> const & q)
1806 using ::boost::math::sinhc_pi;
1808 T z = abs(unreal(q));
1810 T w = -sin(q.real())*sinhc_pi(z);
1812 return(quaternion<T>(cos(q.real())*cosh(z),
1813 w*q.R_component_2(), w*q.R_component_3(),
1814 w*q.R_component_4()));
1818 template<typename T>
1819 inline quaternion<T> sin(quaternion<T> const & q)
1825 using ::boost::math::sinhc_pi;
1827 T z = abs(unreal(q));
1829 T w = +cos(q.real())*sinhc_pi(z);
1831 return(quaternion<T>(sin(q.real())*cosh(z),
1832 w*q.R_component_2(), w*q.R_component_3(),
1833 w*q.R_component_4()));
1837 template<typename T>
1838 inline quaternion<T> tan(quaternion<T> const & q)
1840 return(sin(q)/cos(q));
1844 template<typename T>
1845 inline quaternion<T> cosh(quaternion<T> const & q)
1847 return((exp(+q)+exp(-q))/static_cast<T>(2));
1851 template<typename T>
1852 inline quaternion<T> sinh(quaternion<T> const & q)
1854 return((exp(+q)-exp(-q))/static_cast<T>(2));
1858 template<typename T>
1859 inline quaternion<T> tanh(quaternion<T> const & q)
1861 return(sinh(q)/cosh(q));
1865 template<typename T>
1866 quaternion<T> pow(quaternion<T> const & q,
1873 quaternion<T> result = pow(q, m);
1879 result *= q; // n odd
1890 return(quaternion<T>(1));
1894 return(pow(quaternion<T>(1)/q,-n));
1899 // helper templates for converting copy constructors (definition)
1904 template< typename T,
1907 quaternion<T> quaternion_type_converter(quaternion<U> const & rhs)
1909 return(quaternion<T>( static_cast<T>(rhs.R_component_1()),
1910 static_cast<T>(rhs.R_component_2()),
1911 static_cast<T>(rhs.R_component_3()),
1912 static_cast<T>(rhs.R_component_4())));
1919 #if BOOST_WORKAROUND(__GNUC__, < 3)
1920 #undef BOOST_GET_VALARRAY
1921 #endif /* BOOST_WORKAROUND(__GNUC__, < 3) */
1924 #endif /* BOOST_QUATERNION_HPP */