quaternion.hpp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  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 */