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
13 #include <boost/math_fwd.hpp>
14 #include <boost/math/tools/config.hpp>
15 #include <locale> // for the "<<" operator
18 #include <iosfwd> // for the "<<" and ">>" operators
19 #include <sstream> // for the "<<" operator
21 #include <boost/math/special_functions/sinc.hpp> // for the Sinus cardinal
22 #include <boost/math/special_functions/sinhc.hpp> // for the Hyperbolic Sinus cardinal
23 #include <boost/math/tools/cxx03_warn.hpp>
25 #include <type_traits>
35 struct is_trivial_arithmetic_type_imp
37 typedef std::integral_constant<bool,
38 noexcept(std::declval<T&>() += std::declval<T>())
39 && noexcept(std::declval<T&>() -= std::declval<T>())
40 && noexcept(std::declval<T&>() *= std::declval<T>())
41 && noexcept(std::declval<T&>() /= std::declval<T>())
46 struct is_trivial_arithmetic_type : public is_trivial_arithmetic_type_imp<T>::type {};
49 #ifndef BOOST_NO_CXX14_CONSTEXPR
50 namespace constexpr_detail
53 constexpr void swap(T& a, T& b)
70 // constructor for H seen as R^4
71 // (also default constructor)
73 constexpr explicit quaternion( T const & requested_a = T(),
74 T const & requested_b = T(),
75 T const & requested_c = T(),
76 T const & requested_d = T())
86 // constructor for H seen as C^2
88 constexpr explicit quaternion( ::std::complex<T> const & z0,
89 ::std::complex<T> const & z1 = ::std::complex<T>())
99 // UNtemplated copy constructor
100 constexpr quaternion(quaternion const & a_recopier)
101 : a(a_recopier.R_component_1()),
102 b(a_recopier.R_component_2()),
103 c(a_recopier.R_component_3()),
104 d(a_recopier.R_component_4()) {}
106 constexpr quaternion(quaternion && a_recopier)
107 : a(std::move(a_recopier.R_component_1())),
108 b(std::move(a_recopier.R_component_2())),
109 c(std::move(a_recopier.R_component_3())),
110 d(std::move(a_recopier.R_component_4())) {}
112 // templated copy constructor
115 constexpr explicit quaternion(quaternion<X> const & a_recopier)
116 : a(static_cast<T>(a_recopier.R_component_1())),
117 b(static_cast<T>(a_recopier.R_component_2())),
118 c(static_cast<T>(a_recopier.R_component_3())),
119 d(static_cast<T>(a_recopier.R_component_4()))
126 // (this is taken care of by the compiler itself)
131 // Note: Like complex number, quaternions do have a meaningful notion of "real part",
132 // but unlike them there is no meaningful notion of "imaginary part".
133 // Instead there is an "unreal part" which itself is a quaternion, and usually
134 // nothing simpler (as opposed to the complex number case).
135 // However, for practicality, there are accessors for the other components
136 // (these are necessary for the templated copy constructor, for instance).
138 constexpr T real() const
143 constexpr quaternion<T> unreal() const
145 return(quaternion<T>(static_cast<T>(0), b, c, d));
148 constexpr T R_component_1() const
153 constexpr T R_component_2() const
158 constexpr T R_component_3() const
163 constexpr T R_component_4() const
168 constexpr ::std::complex<T> C_component_1() const
170 return(::std::complex<T>(a, b));
173 constexpr ::std::complex<T> C_component_2() const
175 return(::std::complex<T>(c, d));
178 BOOST_CXX14_CONSTEXPR void swap(quaternion& o)
180 #ifndef BOOST_NO_CXX14_CONSTEXPR
181 using constexpr_detail::swap;
191 // assignment operators
194 BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<X> const & a_affecter)
196 a = static_cast<T>(a_affecter.R_component_1());
197 b = static_cast<T>(a_affecter.R_component_2());
198 c = static_cast<T>(a_affecter.R_component_3());
199 d = static_cast<T>(a_affecter.R_component_4());
204 BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<T> const & a_affecter)
214 BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<T> && a_affecter)
216 a = std::move(a_affecter.a);
217 b = std::move(a_affecter.b);
218 c = std::move(a_affecter.c);
219 d = std::move(a_affecter.d);
224 BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (T const & a_affecter)
228 b = c = d = static_cast<T>(0);
233 BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (::std::complex<T> const & a_affecter)
235 a = a_affecter.real();
236 b = a_affecter.imag();
238 c = d = static_cast<T>(0);
243 // other assignment-related operators
245 // NOTE: Quaternion multiplication is *NOT* commutative;
246 // symbolically, "q *= rhs;" means "q = q * rhs;"
247 // and "q /= rhs;" means "q = q * inverse_of(rhs);"
249 // Note2: Each operator comes in 2 forms - one for the simple case where
250 // type T throws no exceptions, and one exception-safe version
251 // for the case where it might.
253 BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(T const & rhs, const std::true_type&)
258 BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(T const & rhs, const std::false_type&)
260 quaternion<T> result(a + rhs, b, c, d); // exception guard
264 BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(std::complex<T> const & rhs, const std::true_type&)
270 BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(std::complex<T> const & rhs, const std::false_type&)
272 quaternion<T> result(a + std::real(rhs), b + std::imag(rhs), c, d); // exception guard
277 BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(quaternion<X> const & rhs, const std::true_type&)
279 a += rhs.R_component_1();
280 b += rhs.R_component_2();
281 c += rhs.R_component_3();
282 d += rhs.R_component_4();
286 BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(quaternion<X> const & rhs, const std::false_type&)
288 quaternion<T> result(a + rhs.R_component_1(), b + rhs.R_component_2(), c + rhs.R_component_3(), d + rhs.R_component_4()); // exception guard
293 BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(T const & rhs, const std::true_type&)
298 BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(T const & rhs, const std::false_type&)
300 quaternion<T> result(a - rhs, b, c, d); // exception guard
304 BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(std::complex<T> const & rhs, const std::true_type&)
310 BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(std::complex<T> const & rhs, const std::false_type&)
312 quaternion<T> result(a - std::real(rhs), b - std::imag(rhs), c, d); // exception guard
317 BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(quaternion<X> const & rhs, const std::true_type&)
319 a -= rhs.R_component_1();
320 b -= rhs.R_component_2();
321 c -= rhs.R_component_3();
322 d -= rhs.R_component_4();
326 BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(quaternion<X> const & rhs, const std::false_type&)
328 quaternion<T> result(a - rhs.R_component_1(), b - rhs.R_component_2(), c - rhs.R_component_3(), d - rhs.R_component_4()); // exception guard
333 BOOST_CXX14_CONSTEXPR quaternion<T> & do_multiply(T const & rhs, const std::true_type&)
341 BOOST_CXX14_CONSTEXPR quaternion<T> & do_multiply(T const & rhs, const std::false_type&)
343 quaternion<T> result(a * rhs, b * rhs, c * rhs, d * rhs); // exception guard
348 BOOST_CXX14_CONSTEXPR quaternion<T> & do_divide(T const & rhs, const std::true_type&)
356 BOOST_CXX14_CONSTEXPR quaternion<T> & do_divide(T const & rhs, const std::false_type&)
358 quaternion<T> result(a / rhs, b / rhs, c / rhs, d / rhs); // exception guard
364 BOOST_CXX14_CONSTEXPR quaternion<T> & operator += (T const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
365 BOOST_CXX14_CONSTEXPR quaternion<T> & operator += (::std::complex<T> const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
366 template<typename X> BOOST_CXX14_CONSTEXPR quaternion<T> & operator += (quaternion<X> const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
368 BOOST_CXX14_CONSTEXPR quaternion<T> & operator -= (T const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
369 BOOST_CXX14_CONSTEXPR quaternion<T> & operator -= (::std::complex<T> const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
370 template<typename X> BOOST_CXX14_CONSTEXPR quaternion<T> & operator -= (quaternion<X> const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
372 BOOST_CXX14_CONSTEXPR quaternion<T> & operator *= (T const & rhs) { return do_multiply(rhs, detail::is_trivial_arithmetic_type<T>()); }
374 BOOST_CXX14_CONSTEXPR quaternion<T> & operator *= (::std::complex<T> const & rhs)
378 quaternion<T> result(a*ar - b*br, a*br + b*ar, c*ar + d*br, -c*br+d*ar);
384 BOOST_CXX14_CONSTEXPR quaternion<T> & operator *= (quaternion<X> const & rhs)
386 T ar = static_cast<T>(rhs.R_component_1());
387 T br = static_cast<T>(rhs.R_component_2());
388 T cr = static_cast<T>(rhs.R_component_3());
389 T dr = static_cast<T>(rhs.R_component_4());
391 quaternion<T> result(a*ar - b*br - c*cr - d*dr, a*br + b*ar + c*dr - d*cr, a*cr - b*dr + c*ar + d*br, a*dr + b*cr - c*br + d*ar);
396 BOOST_CXX14_CONSTEXPR quaternion<T> & operator /= (T const & rhs) { return do_divide(rhs, detail::is_trivial_arithmetic_type<T>()); }
398 BOOST_CXX14_CONSTEXPR quaternion<T> & operator /= (::std::complex<T> const & rhs)
402 T denominator = ar*ar+br*br;
403 quaternion<T> result((+a*ar + b*br) / denominator, (-a*br + b*ar) / denominator, (+c*ar - d*br) / denominator, (+c*br + d*ar) / denominator);
409 BOOST_CXX14_CONSTEXPR quaternion<T> & operator /= (quaternion<X> const & rhs)
411 T ar = static_cast<T>(rhs.R_component_1());
412 T br = static_cast<T>(rhs.R_component_2());
413 T cr = static_cast<T>(rhs.R_component_3());
414 T dr = static_cast<T>(rhs.R_component_4());
416 T denominator = ar*ar+br*br+cr*cr+dr*dr;
417 quaternion<T> result((+a*ar+b*br+c*cr+d*dr)/denominator, (-a*br+b*ar-c*dr+d*cr)/denominator, (-a*cr+b*dr+c*ar-d*br)/denominator, (-a*dr-b*cr+c*br+d*ar)/denominator);
428 BOOST_CXX14_CONSTEXPR void swap(quaternion<T>& a, quaternion<T>& b) { a.swap(b); }
431 template <class T1, class T2>
432 inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
433 operator + (const quaternion<T1>& a, const T2& b)
435 return quaternion<T1>(static_cast<T1>(a.R_component_1() + b), a.R_component_2(), a.R_component_3(), a.R_component_4());
437 template <class T1, class T2>
438 inline constexpr typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
439 operator + (const T1& a, const quaternion<T2>& b)
441 return quaternion<T2>(static_cast<T2>(b.R_component_1() + a), b.R_component_2(), b.R_component_3(), b.R_component_4());
443 template <class T1, class T2>
444 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
445 operator + (const quaternion<T1>& a, const std::complex<T2>& b)
447 return quaternion<T1>(a.R_component_1() + std::real(b), a.R_component_2() + std::imag(b), a.R_component_3(), a.R_component_4());
449 template <class T1, class T2>
450 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
451 operator + (const std::complex<T1>& a, const quaternion<T2>& b)
453 return quaternion<T1>(b.R_component_1() + std::real(a), b.R_component_2() + std::imag(a), b.R_component_3(), b.R_component_4());
456 inline constexpr quaternion<T> operator + (const quaternion<T>& a, const quaternion<T>& b)
458 return quaternion<T>(a.R_component_1() + b.R_component_1(), a.R_component_2() + b.R_component_2(), a.R_component_3() + b.R_component_3(), a.R_component_4() + b.R_component_4());
461 template <class T1, class T2>
462 inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
463 operator - (const quaternion<T1>& a, const T2& b)
465 return quaternion<T1>(static_cast<T1>(a.R_component_1() - b), a.R_component_2(), a.R_component_3(), a.R_component_4());
467 template <class T1, class T2>
468 inline constexpr typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
469 operator - (const T1& a, const quaternion<T2>& b)
471 return quaternion<T2>(static_cast<T2>(a - b.R_component_1()), -b.R_component_2(), -b.R_component_3(), -b.R_component_4());
473 template <class T1, class T2>
474 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
475 operator - (const quaternion<T1>& a, const std::complex<T2>& b)
477 return quaternion<T1>(a.R_component_1() - std::real(b), a.R_component_2() - std::imag(b), a.R_component_3(), a.R_component_4());
479 template <class T1, class T2>
480 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
481 operator - (const std::complex<T1>& a, const quaternion<T2>& b)
483 return quaternion<T1>(std::real(a) - b.R_component_1(), std::imag(a) - b.R_component_2(), -b.R_component_3(), -b.R_component_4());
486 inline constexpr quaternion<T> operator - (const quaternion<T>& a, const quaternion<T>& b)
488 return quaternion<T>(a.R_component_1() - b.R_component_1(), a.R_component_2() - b.R_component_2(), a.R_component_3() - b.R_component_3(), a.R_component_4() - b.R_component_4());
492 template <class T1, class T2>
493 inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
494 operator * (const quaternion<T1>& a, const T2& b)
496 return quaternion<T1>(static_cast<T1>(a.R_component_1() * b), a.R_component_2() * b, a.R_component_3() * b, a.R_component_4() * b);
498 template <class T1, class T2>
499 inline constexpr typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
500 operator * (const T1& a, const quaternion<T2>& b)
502 return quaternion<T2>(static_cast<T2>(a * b.R_component_1()), a * b.R_component_2(), a * b.R_component_3(), a * b.R_component_4());
504 template <class T1, class T2>
505 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
506 operator * (const quaternion<T1>& a, const std::complex<T2>& b)
508 quaternion<T1> result(a);
512 template <class T1, class T2>
513 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
514 operator * (const std::complex<T1>& a, const quaternion<T2>& b)
516 quaternion<T1> result(a);
521 inline BOOST_CXX14_CONSTEXPR quaternion<T> operator * (const quaternion<T>& a, const quaternion<T>& b)
523 quaternion<T> result(a);
529 template <class T1, class T2>
530 inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
531 operator / (const quaternion<T1>& a, const T2& b)
533 return quaternion<T1>(a.R_component_1() / b, a.R_component_2() / b, a.R_component_3() / b, a.R_component_4() / b);
535 template <class T1, class T2>
536 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
537 operator / (const T1& a, const quaternion<T2>& b)
539 quaternion<T2> result(a);
543 template <class T1, class T2>
544 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
545 operator / (const quaternion<T1>& a, const std::complex<T2>& b)
547 quaternion<T1> result(a);
551 template <class T1, class T2>
552 inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
553 operator / (const std::complex<T1>& a, const quaternion<T2>& b)
555 quaternion<T2> result(a);
560 inline BOOST_CXX14_CONSTEXPR quaternion<T> operator / (const quaternion<T>& a, const quaternion<T>& b)
562 quaternion<T> result(a);
569 inline constexpr const quaternion<T>& operator + (quaternion<T> const & q)
576 inline constexpr quaternion<T> operator - (quaternion<T> const & q)
578 return(quaternion<T>(-q.R_component_1(),-q.R_component_2(),-q.R_component_3(),-q.R_component_4()));
582 template<typename R, typename T>
583 inline constexpr typename std::enable_if<std::is_convertible<R, T>::value, bool>::type operator == (R const & lhs, quaternion<T> const & rhs)
586 (rhs.R_component_1() == lhs)&&
587 (rhs.R_component_2() == static_cast<T>(0))&&
588 (rhs.R_component_3() == static_cast<T>(0))&&
589 (rhs.R_component_4() == static_cast<T>(0))
594 template<typename T, typename R>
595 inline constexpr typename std::enable_if<std::is_convertible<R, T>::value, bool>::type operator == (quaternion<T> const & lhs, R const & rhs)
602 inline constexpr bool operator == (::std::complex<T> const & lhs, quaternion<T> const & rhs)
605 (rhs.R_component_1() == lhs.real())&&
606 (rhs.R_component_2() == lhs.imag())&&
607 (rhs.R_component_3() == static_cast<T>(0))&&
608 (rhs.R_component_4() == static_cast<T>(0))
614 inline constexpr bool operator == (quaternion<T> const & lhs, ::std::complex<T> const & rhs)
621 inline constexpr bool operator == (quaternion<T> const & lhs, quaternion<T> const & rhs)
624 (rhs.R_component_1() == lhs.R_component_1())&&
625 (rhs.R_component_2() == lhs.R_component_2())&&
626 (rhs.R_component_3() == lhs.R_component_3())&&
627 (rhs.R_component_4() == lhs.R_component_4())
631 template<typename R, typename T> inline constexpr bool operator != (R const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
632 template<typename T, typename R> inline constexpr bool operator != (quaternion<T> const & lhs, R const & rhs) { return !(lhs == rhs); }
633 template<typename T> inline constexpr bool operator != (::std::complex<T> const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
634 template<typename T> inline constexpr bool operator != (quaternion<T> const & lhs, ::std::complex<T> const & rhs) { return !(lhs == rhs); }
635 template<typename T> inline constexpr bool operator != (quaternion<T> const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
638 // Note: we allow the following formats, with a, b, c, and d reals
640 // (a), (a,b), (a,b,c), (a,b,c,d)
641 // (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))
642 template<typename T, typename charT, class traits>
643 ::std::basic_istream<charT,traits> & operator >> ( ::std::basic_istream<charT,traits> & is,
646 const ::std::ctype<charT> & ct = ::std::use_facet< ::std::ctype<charT> >(is.getloc());
653 ::std::complex<T> u = ::std::complex<T>();
654 ::std::complex<T> v = ::std::complex<T>();
659 is >> ch; // get the first lexeme
661 if (!is.good()) goto finish;
663 cc = ct.narrow(ch, char());
665 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,))
667 is >> ch; // get the second lexeme
669 if (!is.good()) goto finish;
671 cc = ct.narrow(ch, char());
673 if (cc == '(') // read "((", possible: ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
677 is >> u; // we extract the first and second components
681 if (!is.good()) goto finish;
683 is >> ch; // get the next lexeme
685 if (!is.good()) goto finish;
687 cc = ct.narrow(ch, char());
689 if (cc == ')') // format: ((a)) or ((a,b))
691 q = quaternion<T>(a,b);
693 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,))
695 is >> v; // we extract the third and fourth components
699 if (!is.good()) goto finish;
701 is >> ch; // get the last lexeme
703 if (!is.good()) goto finish;
705 cc = ct.narrow(ch, char());
707 if (cc == ')') // format: ((a),c), ((a),(c)), ((a),(c,d)), ((a,b),c), ((a,b),(c)) or ((a,b,),(c,d,))
709 q = quaternion<T>(a,b,c,d);
713 is.setstate(::std::ios_base::failbit);
718 is.setstate(::std::ios_base::failbit);
721 else // read "(a", possible: (a), (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
725 is >> a; // we extract the first component
727 if (!is.good()) goto finish;
729 is >> ch; // get the third lexeme
731 if (!is.good()) goto finish;
733 cc = ct.narrow(ch, char());
735 if (cc == ')') // format: (a)
737 q = quaternion<T>(a);
739 else if (cc == ',') // read "(a,", possible: (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
741 is >> ch; // get the fourth lexeme
743 if (!is.good()) goto finish;
745 cc = ct.narrow(ch, char());
747 if (cc == '(') // read "(a,(", possible: (a,(c)), (a,(c,d))
751 is >> v; // we extract the third and fourth component
756 if (!is.good()) goto finish;
758 is >> ch; // get the ninth lexeme
760 if (!is.good()) goto finish;
762 cc = ct.narrow(ch, char());
764 if (cc == ')') // format: (a,(c)) or (a,(c,d))
766 q = quaternion<T>(a,b,c,d);
770 is.setstate(::std::ios_base::failbit);
773 else // read "(a,b", possible: (a,b), (a,b,c), (a,b,c,d)
777 is >> b; // we extract the second component
779 if (!is.good()) goto finish;
781 is >> ch; // get the fifth lexeme
783 if (!is.good()) goto finish;
785 cc = ct.narrow(ch, char());
787 if (cc == ')') // format: (a,b)
789 q = quaternion<T>(a,b);
791 else if (cc == ',') // read "(a,b,", possible: (a,b,c), (a,b,c,d)
793 is >> c; // we extract the third component
795 if (!is.good()) goto finish;
797 is >> ch; // get the seventh lexeme
799 if (!is.good()) goto finish;
801 cc = ct.narrow(ch, char());
803 if (cc == ')') // format: (a,b,c)
805 q = quaternion<T>(a,b,c);
807 else if (cc == ',') // read "(a,b,c,", possible: (a,b,c,d)
809 is >> d; // we extract the fourth component
811 if (!is.good()) goto finish;
813 is >> ch; // get the ninth lexeme
815 if (!is.good()) goto finish;
817 cc = ct.narrow(ch, char());
819 if (cc == ')') // format: (a,b,c,d)
821 q = quaternion<T>(a,b,c,d);
825 is.setstate(::std::ios_base::failbit);
830 is.setstate(::std::ios_base::failbit);
835 is.setstate(::std::ios_base::failbit);
841 is.setstate(::std::ios_base::failbit);
849 is >> a; // we extract the first component
851 if (!is.good()) goto finish;
853 q = quaternion<T>(a);
861 template<typename T, typename charT, class traits>
862 ::std::basic_ostream<charT,traits> & operator << ( ::std::basic_ostream<charT,traits> & os,
863 quaternion<T> const & q)
865 ::std::basic_ostringstream<charT,traits> s;
868 s.imbue(os.getloc());
869 s.precision(os.precision());
871 s << '(' << q.R_component_1() << ','
872 << q.R_component_2() << ','
873 << q.R_component_3() << ','
874 << q.R_component_4() << ')';
876 return os << s.str();
883 inline constexpr T real(quaternion<T> const & q)
890 inline constexpr quaternion<T> unreal(quaternion<T> const & q)
896 inline T sup(quaternion<T> const & q)
899 return (std::max)((std::max)(abs(q.R_component_1()), abs(q.R_component_2())), (std::max)(abs(q.R_component_3()), abs(q.R_component_4())));
904 inline T l1(quaternion<T> const & q)
907 return abs(q.R_component_1()) + abs(q.R_component_2()) + abs(q.R_component_3()) + abs(q.R_component_4());
912 inline T abs(quaternion<T> const & q)
917 T maxim = sup(q); // overflow protection
919 if (maxim == static_cast<T>(0))
925 T mixam = static_cast<T>(1)/maxim; // prefer multiplications over divisions
927 T a = q.R_component_1() * mixam;
928 T b = q.R_component_2() * mixam;
929 T c = q.R_component_3() * mixam;
930 T d = q.R_component_4() * mixam;
937 return(maxim * sqrt(a + b + c + d));
940 //return(sqrt(norm(q)));
944 // Note: This is the Cayley norm, not the Euclidean norm...
947 inline BOOST_CXX14_CONSTEXPR T norm(quaternion<T>const & q)
949 return(real(q*conj(q)));
954 inline constexpr quaternion<T> conj(quaternion<T> const & q)
956 return(quaternion<T>( +q.R_component_1(),
959 -q.R_component_4()));
964 inline quaternion<T> spherical( T const & rho,
972 //T a = cos(theta)*cos(phi1)*cos(phi2);
973 //T b = sin(theta)*cos(phi1)*cos(phi2);
974 //T c = sin(phi1)*cos(phi2);
977 T courrant = static_cast<T>(1);
981 courrant *= cos(phi2);
983 T c = sin(phi1)*courrant;
985 courrant *= cos(phi1);
987 T b = sin(theta)*courrant;
988 T a = cos(theta)*courrant;
990 return(rho*quaternion<T>(a,b,c,d));
995 inline quaternion<T> semipolar( T const & rho,
1003 T a = cos(alpha)*cos(theta1);
1004 T b = cos(alpha)*sin(theta1);
1005 T c = sin(alpha)*cos(theta2);
1006 T d = sin(alpha)*sin(theta2);
1008 return(rho*quaternion<T>(a,b,c,d));
1012 template<typename T>
1013 inline quaternion<T> multipolar( T const & rho1,
1021 T a = rho1*cos(theta1);
1022 T b = rho1*sin(theta1);
1023 T c = rho2*cos(theta2);
1024 T d = rho2*sin(theta2);
1026 return(quaternion<T>(a,b,c,d));
1030 template<typename T>
1031 inline quaternion<T> cylindrospherical( T const & t,
1033 T const & longitude,
1041 T b = radius*cos(longitude)*cos(latitude);
1042 T c = radius*sin(longitude)*cos(latitude);
1043 T d = radius*sin(latitude);
1045 return(quaternion<T>(t,b,c,d));
1049 template<typename T>
1050 inline quaternion<T> cylindrical(T const & r,
1061 return(quaternion<T>(a,b,h1,h2));
1066 // (please see the documentation)
1069 template<typename T>
1070 inline quaternion<T> exp(quaternion<T> const & q)
1075 using ::boost::math::sinc_pi;
1079 T z = abs(unreal(q));
1083 return(u*quaternion<T>(cos(z),
1084 w*q.R_component_2(), w*q.R_component_3(),
1085 w*q.R_component_4()));
1089 template<typename T>
1090 inline quaternion<T> cos(quaternion<T> const & q)
1096 using ::boost::math::sinhc_pi;
1098 T z = abs(unreal(q));
1100 T w = -sin(q.real())*sinhc_pi(z);
1102 return(quaternion<T>(cos(q.real())*cosh(z),
1103 w*q.R_component_2(), w*q.R_component_3(),
1104 w*q.R_component_4()));
1108 template<typename T>
1109 inline quaternion<T> sin(quaternion<T> const & q)
1115 using ::boost::math::sinhc_pi;
1117 T z = abs(unreal(q));
1119 T w = +cos(q.real())*sinhc_pi(z);
1121 return(quaternion<T>(sin(q.real())*cosh(z),
1122 w*q.R_component_2(), w*q.R_component_3(),
1123 w*q.R_component_4()));
1127 template<typename T>
1128 inline quaternion<T> tan(quaternion<T> const & q)
1130 return(sin(q)/cos(q));
1134 template<typename T>
1135 inline quaternion<T> cosh(quaternion<T> const & q)
1137 return((exp(+q)+exp(-q))/static_cast<T>(2));
1141 template<typename T>
1142 inline quaternion<T> sinh(quaternion<T> const & q)
1144 return((exp(+q)-exp(-q))/static_cast<T>(2));
1148 template<typename T>
1149 inline quaternion<T> tanh(quaternion<T> const & q)
1151 return(sinh(q)/cosh(q));
1155 template<typename T>
1156 quaternion<T> pow(quaternion<T> const & q,
1163 quaternion<T> result = pow(q, m);
1169 result *= q; // n odd
1180 return(quaternion<T>(static_cast<T>(1)));
1184 return(pow(quaternion<T>(static_cast<T>(1))/q,-n));
1190 #endif /* BOOST_QUATERNION_HPP */