quaternion.hpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  1. // boost quaternion.hpp header file
  2. // (C) Copyright Hubert Holin 2001.
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // See http://www.boost.org for updates, documentation, and revision history.
  7. #ifndef BOOST_QUATERNION_HPP
  8. #define BOOST_QUATERNION_HPP
  9. #include <boost/math_fwd.hpp>
  10. #include <boost/math/tools/config.hpp>
  11. #include <locale> // for the "<<" operator
  12. #include <complex>
  13. #include <iosfwd> // for the "<<" and ">>" operators
  14. #include <sstream> // for the "<<" operator
  15. #include <boost/math/special_functions/sinc.hpp> // for the Sinus cardinal
  16. #include <boost/math/special_functions/sinhc.hpp> // for the Hyperbolic Sinus cardinal
  17. #include <boost/math/tools/cxx03_warn.hpp>
  18. #include <type_traits>
  19. namespace boost
  20. {
  21. namespace math
  22. {
  23. namespace detail {
  24. template <class T>
  25. struct is_trivial_arithmetic_type_imp
  26. {
  27. typedef std::integral_constant<bool,
  28. noexcept(std::declval<T&>() += std::declval<T>())
  29. && noexcept(std::declval<T&>() -= std::declval<T>())
  30. && noexcept(std::declval<T&>() *= std::declval<T>())
  31. && noexcept(std::declval<T&>() /= std::declval<T>())
  32. > type;
  33. };
  34. template <class T>
  35. struct is_trivial_arithmetic_type : public is_trivial_arithmetic_type_imp<T>::type {};
  36. }
  37. #ifndef BOOST_MATH_NO_CXX14_CONSTEXPR
  38. namespace constexpr_detail
  39. {
  40. template <class T>
  41. constexpr void swap(T& a, T& b)
  42. {
  43. T t(a);
  44. a = b;
  45. b = t;
  46. }
  47. }
  48. #endif
  49. template<typename T>
  50. class quaternion
  51. {
  52. public:
  53. typedef T value_type;
  54. // constructor for H seen as R^4
  55. // (also default constructor)
  56. constexpr explicit quaternion( T const & requested_a = T(),
  57. T const & requested_b = T(),
  58. T const & requested_c = T(),
  59. T const & requested_d = T())
  60. : a(requested_a),
  61. b(requested_b),
  62. c(requested_c),
  63. d(requested_d)
  64. {
  65. // nothing to do!
  66. }
  67. // constructor for H seen as C^2
  68. constexpr explicit quaternion( ::std::complex<T> const & z0,
  69. ::std::complex<T> const & z1 = ::std::complex<T>())
  70. : a(z0.real()),
  71. b(z0.imag()),
  72. c(z1.real()),
  73. d(z1.imag())
  74. {
  75. // nothing to do!
  76. }
  77. // UNtemplated copy constructor
  78. constexpr quaternion(quaternion const & a_recopier)
  79. : a(a_recopier.R_component_1()),
  80. b(a_recopier.R_component_2()),
  81. c(a_recopier.R_component_3()),
  82. d(a_recopier.R_component_4()) {}
  83. constexpr quaternion(quaternion && a_recopier)
  84. : a(std::move(a_recopier.R_component_1())),
  85. b(std::move(a_recopier.R_component_2())),
  86. c(std::move(a_recopier.R_component_3())),
  87. d(std::move(a_recopier.R_component_4())) {}
  88. // templated copy constructor
  89. template<typename X>
  90. constexpr explicit quaternion(quaternion<X> const & a_recopier)
  91. : a(static_cast<T>(a_recopier.R_component_1())),
  92. b(static_cast<T>(a_recopier.R_component_2())),
  93. c(static_cast<T>(a_recopier.R_component_3())),
  94. d(static_cast<T>(a_recopier.R_component_4()))
  95. {
  96. // nothing to do!
  97. }
  98. // destructor
  99. // (this is taken care of by the compiler itself)
  100. // accessors
  101. //
  102. // Note: Like complex number, quaternions do have a meaningful notion of "real part",
  103. // but unlike them there is no meaningful notion of "imaginary part".
  104. // Instead there is an "unreal part" which itself is a quaternion, and usually
  105. // nothing simpler (as opposed to the complex number case).
  106. // However, for practicality, there are accessors for the other components
  107. // (these are necessary for the templated copy constructor, for instance).
  108. constexpr T real() const
  109. {
  110. return(a);
  111. }
  112. constexpr quaternion<T> unreal() const
  113. {
  114. return(quaternion<T>(static_cast<T>(0), b, c, d));
  115. }
  116. constexpr T R_component_1() const
  117. {
  118. return(a);
  119. }
  120. constexpr T R_component_2() const
  121. {
  122. return(b);
  123. }
  124. constexpr T R_component_3() const
  125. {
  126. return(c);
  127. }
  128. constexpr T R_component_4() const
  129. {
  130. return(d);
  131. }
  132. constexpr ::std::complex<T> C_component_1() const
  133. {
  134. return(::std::complex<T>(a, b));
  135. }
  136. constexpr ::std::complex<T> C_component_2() const
  137. {
  138. return(::std::complex<T>(c, d));
  139. }
  140. BOOST_MATH_CXX14_CONSTEXPR void swap(quaternion& o)
  141. {
  142. #ifndef BOOST_MATH_NO_CXX14_CONSTEXPR
  143. using constexpr_detail::swap;
  144. #else
  145. using std::swap;
  146. #endif
  147. swap(a, o.a);
  148. swap(b, o.b);
  149. swap(c, o.c);
  150. swap(d, o.d);
  151. }
  152. // assignment operators
  153. template<typename X>
  154. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<X> const & a_affecter)
  155. {
  156. a = static_cast<T>(a_affecter.R_component_1());
  157. b = static_cast<T>(a_affecter.R_component_2());
  158. c = static_cast<T>(a_affecter.R_component_3());
  159. d = static_cast<T>(a_affecter.R_component_4());
  160. return(*this);
  161. }
  162. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<T> const & a_affecter)
  163. {
  164. a = a_affecter.a;
  165. b = a_affecter.b;
  166. c = a_affecter.c;
  167. d = a_affecter.d;
  168. return(*this);
  169. }
  170. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<T> && a_affecter)
  171. {
  172. a = std::move(a_affecter.a);
  173. b = std::move(a_affecter.b);
  174. c = std::move(a_affecter.c);
  175. d = std::move(a_affecter.d);
  176. return(*this);
  177. }
  178. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator = (T const & a_affecter)
  179. {
  180. a = a_affecter;
  181. b = c = d = static_cast<T>(0);
  182. return(*this);
  183. }
  184. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator = (::std::complex<T> const & a_affecter)
  185. {
  186. a = a_affecter.real();
  187. b = a_affecter.imag();
  188. c = d = static_cast<T>(0);
  189. return(*this);
  190. }
  191. // other assignment-related operators
  192. //
  193. // NOTE: Quaternion multiplication is *NOT* commutative;
  194. // symbolically, "q *= rhs;" means "q = q * rhs;"
  195. // and "q /= rhs;" means "q = q * inverse_of(rhs);"
  196. //
  197. // Note2: Each operator comes in 2 forms - one for the simple case where
  198. // type T throws no exceptions, and one exception-safe version
  199. // for the case where it might.
  200. private:
  201. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_add(T const & rhs, const std::true_type&)
  202. {
  203. a += rhs;
  204. return *this;
  205. }
  206. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_add(T const & rhs, const std::false_type&)
  207. {
  208. quaternion<T> result(a + rhs, b, c, d); // exception guard
  209. swap(result);
  210. return *this;
  211. }
  212. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_add(std::complex<T> const & rhs, const std::true_type&)
  213. {
  214. a += std::real(rhs);
  215. b += std::imag(rhs);
  216. return *this;
  217. }
  218. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_add(std::complex<T> const & rhs, const std::false_type&)
  219. {
  220. quaternion<T> result(a + std::real(rhs), b + std::imag(rhs), c, d); // exception guard
  221. swap(result);
  222. return *this;
  223. }
  224. template <class X>
  225. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_add(quaternion<X> const & rhs, const std::true_type&)
  226. {
  227. a += rhs.R_component_1();
  228. b += rhs.R_component_2();
  229. c += rhs.R_component_3();
  230. d += rhs.R_component_4();
  231. return *this;
  232. }
  233. template <class X>
  234. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_add(quaternion<X> const & rhs, const std::false_type&)
  235. {
  236. 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
  237. swap(result);
  238. return *this;
  239. }
  240. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_subtract(T const & rhs, const std::true_type&)
  241. {
  242. a -= rhs;
  243. return *this;
  244. }
  245. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_subtract(T const & rhs, const std::false_type&)
  246. {
  247. quaternion<T> result(a - rhs, b, c, d); // exception guard
  248. swap(result);
  249. return *this;
  250. }
  251. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_subtract(std::complex<T> const & rhs, const std::true_type&)
  252. {
  253. a -= std::real(rhs);
  254. b -= std::imag(rhs);
  255. return *this;
  256. }
  257. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_subtract(std::complex<T> const & rhs, const std::false_type&)
  258. {
  259. quaternion<T> result(a - std::real(rhs), b - std::imag(rhs), c, d); // exception guard
  260. swap(result);
  261. return *this;
  262. }
  263. template <class X>
  264. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_subtract(quaternion<X> const & rhs, const std::true_type&)
  265. {
  266. a -= rhs.R_component_1();
  267. b -= rhs.R_component_2();
  268. c -= rhs.R_component_3();
  269. d -= rhs.R_component_4();
  270. return *this;
  271. }
  272. template <class X>
  273. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_subtract(quaternion<X> const & rhs, const std::false_type&)
  274. {
  275. 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
  276. swap(result);
  277. return *this;
  278. }
  279. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_multiply(T const & rhs, const std::true_type&)
  280. {
  281. a *= rhs;
  282. b *= rhs;
  283. c *= rhs;
  284. d *= rhs;
  285. return *this;
  286. }
  287. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_multiply(T const & rhs, const std::false_type&)
  288. {
  289. quaternion<T> result(a * rhs, b * rhs, c * rhs, d * rhs); // exception guard
  290. swap(result);
  291. return *this;
  292. }
  293. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_divide(T const & rhs, const std::true_type&)
  294. {
  295. a /= rhs;
  296. b /= rhs;
  297. c /= rhs;
  298. d /= rhs;
  299. return *this;
  300. }
  301. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & do_divide(T const & rhs, const std::false_type&)
  302. {
  303. quaternion<T> result(a / rhs, b / rhs, c / rhs, d / rhs); // exception guard
  304. swap(result);
  305. return *this;
  306. }
  307. public:
  308. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator += (T const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
  309. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator += (::std::complex<T> const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
  310. template<typename X> BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator += (quaternion<X> const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
  311. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator -= (T const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
  312. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator -= (::std::complex<T> const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
  313. template<typename X> BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator -= (quaternion<X> const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
  314. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator *= (T const & rhs) { return do_multiply(rhs, detail::is_trivial_arithmetic_type<T>()); }
  315. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator *= (::std::complex<T> const & rhs)
  316. {
  317. T ar = rhs.real();
  318. T br = rhs.imag();
  319. quaternion<T> result(a*ar - b*br, a*br + b*ar, c*ar + d*br, -c*br+d*ar);
  320. swap(result);
  321. return(*this);
  322. }
  323. template<typename X>
  324. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator *= (quaternion<X> const & rhs)
  325. {
  326. T ar = static_cast<T>(rhs.R_component_1());
  327. T br = static_cast<T>(rhs.R_component_2());
  328. T cr = static_cast<T>(rhs.R_component_3());
  329. T dr = static_cast<T>(rhs.R_component_4());
  330. 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);
  331. swap(result);
  332. return(*this);
  333. }
  334. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator /= (T const & rhs) { return do_divide(rhs, detail::is_trivial_arithmetic_type<T>()); }
  335. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator /= (::std::complex<T> const & rhs)
  336. {
  337. T ar = rhs.real();
  338. T br = rhs.imag();
  339. T denominator = ar*ar+br*br;
  340. quaternion<T> result((+a*ar + b*br) / denominator, (-a*br + b*ar) / denominator, (+c*ar - d*br) / denominator, (+c*br + d*ar) / denominator);
  341. swap(result);
  342. return(*this);
  343. }
  344. template<typename X>
  345. BOOST_MATH_CXX14_CONSTEXPR quaternion<T> & operator /= (quaternion<X> const & rhs)
  346. {
  347. T ar = static_cast<T>(rhs.R_component_1());
  348. T br = static_cast<T>(rhs.R_component_2());
  349. T cr = static_cast<T>(rhs.R_component_3());
  350. T dr = static_cast<T>(rhs.R_component_4());
  351. T denominator = ar*ar+br*br+cr*cr+dr*dr;
  352. 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);
  353. swap(result);
  354. return(*this);
  355. }
  356. private:
  357. T a, b, c, d;
  358. };
  359. // swap:
  360. template <class T>
  361. BOOST_MATH_CXX14_CONSTEXPR void swap(quaternion<T>& a, quaternion<T>& b) { a.swap(b); }
  362. // operator+
  363. template <class T1, class T2>
  364. inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  365. operator + (const quaternion<T1>& a, const T2& b)
  366. {
  367. return quaternion<T1>(static_cast<T1>(a.R_component_1() + b), a.R_component_2(), a.R_component_3(), a.R_component_4());
  368. }
  369. template <class T1, class T2>
  370. inline constexpr typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  371. operator + (const T1& a, const quaternion<T2>& b)
  372. {
  373. return quaternion<T2>(static_cast<T2>(b.R_component_1() + a), b.R_component_2(), b.R_component_3(), b.R_component_4());
  374. }
  375. template <class T1, class T2>
  376. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  377. operator + (const quaternion<T1>& a, const std::complex<T2>& b)
  378. {
  379. 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());
  380. }
  381. template <class T1, class T2>
  382. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  383. operator + (const std::complex<T1>& a, const quaternion<T2>& b)
  384. {
  385. 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());
  386. }
  387. template <class T>
  388. inline constexpr quaternion<T> operator + (const quaternion<T>& a, const quaternion<T>& b)
  389. {
  390. 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());
  391. }
  392. // operator-
  393. template <class T1, class T2>
  394. inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  395. operator - (const quaternion<T1>& a, const T2& b)
  396. {
  397. return quaternion<T1>(static_cast<T1>(a.R_component_1() - b), a.R_component_2(), a.R_component_3(), a.R_component_4());
  398. }
  399. template <class T1, class T2>
  400. inline constexpr typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  401. operator - (const T1& a, const quaternion<T2>& b)
  402. {
  403. return quaternion<T2>(static_cast<T2>(a - b.R_component_1()), -b.R_component_2(), -b.R_component_3(), -b.R_component_4());
  404. }
  405. template <class T1, class T2>
  406. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  407. operator - (const quaternion<T1>& a, const std::complex<T2>& b)
  408. {
  409. 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());
  410. }
  411. template <class T1, class T2>
  412. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  413. operator - (const std::complex<T1>& a, const quaternion<T2>& b)
  414. {
  415. 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());
  416. }
  417. template <class T>
  418. inline constexpr quaternion<T> operator - (const quaternion<T>& a, const quaternion<T>& b)
  419. {
  420. 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());
  421. }
  422. // operator*
  423. template <class T1, class T2>
  424. inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  425. operator * (const quaternion<T1>& a, const T2& b)
  426. {
  427. 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);
  428. }
  429. template <class T1, class T2>
  430. inline constexpr typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  431. operator * (const T1& a, const quaternion<T2>& b)
  432. {
  433. 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());
  434. }
  435. template <class T1, class T2>
  436. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  437. operator * (const quaternion<T1>& a, const std::complex<T2>& b)
  438. {
  439. quaternion<T1> result(a);
  440. result *= b;
  441. return result;
  442. }
  443. template <class T1, class T2>
  444. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  445. operator * (const std::complex<T1>& a, const quaternion<T2>& b)
  446. {
  447. quaternion<T1> result(a);
  448. result *= b;
  449. return result;
  450. }
  451. template <class T>
  452. inline BOOST_MATH_CXX14_CONSTEXPR quaternion<T> operator * (const quaternion<T>& a, const quaternion<T>& b)
  453. {
  454. quaternion<T> result(a);
  455. result *= b;
  456. return result;
  457. }
  458. // operator/
  459. template <class T1, class T2>
  460. inline constexpr typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  461. operator / (const quaternion<T1>& a, const T2& b)
  462. {
  463. return quaternion<T1>(a.R_component_1() / b, a.R_component_2() / b, a.R_component_3() / b, a.R_component_4() / b);
  464. }
  465. template <class T1, class T2>
  466. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  467. operator / (const T1& a, const quaternion<T2>& b)
  468. {
  469. quaternion<T2> result(a);
  470. result /= b;
  471. return result;
  472. }
  473. template <class T1, class T2>
  474. inline BOOST_MATH_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)
  476. {
  477. quaternion<T1> result(a);
  478. result /= b;
  479. return result;
  480. }
  481. template <class T1, class T2>
  482. inline BOOST_MATH_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  483. operator / (const std::complex<T1>& a, const quaternion<T2>& b)
  484. {
  485. quaternion<T2> result(a);
  486. result /= b;
  487. return result;
  488. }
  489. template <class T>
  490. inline BOOST_MATH_CXX14_CONSTEXPR quaternion<T> operator / (const quaternion<T>& a, const quaternion<T>& b)
  491. {
  492. quaternion<T> result(a);
  493. result /= b;
  494. return result;
  495. }
  496. template<typename T>
  497. inline constexpr const quaternion<T>& operator + (quaternion<T> const & q)
  498. {
  499. return q;
  500. }
  501. template<typename T>
  502. inline constexpr quaternion<T> operator - (quaternion<T> const & q)
  503. {
  504. return(quaternion<T>(-q.R_component_1(),-q.R_component_2(),-q.R_component_3(),-q.R_component_4()));
  505. }
  506. template<typename R, typename T>
  507. inline constexpr typename std::enable_if<std::is_convertible<R, T>::value, bool>::type operator == (R const & lhs, quaternion<T> const & rhs)
  508. {
  509. return (
  510. (rhs.R_component_1() == lhs)&&
  511. (rhs.R_component_2() == static_cast<T>(0))&&
  512. (rhs.R_component_3() == static_cast<T>(0))&&
  513. (rhs.R_component_4() == static_cast<T>(0))
  514. );
  515. }
  516. template<typename T, typename R>
  517. inline constexpr typename std::enable_if<std::is_convertible<R, T>::value, bool>::type operator == (quaternion<T> const & lhs, R const & rhs)
  518. {
  519. return rhs == lhs;
  520. }
  521. template<typename T>
  522. inline constexpr bool operator == (::std::complex<T> const & lhs, quaternion<T> const & rhs)
  523. {
  524. return (
  525. (rhs.R_component_1() == lhs.real())&&
  526. (rhs.R_component_2() == lhs.imag())&&
  527. (rhs.R_component_3() == static_cast<T>(0))&&
  528. (rhs.R_component_4() == static_cast<T>(0))
  529. );
  530. }
  531. template<typename T>
  532. inline constexpr bool operator == (quaternion<T> const & lhs, ::std::complex<T> const & rhs)
  533. {
  534. return rhs == lhs;
  535. }
  536. template<typename T>
  537. inline constexpr bool operator == (quaternion<T> const & lhs, quaternion<T> const & rhs)
  538. {
  539. return (
  540. (rhs.R_component_1() == lhs.R_component_1())&&
  541. (rhs.R_component_2() == lhs.R_component_2())&&
  542. (rhs.R_component_3() == lhs.R_component_3())&&
  543. (rhs.R_component_4() == lhs.R_component_4())
  544. );
  545. }
  546. template<typename R, typename T> inline constexpr bool operator != (R const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
  547. template<typename T, typename R> inline constexpr bool operator != (quaternion<T> const & lhs, R const & rhs) { return !(lhs == rhs); }
  548. template<typename T> inline constexpr bool operator != (::std::complex<T> const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
  549. template<typename T> inline constexpr bool operator != (quaternion<T> const & lhs, ::std::complex<T> const & rhs) { return !(lhs == rhs); }
  550. template<typename T> inline constexpr bool operator != (quaternion<T> const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
  551. // Note: we allow the following formats, with a, b, c, and d reals
  552. // a
  553. // (a), (a,b), (a,b,c), (a,b,c,d)
  554. // (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))
  555. template<typename T, typename charT, class traits>
  556. ::std::basic_istream<charT,traits> & operator >> ( ::std::basic_istream<charT,traits> & is,
  557. quaternion<T> & q)
  558. {
  559. const ::std::ctype<charT> & ct = ::std::use_facet< ::std::ctype<charT> >(is.getloc());
  560. T a = T();
  561. T b = T();
  562. T c = T();
  563. T d = T();
  564. ::std::complex<T> u = ::std::complex<T>();
  565. ::std::complex<T> v = ::std::complex<T>();
  566. charT ch = charT();
  567. char cc;
  568. is >> ch; // get the first lexeme
  569. if (!is.good()) goto finish;
  570. cc = ct.narrow(ch, char());
  571. 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,))
  572. {
  573. is >> ch; // get the second lexeme
  574. if (!is.good()) goto finish;
  575. cc = ct.narrow(ch, char());
  576. if (cc == '(') // read "((", possible: ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
  577. {
  578. is.putback(ch);
  579. is >> u; // we extract the first and second components
  580. a = u.real();
  581. b = u.imag();
  582. if (!is.good()) goto finish;
  583. is >> ch; // get the next lexeme
  584. if (!is.good()) goto finish;
  585. cc = ct.narrow(ch, char());
  586. if (cc == ')') // format: ((a)) or ((a,b))
  587. {
  588. q = quaternion<T>(a,b);
  589. }
  590. 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,))
  591. {
  592. is >> v; // we extract the third and fourth components
  593. c = v.real();
  594. d = v.imag();
  595. if (!is.good()) goto finish;
  596. is >> ch; // get the last lexeme
  597. if (!is.good()) goto finish;
  598. cc = ct.narrow(ch, char());
  599. if (cc == ')') // format: ((a),c), ((a),(c)), ((a),(c,d)), ((a,b),c), ((a,b),(c)) or ((a,b,),(c,d,))
  600. {
  601. q = quaternion<T>(a,b,c,d);
  602. }
  603. else // error
  604. {
  605. is.setstate(::std::ios_base::failbit);
  606. }
  607. }
  608. else // error
  609. {
  610. is.setstate(::std::ios_base::failbit);
  611. }
  612. }
  613. else // read "(a", possible: (a), (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
  614. {
  615. is.putback(ch);
  616. is >> a; // we extract the first component
  617. if (!is.good()) goto finish;
  618. is >> ch; // get the third lexeme
  619. if (!is.good()) goto finish;
  620. cc = ct.narrow(ch, char());
  621. if (cc == ')') // format: (a)
  622. {
  623. q = quaternion<T>(a);
  624. }
  625. else if (cc == ',') // read "(a,", possible: (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
  626. {
  627. is >> ch; // get the fourth lexeme
  628. if (!is.good()) goto finish;
  629. cc = ct.narrow(ch, char());
  630. if (cc == '(') // read "(a,(", possible: (a,(c)), (a,(c,d))
  631. {
  632. is.putback(ch);
  633. is >> v; // we extract the third and fourth component
  634. c = v.real();
  635. d = v.imag();
  636. if (!is.good()) goto finish;
  637. is >> ch; // get the ninth lexeme
  638. if (!is.good()) goto finish;
  639. cc = ct.narrow(ch, char());
  640. if (cc == ')') // format: (a,(c)) or (a,(c,d))
  641. {
  642. q = quaternion<T>(a,b,c,d);
  643. }
  644. else // error
  645. {
  646. is.setstate(::std::ios_base::failbit);
  647. }
  648. }
  649. else // read "(a,b", possible: (a,b), (a,b,c), (a,b,c,d)
  650. {
  651. is.putback(ch);
  652. is >> b; // we extract the second component
  653. if (!is.good()) goto finish;
  654. is >> ch; // get the fifth lexeme
  655. if (!is.good()) goto finish;
  656. cc = ct.narrow(ch, char());
  657. if (cc == ')') // format: (a,b)
  658. {
  659. q = quaternion<T>(a,b);
  660. }
  661. else if (cc == ',') // read "(a,b,", possible: (a,b,c), (a,b,c,d)
  662. {
  663. is >> c; // we extract the third component
  664. if (!is.good()) goto finish;
  665. is >> ch; // get the seventh lexeme
  666. if (!is.good()) goto finish;
  667. cc = ct.narrow(ch, char());
  668. if (cc == ')') // format: (a,b,c)
  669. {
  670. q = quaternion<T>(a,b,c);
  671. }
  672. else if (cc == ',') // read "(a,b,c,", possible: (a,b,c,d)
  673. {
  674. is >> d; // we extract the fourth component
  675. if (!is.good()) goto finish;
  676. is >> ch; // get the ninth lexeme
  677. if (!is.good()) goto finish;
  678. cc = ct.narrow(ch, char());
  679. if (cc == ')') // format: (a,b,c,d)
  680. {
  681. q = quaternion<T>(a,b,c,d);
  682. }
  683. else // error
  684. {
  685. is.setstate(::std::ios_base::failbit);
  686. }
  687. }
  688. else // error
  689. {
  690. is.setstate(::std::ios_base::failbit);
  691. }
  692. }
  693. else // error
  694. {
  695. is.setstate(::std::ios_base::failbit);
  696. }
  697. }
  698. }
  699. else // error
  700. {
  701. is.setstate(::std::ios_base::failbit);
  702. }
  703. }
  704. }
  705. else // format: a
  706. {
  707. is.putback(ch);
  708. is >> a; // we extract the first component
  709. if (!is.good()) goto finish;
  710. q = quaternion<T>(a);
  711. }
  712. finish:
  713. return(is);
  714. }
  715. template<typename T, typename charT, class traits>
  716. ::std::basic_ostream<charT,traits> & operator << ( ::std::basic_ostream<charT,traits> & os,
  717. quaternion<T> const & q)
  718. {
  719. ::std::basic_ostringstream<charT,traits> s;
  720. s.flags(os.flags());
  721. s.imbue(os.getloc());
  722. s.precision(os.precision());
  723. s << '(' << q.R_component_1() << ','
  724. << q.R_component_2() << ','
  725. << q.R_component_3() << ','
  726. << q.R_component_4() << ')';
  727. return os << s.str();
  728. }
  729. // values
  730. template<typename T>
  731. inline constexpr T real(quaternion<T> const & q)
  732. {
  733. return(q.real());
  734. }
  735. template<typename T>
  736. inline constexpr quaternion<T> unreal(quaternion<T> const & q)
  737. {
  738. return(q.unreal());
  739. }
  740. template<typename T>
  741. inline T sup(quaternion<T> const & q)
  742. {
  743. using ::std::abs;
  744. 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())));
  745. }
  746. template<typename T>
  747. inline T l1(quaternion<T> const & q)
  748. {
  749. using ::std::abs;
  750. return abs(q.R_component_1()) + abs(q.R_component_2()) + abs(q.R_component_3()) + abs(q.R_component_4());
  751. }
  752. template<typename T>
  753. inline T abs(quaternion<T> const & q)
  754. {
  755. using ::std::abs;
  756. using ::std::sqrt;
  757. T maxim = sup(q); // overflow protection
  758. if (maxim == static_cast<T>(0))
  759. {
  760. return(maxim);
  761. }
  762. else
  763. {
  764. T mixam = static_cast<T>(1)/maxim; // prefer multiplications over divisions
  765. T a = q.R_component_1() * mixam;
  766. T b = q.R_component_2() * mixam;
  767. T c = q.R_component_3() * mixam;
  768. T d = q.R_component_4() * mixam;
  769. a *= a;
  770. b *= b;
  771. c *= c;
  772. d *= d;
  773. return(maxim * sqrt(a + b + c + d));
  774. }
  775. //return(sqrt(norm(q)));
  776. }
  777. // Note: This is the Cayley norm, not the Euclidean norm...
  778. template<typename T>
  779. inline BOOST_MATH_CXX14_CONSTEXPR T norm(quaternion<T>const & q)
  780. {
  781. return(real(q*conj(q)));
  782. }
  783. template<typename T>
  784. inline constexpr quaternion<T> conj(quaternion<T> const & q)
  785. {
  786. return(quaternion<T>( +q.R_component_1(),
  787. -q.R_component_2(),
  788. -q.R_component_3(),
  789. -q.R_component_4()));
  790. }
  791. template<typename T>
  792. inline quaternion<T> spherical( T const & rho,
  793. T const & theta,
  794. T const & phi1,
  795. T const & phi2)
  796. {
  797. using ::std::cos;
  798. using ::std::sin;
  799. //T a = cos(theta)*cos(phi1)*cos(phi2);
  800. //T b = sin(theta)*cos(phi1)*cos(phi2);
  801. //T c = sin(phi1)*cos(phi2);
  802. //T d = sin(phi2);
  803. T courrant = static_cast<T>(1);
  804. T d = sin(phi2);
  805. courrant *= cos(phi2);
  806. T c = sin(phi1)*courrant;
  807. courrant *= cos(phi1);
  808. T b = sin(theta)*courrant;
  809. T a = cos(theta)*courrant;
  810. return(rho*quaternion<T>(a,b,c,d));
  811. }
  812. template<typename T>
  813. inline quaternion<T> semipolar( T const & rho,
  814. T const & alpha,
  815. T const & theta1,
  816. T const & theta2)
  817. {
  818. using ::std::cos;
  819. using ::std::sin;
  820. T a = cos(alpha)*cos(theta1);
  821. T b = cos(alpha)*sin(theta1);
  822. T c = sin(alpha)*cos(theta2);
  823. T d = sin(alpha)*sin(theta2);
  824. return(rho*quaternion<T>(a,b,c,d));
  825. }
  826. template<typename T>
  827. inline quaternion<T> multipolar( T const & rho1,
  828. T const & theta1,
  829. T const & rho2,
  830. T const & theta2)
  831. {
  832. using ::std::cos;
  833. using ::std::sin;
  834. T a = rho1*cos(theta1);
  835. T b = rho1*sin(theta1);
  836. T c = rho2*cos(theta2);
  837. T d = rho2*sin(theta2);
  838. return(quaternion<T>(a,b,c,d));
  839. }
  840. template<typename T>
  841. inline quaternion<T> cylindrospherical( T const & t,
  842. T const & radius,
  843. T const & longitude,
  844. T const & latitude)
  845. {
  846. using ::std::cos;
  847. using ::std::sin;
  848. T b = radius*cos(longitude)*cos(latitude);
  849. T c = radius*sin(longitude)*cos(latitude);
  850. T d = radius*sin(latitude);
  851. return(quaternion<T>(t,b,c,d));
  852. }
  853. template<typename T>
  854. inline quaternion<T> cylindrical(T const & r,
  855. T const & angle,
  856. T const & h1,
  857. T const & h2)
  858. {
  859. using ::std::cos;
  860. using ::std::sin;
  861. T a = r*cos(angle);
  862. T b = r*sin(angle);
  863. return(quaternion<T>(a,b,h1,h2));
  864. }
  865. // transcendentals
  866. // (please see the documentation)
  867. template<typename T>
  868. inline quaternion<T> exp(quaternion<T> const & q)
  869. {
  870. using ::std::exp;
  871. using ::std::cos;
  872. using ::boost::math::sinc_pi;
  873. T u = exp(real(q));
  874. T z = abs(unreal(q));
  875. T w = sinc_pi(z);
  876. return(u*quaternion<T>(cos(z),
  877. w*q.R_component_2(), w*q.R_component_3(),
  878. w*q.R_component_4()));
  879. }
  880. template<typename T>
  881. inline quaternion<T> cos(quaternion<T> const & q)
  882. {
  883. using ::std::sin;
  884. using ::std::cos;
  885. using ::std::cosh;
  886. using ::boost::math::sinhc_pi;
  887. T z = abs(unreal(q));
  888. T w = -sin(q.real())*sinhc_pi(z);
  889. return(quaternion<T>(cos(q.real())*cosh(z),
  890. w*q.R_component_2(), w*q.R_component_3(),
  891. w*q.R_component_4()));
  892. }
  893. template<typename T>
  894. inline quaternion<T> sin(quaternion<T> const & q)
  895. {
  896. using ::std::sin;
  897. using ::std::cos;
  898. using ::std::cosh;
  899. using ::boost::math::sinhc_pi;
  900. T z = abs(unreal(q));
  901. T w = +cos(q.real())*sinhc_pi(z);
  902. return(quaternion<T>(sin(q.real())*cosh(z),
  903. w*q.R_component_2(), w*q.R_component_3(),
  904. w*q.R_component_4()));
  905. }
  906. template<typename T>
  907. inline quaternion<T> tan(quaternion<T> const & q)
  908. {
  909. return(sin(q)/cos(q));
  910. }
  911. template<typename T>
  912. inline quaternion<T> cosh(quaternion<T> const & q)
  913. {
  914. return((exp(+q)+exp(-q))/static_cast<T>(2));
  915. }
  916. template<typename T>
  917. inline quaternion<T> sinh(quaternion<T> const & q)
  918. {
  919. return((exp(+q)-exp(-q))/static_cast<T>(2));
  920. }
  921. template<typename T>
  922. inline quaternion<T> tanh(quaternion<T> const & q)
  923. {
  924. return(sinh(q)/cosh(q));
  925. }
  926. template<typename T>
  927. quaternion<T> pow(quaternion<T> const & q,
  928. int n)
  929. {
  930. if (n > 1)
  931. {
  932. int m = n>>1;
  933. quaternion<T> result = pow(q, m);
  934. result *= result;
  935. if (n != (m<<1))
  936. {
  937. result *= q; // n odd
  938. }
  939. return(result);
  940. }
  941. else if (n == 1)
  942. {
  943. return(q);
  944. }
  945. else if (n == 0)
  946. {
  947. return(quaternion<T>(static_cast<T>(1)));
  948. }
  949. else /* n < 0 */
  950. {
  951. return(pow(quaternion<T>(static_cast<T>(1))/q,-n));
  952. }
  953. }
  954. }
  955. }
  956. #endif /* BOOST_QUATERNION_HPP */