xcomplex.hpp 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361
  1. /***************************************************************************
  2. * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht *
  3. * Copyright (c) QuantStack *
  4. * *
  5. * Distributed under the terms of the BSD 3-Clause License. *
  6. * *
  7. * The full license is in the file LICENSE, distributed with this software. *
  8. ****************************************************************************/
  9. #ifndef XTL_COMPLEX_HPP
  10. #define XTL_COMPLEX_HPP
  11. #if !defined(_MSC_VER)
  12. #include <cmath>
  13. using std::copysign;
  14. #endif
  15. #include <complex>
  16. #include <cstddef>
  17. #include <limits>
  18. #include <type_traits>
  19. #include <utility>
  20. #include <sstream>
  21. #include <string>
  22. #ifdef __CLING__
  23. #include <nlohmann/json.hpp>
  24. #endif
  25. #include "xclosure.hpp"
  26. #include "xtl_config.hpp"
  27. #include "xtype_traits.hpp"
  28. namespace xtl
  29. {
  30. template <class CTR, class CTI = CTR, bool ieee_compliant = false>
  31. class xcomplex;
  32. /**************
  33. * is_complex *
  34. **************/
  35. namespace detail
  36. {
  37. template <class T>
  38. struct is_complex : std::false_type
  39. {
  40. };
  41. template <class T>
  42. struct is_complex<std::complex<T>> : std::true_type
  43. {
  44. };
  45. }
  46. template <class T>
  47. struct is_complex
  48. {
  49. static constexpr bool value = detail::is_complex<std::decay_t<T>>::value;
  50. };
  51. /***************
  52. * is_xcomplex *
  53. ***************/
  54. namespace detail
  55. {
  56. template <class T>
  57. struct is_xcomplex : std::false_type
  58. {
  59. };
  60. template <class CTR, class CTI, bool B>
  61. struct is_xcomplex<xcomplex<CTR, CTI, B>> : std::true_type
  62. {
  63. };
  64. }
  65. template <class T>
  66. struct is_xcomplex
  67. {
  68. static constexpr bool value = detail::is_xcomplex<std::decay_t<T>>::value;
  69. };
  70. /******************
  71. * is_gen_complex *
  72. ******************/
  73. template <class T>
  74. using is_gen_complex = disjunction<is_complex<std::decay_t<T>>, is_xcomplex<std::decay_t<T>>>;
  75. /****************************
  76. * enable / disable complex *
  77. ****************************/
  78. template <class E, class R = void>
  79. using disable_xcomplex = std::enable_if_t<!is_gen_complex<E>::value, R>;
  80. template <class E, class R = void>
  81. using enable_xcomplex = std::enable_if_t<is_gen_complex<E>::value, R>;
  82. /*****************
  83. * enable_scalar *
  84. *****************/
  85. template <class E, class R = void>
  86. using enable_scalar = std::enable_if_t<xtl::is_arithmetic<E>::value, R>;
  87. /*******************
  88. * common_xcomplex *
  89. *******************/
  90. template <class CTR1, class CTI1, bool ieee1, class CTR2, class CTI2, bool ieee2>
  91. struct common_xcomplex
  92. {
  93. using type = xcomplex<std::common_type_t<CTR1, CTI1>, std::common_type_t<CTR2, CTI2>, ieee1 || ieee2>;
  94. };
  95. template <class CTR1, class CTI1, bool ieee1, class CTR2, class CTI2, bool ieee2>
  96. using common_xcomplex_t = typename common_xcomplex<CTR1, CTI1, ieee1, CTR2, CTI2, ieee2>::type;
  97. /**********************
  98. * temporary_xcomplex *
  99. **********************/
  100. template <class CTR, class CTI, bool ieee>
  101. struct temporary_xcomplex
  102. {
  103. using type = xcomplex<std::decay_t<CTR>, std::decay_t<CTI>, ieee>;
  104. };
  105. template <class CTR, class CTI, bool ieee>
  106. using temporary_xcomplex_t = typename temporary_xcomplex<CTR, CTI, ieee>::type;
  107. /************
  108. * xcomplex *
  109. ************/
  110. template <class CTR, class CTI, bool ieee_compliant>
  111. class xcomplex
  112. {
  113. public:
  114. static_assert(std::is_same<std::decay_t<CTR>, std::decay_t<CTI>>::value,
  115. "closure types must have the same value type");
  116. using value_type = std::common_type_t<CTR, CTI>;
  117. using self_type = xcomplex<CTR, CTI, ieee_compliant>;
  118. using temporary_type = temporary_xcomplex_t<CTR, CTI, ieee_compliant>;
  119. using real_reference = std::add_lvalue_reference_t<CTR>;
  120. using real_const_reference = std::add_lvalue_reference_t<std::add_const_t<CTR>>;
  121. using real_rvalue_reference = std::conditional_t<std::is_reference<CTR>::value, apply_cv_t<CTR, value_type>&, value_type>;
  122. using real_rvalue_const_reference = std::conditional_t<std::is_reference<CTR>::value, const value_type&, value_type>;
  123. using imag_reference = std::add_lvalue_reference_t<CTI>;
  124. using imag_const_reference = std::add_lvalue_reference_t<std::add_const_t<CTI>>;
  125. using imag_rvalue_reference = std::conditional_t<std::is_reference<CTI>::value, apply_cv_t<CTI, value_type>&, value_type>;
  126. using imag_rvalue_const_reference = std::conditional_t<std::is_reference<CTI>::value, const value_type&, value_type>;
  127. constexpr xcomplex() noexcept
  128. : m_real(), m_imag()
  129. {
  130. }
  131. template <class OCTR,
  132. std::enable_if_t<
  133. conjunction<
  134. negation<is_gen_complex<OCTR>>,
  135. std::is_constructible<CTR, OCTR&&>,
  136. std::is_convertible<OCTR&&, CTR>
  137. >::value,
  138. bool
  139. > = true>
  140. constexpr xcomplex(OCTR&& re) noexcept
  141. : m_real(std::forward<OCTR>(re)), m_imag()
  142. {
  143. }
  144. template <class OCTR,
  145. std::enable_if_t<
  146. conjunction<
  147. negation<is_gen_complex<OCTR>>,
  148. std::is_constructible<CTR, OCTR&&>,
  149. negation<std::is_convertible<OCTR&&, CTR>>
  150. >::value,
  151. bool
  152. > = true>
  153. explicit constexpr xcomplex(OCTR&& re) noexcept
  154. : m_real(std::forward<OCTR>(re)), m_imag()
  155. {
  156. }
  157. template <class OCTR, class OCTI>
  158. explicit constexpr xcomplex(OCTR&& re, OCTI&& im) noexcept
  159. : m_real(std::forward<OCTR>(re)), m_imag(std::forward<OCTI>(im))
  160. {
  161. }
  162. template <class OCTR, class OCTI, bool OB>
  163. explicit constexpr xcomplex(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept
  164. : m_real(rhs.real()), m_imag(rhs.imag())
  165. {
  166. }
  167. template <class OCTR, class OCTI, bool OB>
  168. explicit constexpr xcomplex(xcomplex<OCTR, OCTI, OB>&& rhs) noexcept
  169. : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag())
  170. {
  171. }
  172. template <class T>
  173. constexpr xcomplex(const std::complex<T>& rhs) noexcept
  174. : m_real(rhs.real()), m_imag(rhs.imag())
  175. {
  176. }
  177. template <class T>
  178. constexpr xcomplex(std::complex<T>&& rhs) noexcept
  179. : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag())
  180. {
  181. }
  182. template <class OCTR>
  183. disable_xcomplex<OCTR, self_type&> operator=(OCTR&& rhs) noexcept;
  184. template <class OCTR, class OCTI, bool OB>
  185. self_type& operator=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
  186. template <class OCTR, class OCTI, bool OB>
  187. self_type& operator=(xcomplex<OCTR, OCTI, OB>&& rhs) noexcept;
  188. operator std::complex<std::decay_t<CTR>>() const noexcept;
  189. template <class OCTR, class OCTI, bool OB>
  190. self_type& operator+=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
  191. template <class OCTR, class OCTI, bool OB>
  192. self_type& operator-=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
  193. template <class OCTR, class OCTI, bool OB>
  194. self_type& operator*=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
  195. template <class OCTR, class OCTI, bool OB>
  196. self_type& operator/=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
  197. template <class T>
  198. disable_xcomplex<T, self_type&> operator+=(const T& rhs) noexcept;
  199. template <class T>
  200. disable_xcomplex<T, self_type&> operator-=(const T& rhs) noexcept;
  201. template <class T>
  202. disable_xcomplex<T, self_type&> operator*=(const T& rhs) noexcept;
  203. template <class T>
  204. disable_xcomplex<T, self_type&> operator/=(const T& rhs) noexcept;
  205. real_reference real() & noexcept;
  206. real_rvalue_reference real() && noexcept;
  207. constexpr real_const_reference real() const & noexcept;
  208. constexpr real_rvalue_const_reference real() const && noexcept;
  209. imag_reference imag() & noexcept;
  210. imag_rvalue_reference imag() && noexcept;
  211. constexpr imag_const_reference imag() const & noexcept;
  212. constexpr imag_rvalue_const_reference imag() const && noexcept;
  213. xclosure_pointer<self_type&> operator&() & noexcept;
  214. xclosure_pointer<const self_type&> operator&() const & noexcept;
  215. xclosure_pointer<self_type> operator&() && noexcept;
  216. private:
  217. CTR m_real;
  218. CTI m_imag;
  219. };
  220. /**********************
  221. * xcomplex operators *
  222. **********************/
  223. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  224. bool operator==(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
  225. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  226. bool operator!=(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
  227. template <class OC, class OT, class CTR, class CTI, bool B>
  228. std::basic_ostream<OC, OT>& operator<<(std::basic_ostream<OC, OT>& out, const xcomplex<CTR, CTI, B>& c) noexcept;
  229. template <class CTR, class CTI, bool B>
  230. temporary_xcomplex_t<CTR, CTI, B>
  231. operator+(const xcomplex<CTR, CTI, B>& rhs) noexcept;
  232. template <class CTR, class CTI, bool B>
  233. temporary_xcomplex_t<CTR, CTI, B>
  234. operator-(const xcomplex<CTR, CTI, B>& rhs) noexcept;
  235. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  236. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  237. operator+(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
  238. template <class CTR, class CTI, bool B, class T>
  239. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  240. operator+(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
  241. template <class CTR, class CTI, bool B, class T>
  242. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  243. operator+(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
  244. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  245. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  246. operator-(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
  247. template <class CTR, class CTI, bool B, class T>
  248. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  249. operator-(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
  250. template <class CTR, class CTI, bool B, class T>
  251. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  252. operator-(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
  253. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  254. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  255. operator*(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
  256. template <class CTR, class CTI, bool B, class T>
  257. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  258. operator*(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
  259. template <class CTR, class CTI, bool B, class T>
  260. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  261. operator*(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
  262. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  263. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  264. operator/(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
  265. template <class CTR, class CTI, bool B, class T>
  266. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  267. operator/(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
  268. template <class CTR, class CTI, bool B, class T>
  269. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  270. operator/(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
  271. /*****************
  272. * real and imag *
  273. *****************/
  274. template <class E>
  275. decltype(auto) real(E&& e) noexcept;
  276. template <class E>
  277. decltype(auto) imag(E&& e) noexcept;
  278. /***************************
  279. * xcomplex free functions *
  280. ***************************/
  281. template <class CTR, class CTI, bool B>
  282. typename xcomplex<CTR, CTI, B>::value_type
  283. abs(const xcomplex<CTR, CTI, B>& rhs);
  284. template <class CTR, class CTI, bool B>
  285. typename xcomplex<CTR, CTI, B>::value_type
  286. arg(const xcomplex<CTR, CTI, B>& rhs);
  287. template <class CTR, class CTI, bool B>
  288. typename xcomplex<CTR, CTI, B>::value_type
  289. norm(const xcomplex<CTR, CTI, B>& rhs);
  290. template <class CTR, class CTI, bool B>
  291. temporary_xcomplex_t<CTR, CTI, B>
  292. conj(const xcomplex<CTR, CTI, B>& rhs);
  293. template <class CTR, class CTI, bool B>
  294. temporary_xcomplex_t<CTR, CTI, B>
  295. proj(const xcomplex<CTR, CTI, B>& rhs);
  296. /**********************************
  297. * xcomplex exponential functions *
  298. **********************************/
  299. template <class CTR, class CTI, bool B>
  300. temporary_xcomplex_t<CTR, CTI, B>
  301. exp(const xcomplex<CTR, CTI, B>& rhs);
  302. template <class CTR, class CTI, bool B>
  303. temporary_xcomplex_t<CTR, CTI, B>
  304. log(const xcomplex<CTR, CTI, B>& rhs);
  305. template <class CTR, class CTI, bool B>
  306. temporary_xcomplex_t<CTR, CTI, B>
  307. log10(const xcomplex<CTR, CTI, B>& rhs);
  308. /****************************
  309. * xcomplex power functions *
  310. ****************************/
  311. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  312. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  313. pow(const xcomplex<CTR1, CTI1, B1>& x, const xcomplex<CTR2, CTI2, B2>& y);
  314. template <class CTR, class CTI, bool B, class T>
  315. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  316. pow(const xcomplex<CTR, CTI, B>& x, const T& y);
  317. template <class CTR, class CTI, bool B, class T>
  318. enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  319. pow(const T& x, const xcomplex<CTR, CTI, B>& y);
  320. template <class CTR, class CTI, bool B>
  321. temporary_xcomplex_t<CTR, CTI, B>
  322. sqrt(const xcomplex<CTR, CTI, B>& x);
  323. /************************************
  324. * xcomplex trigonometric functions *
  325. ************************************/
  326. template <class CTR, class CTI, bool B>
  327. temporary_xcomplex_t<CTR, CTI, B>
  328. sin(const xcomplex<CTR, CTI, B>& x);
  329. template <class CTR, class CTI, bool B>
  330. temporary_xcomplex_t<CTR, CTI, B>
  331. cos(const xcomplex<CTR, CTI, B>& x);
  332. template <class CTR, class CTI, bool B>
  333. temporary_xcomplex_t<CTR, CTI, B>
  334. tan(const xcomplex<CTR, CTI, B>& x);
  335. template <class CTR, class CTI, bool B>
  336. temporary_xcomplex_t<CTR, CTI, B>
  337. asin(const xcomplex<CTR, CTI, B>& x);
  338. template <class CTR, class CTI, bool B>
  339. temporary_xcomplex_t<CTR, CTI, B>
  340. acos(const xcomplex<CTR, CTI, B>& x);
  341. template <class CTR, class CTI, bool B>
  342. temporary_xcomplex_t<CTR, CTI, B>
  343. atan(const xcomplex<CTR, CTI, B>& x);
  344. /*********************************
  345. * xcomplex hyperbolic functions *
  346. *********************************/
  347. template <class CTR, class CTI, bool B>
  348. temporary_xcomplex_t<CTR, CTI, B>
  349. sinh(const xcomplex<CTR, CTI, B>& x);
  350. template <class CTR, class CTI, bool B>
  351. temporary_xcomplex_t<CTR, CTI, B>
  352. cosh(const xcomplex<CTR, CTI, B>& x);
  353. template <class CTR, class CTI, bool B>
  354. temporary_xcomplex_t<CTR, CTI, B>
  355. tanh(const xcomplex<CTR, CTI, B>& x);
  356. template <class CTR, class CTI, bool B>
  357. temporary_xcomplex_t<CTR, CTI, B>
  358. asinh(const xcomplex<CTR, CTI, B>& x);
  359. template <class CTR, class CTI, bool B>
  360. temporary_xcomplex_t<CTR, CTI, B>
  361. acosh(const xcomplex<CTR, CTI, B>& x);
  362. template <class CTR, class CTI, bool B>
  363. temporary_xcomplex_t<CTR, CTI, B>
  364. atanh(const xcomplex<CTR, CTI, B>& x);
  365. /***************************
  366. * xcomplex implementation *
  367. ***************************/
  368. template <class CTR, class CTI, bool B>
  369. template <class OCTR>
  370. inline auto xcomplex<CTR, CTI, B>::operator=(OCTR&& rhs) noexcept -> disable_xcomplex<OCTR, self_type&>
  371. {
  372. m_real = std::forward<OCTR>(rhs);
  373. m_imag = std::decay_t<CTI>();
  374. return *this;
  375. }
  376. template <class CTR, class CTI, bool B>
  377. template <class OCTR, class OCTI, bool OB>
  378. inline auto xcomplex<CTR, CTI, B>::operator=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
  379. {
  380. m_real = rhs.m_real;
  381. m_imag = rhs.m_imag;
  382. return *this;
  383. }
  384. template <class CTR, class CTI, bool B>
  385. template <class OCTR, class OCTI, bool OB>
  386. inline auto xcomplex<CTR, CTI, B>::operator=(xcomplex<OCTR, OCTI, OB>&& rhs) noexcept -> self_type&
  387. {
  388. m_real = std::move(rhs.m_real);
  389. m_imag = std::move(rhs.m_imag);
  390. return *this;
  391. }
  392. template <class CTR, class CTI, bool B>
  393. inline xcomplex<CTR, CTI, B>::operator std::complex<std::decay_t<CTR>>() const noexcept
  394. {
  395. return std::complex<std::decay_t<CTR>>(m_real, m_imag);
  396. }
  397. template <class CTR, class CTI, bool B>
  398. template <class OCTR, class OCTI, bool OB>
  399. inline auto xcomplex<CTR, CTI, B>::operator+=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
  400. {
  401. m_real += rhs.m_real;
  402. m_imag += rhs.m_imag;
  403. return *this;
  404. }
  405. template <class CTR, class CTI, bool B>
  406. template <class OCTR, class OCTI, bool OB>
  407. inline auto xcomplex<CTR, CTI, B>::operator-=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
  408. {
  409. m_real -= rhs.m_real;
  410. m_imag -= rhs.m_imag;
  411. return *this;
  412. }
  413. namespace detail
  414. {
  415. template <bool ieee_compliant>
  416. struct xcomplex_multiplier
  417. {
  418. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  419. static auto mul(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
  420. {
  421. using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
  422. using value_type = typename return_type::value_type;
  423. value_type a = lhs.real();
  424. value_type b = lhs.imag();
  425. value_type c = rhs.real();
  426. value_type d = rhs.imag();
  427. return return_type(a*c - b*d, a*d + b*c);
  428. }
  429. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  430. static auto div(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
  431. {
  432. using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
  433. using value_type = typename return_type::value_type;
  434. value_type a = lhs.real();
  435. value_type b = lhs.imag();
  436. value_type c = rhs.real();
  437. value_type d = rhs.imag();
  438. value_type e = c*c + d*d;
  439. return return_type((c*a + d*b) / e, (c*b - d*a) / e);
  440. }
  441. };
  442. template <>
  443. struct xcomplex_multiplier<true>
  444. {
  445. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  446. static auto mul(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
  447. {
  448. using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
  449. using value_type = typename return_type::value_type;
  450. value_type a = lhs.real();
  451. value_type b = lhs.imag();
  452. value_type c = rhs.real();
  453. value_type d = rhs.imag();
  454. value_type ac = a * c;
  455. value_type bd = b * d;
  456. value_type ad = a * d;
  457. value_type bc = b * c;
  458. value_type x = ac - bd;
  459. value_type y = ad + bc;
  460. if (std::isnan(x) && std::isnan(y))
  461. {
  462. bool recalc = false;
  463. if (std::isinf(a) || std::isinf(b))
  464. {
  465. a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a);
  466. b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b);
  467. if (std::isnan(c))
  468. {
  469. c = copysign(value_type(0), c);
  470. }
  471. if (std::isnan(d))
  472. {
  473. d = copysign(value_type(0), d);
  474. }
  475. recalc = true;
  476. }
  477. if (std::isinf(c) || std::isinf(d))
  478. {
  479. c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c);
  480. d = copysign(std::isinf(c) ? value_type(1) : value_type(0), d);
  481. if (std::isnan(a))
  482. {
  483. a = copysign(value_type(0), a);
  484. }
  485. if (std::isnan(b))
  486. {
  487. b = copysign(value_type(0), b);
  488. }
  489. recalc = true;
  490. }
  491. if (!recalc && (std::isinf(ac) || std::isinf(bd) || std::isinf(ad) || std::isinf(bc)))
  492. {
  493. if (std::isnan(a))
  494. {
  495. a = copysign(value_type(0), a);
  496. }
  497. if (std::isnan(b))
  498. {
  499. b = copysign(value_type(0), b);
  500. }
  501. if (std::isnan(c))
  502. {
  503. c = copysign(value_type(0), c);
  504. }
  505. if (std::isnan(d))
  506. {
  507. d = copysign(value_type(0), d);
  508. }
  509. recalc = true;
  510. }
  511. if (recalc)
  512. {
  513. x = std::numeric_limits<value_type>::infinity() * (a * c - b * d);
  514. y = std::numeric_limits<value_type>::infinity() * (a * d + b * c);
  515. }
  516. }
  517. return return_type(x, y);
  518. }
  519. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  520. static auto div(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
  521. {
  522. using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
  523. using value_type = typename return_type::value_type;
  524. value_type a = lhs.real();
  525. value_type b = lhs.imag();
  526. value_type c = rhs.real();
  527. value_type d = rhs.imag();
  528. value_type logbw = std::logb(std::fmax(std::fabs(c), std::fabs(d)));
  529. int ilogbw = 0;
  530. if (std::isfinite(logbw))
  531. {
  532. ilogbw = static_cast<int>(logbw);
  533. c = std::scalbn(c, -ilogbw);
  534. d = std::scalbn(d, -ilogbw);
  535. }
  536. value_type denom = c*c + d*d;
  537. value_type x = std::scalbn((a*c + b*d) / denom, -ilogbw);
  538. value_type y = std::scalbn((b*c - a*d) / denom, -ilogbw);
  539. if (std::isnan(x) && std::isnan(y))
  540. {
  541. if ((denom == value_type(0)) && (!std::isnan(a) || !std::isnan(b)))
  542. {
  543. x = copysign(std::numeric_limits<value_type>::infinity(), c) * a;
  544. y = copysign(std::numeric_limits<value_type>::infinity(), c) * b;
  545. }
  546. else if ((std::isinf(a) || std::isinf(b)) && std::isfinite(c) && std::isfinite(d))
  547. {
  548. a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a);
  549. b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b);
  550. x = std::numeric_limits<value_type>::infinity() * (a*c + b*d);
  551. y = std::numeric_limits<value_type>::infinity() * (b*c - a*d);
  552. }
  553. else if (std::isinf(logbw) && logbw > value_type(0) && std::isfinite(a) && std::isfinite(b))
  554. {
  555. c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c);
  556. d = copysign(std::isinf(d) ? value_type(1) : value_type(0), d);
  557. x = value_type(0) * (a*c + b*d);
  558. y = value_type(0) * (b*c - a*d);
  559. }
  560. }
  561. return std::complex<value_type>(x, y);
  562. }
  563. };
  564. }
  565. template <class CTR, class CTI, bool B>
  566. template <class OCTR, class OCTI, bool OB>
  567. inline auto xcomplex<CTR, CTI, B>::operator*=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
  568. {
  569. *this = detail::xcomplex_multiplier<B || OB>::mul(*this, rhs);
  570. return *this;
  571. }
  572. template <class CTR, class CTI, bool B>
  573. template <class OCTR, class OCTI, bool OB>
  574. inline auto xcomplex<CTR, CTI, B>::operator/=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
  575. {
  576. *this = detail::xcomplex_multiplier<B || OB>::div(*this, rhs);
  577. return *this;
  578. }
  579. template <class CTR, class CTI, bool B>
  580. template <class T>
  581. inline auto xcomplex<CTR, CTI, B>::operator+=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
  582. {
  583. m_real += rhs;
  584. return *this;
  585. }
  586. template <class CTR, class CTI, bool B>
  587. template <class T>
  588. inline auto xcomplex<CTR, CTI, B>::operator-=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
  589. {
  590. m_real -= rhs;
  591. return *this;
  592. }
  593. template <class CTR, class CTI, bool B>
  594. template <class T>
  595. inline auto xcomplex<CTR, CTI, B>::operator*=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
  596. {
  597. m_real *= rhs;
  598. m_imag *= rhs;
  599. return *this;
  600. }
  601. template <class CTR, class CTI, bool B>
  602. template <class T>
  603. inline auto xcomplex<CTR, CTI, B>::operator/=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
  604. {
  605. m_real /= rhs;
  606. m_imag /= rhs;
  607. return *this;
  608. }
  609. template <class CTR, class CTI, bool B>
  610. auto xcomplex<CTR, CTI, B>::real() & noexcept -> real_reference
  611. {
  612. return m_real;
  613. }
  614. template <class CTR, class CTI, bool B>
  615. auto xcomplex<CTR, CTI, B>::real() && noexcept -> real_rvalue_reference
  616. {
  617. return m_real;
  618. }
  619. template <class CTR, class CTI, bool B>
  620. constexpr auto xcomplex<CTR, CTI, B>::real() const & noexcept -> real_const_reference
  621. {
  622. return m_real;
  623. }
  624. template <class CTR, class CTI, bool B>
  625. constexpr auto xcomplex<CTR, CTI, B>::real() const && noexcept -> real_rvalue_const_reference
  626. {
  627. return m_real;
  628. }
  629. template <class CTR, class CTI, bool B>
  630. auto xcomplex<CTR, CTI, B>::imag() & noexcept -> imag_reference
  631. {
  632. return m_imag;
  633. }
  634. template <class CTR, class CTI, bool B>
  635. auto xcomplex<CTR, CTI, B>::imag() && noexcept -> imag_rvalue_reference
  636. {
  637. return m_imag;
  638. }
  639. template <class CTR, class CTI, bool B>
  640. constexpr auto xcomplex<CTR, CTI, B>::imag() const & noexcept -> imag_const_reference
  641. {
  642. return m_imag;
  643. }
  644. template <class CTR, class CTI, bool B>
  645. constexpr auto xcomplex<CTR, CTI, B>::imag() const && noexcept -> imag_rvalue_const_reference
  646. {
  647. return m_imag;
  648. }
  649. template <class CTR, class CTI, bool B>
  650. inline auto xcomplex<CTR, CTI, B>::operator&() & noexcept -> xclosure_pointer<self_type&>
  651. {
  652. return xclosure_pointer<self_type&>(*this);
  653. }
  654. template <class CTR, class CTI, bool B>
  655. inline auto xcomplex<CTR, CTI, B>::operator&() const & noexcept -> xclosure_pointer<const self_type&>
  656. {
  657. return xclosure_pointer<const self_type&>(*this);
  658. }
  659. template <class CTR, class CTI, bool B>
  660. inline auto xcomplex<CTR, CTI, B>::operator&() && noexcept -> xclosure_pointer<self_type>
  661. {
  662. return xclosure_pointer<self_type>(std::move(*this));
  663. }
  664. /*************************************
  665. * xcomplex operators implementation *
  666. *************************************/
  667. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  668. inline bool operator==(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
  669. {
  670. return lhs.real() == rhs.real() && lhs.imag() == rhs.imag();
  671. }
  672. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  673. inline bool operator!=(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
  674. {
  675. return !(lhs == rhs);
  676. }
  677. template <class OC, class OT, class CTR, class CTI, bool B>
  678. inline std::basic_ostream<OC, OT>& operator<<(std::basic_ostream<OC, OT>& out, const xcomplex<CTR, CTI, B>& c) noexcept
  679. {
  680. out << "(" << c.real() << "," << c.imag() << ")";
  681. return out;
  682. }
  683. #ifdef __CLING__
  684. template <class CTR, class CTI, bool B>
  685. nlohmann::json mime_bundle_repr(const xcomplex<CTR, CTI, B>& c)
  686. {
  687. auto bundle = nlohmann::json::object();
  688. std::stringstream tmp;
  689. tmp << c;
  690. bundle["text/plain"] = tmp.str();
  691. return bundle;
  692. }
  693. #endif
  694. template <class CTR, class CTI, bool B>
  695. inline temporary_xcomplex_t<CTR, CTI, B>
  696. operator+(const xcomplex<CTR, CTI, B>& rhs) noexcept
  697. {
  698. return rhs;
  699. }
  700. template <class CTR, class CTI, bool B>
  701. inline temporary_xcomplex_t<CTR, CTI, B>
  702. operator-(const xcomplex<CTR, CTI, B>& rhs) noexcept
  703. {
  704. return temporary_xcomplex_t<CTR, CTI, B>(-rhs.real(), -rhs.imag());
  705. }
  706. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  707. inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  708. operator+(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
  709. {
  710. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
  711. res += rhs;
  712. return res;
  713. }
  714. template <class CTR, class CTI, bool B, class T>
  715. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  716. operator+(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
  717. {
  718. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  719. res += rhs;
  720. return res;
  721. }
  722. template <class CTR, class CTI, bool B, class T>
  723. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  724. operator+(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
  725. {
  726. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  727. res += rhs;
  728. return res;
  729. }
  730. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  731. inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  732. operator-(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
  733. {
  734. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
  735. res -= rhs;
  736. return res;
  737. }
  738. template <class CTR, class CTI, bool B, class T>
  739. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  740. operator-(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
  741. {
  742. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  743. res -= rhs;
  744. return res;
  745. }
  746. template <class CTR, class CTI, bool B, class T>
  747. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  748. operator-(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
  749. {
  750. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  751. res -= rhs;
  752. return res;
  753. }
  754. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  755. inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  756. operator*(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
  757. {
  758. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
  759. res *= rhs;
  760. return res;
  761. }
  762. template <class CTR, class CTI, bool B, class T>
  763. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  764. operator*(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
  765. {
  766. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  767. res *= rhs;
  768. return res;
  769. }
  770. template <class CTR, class CTI, bool B, class T>
  771. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  772. operator*(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
  773. {
  774. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  775. res *= rhs;
  776. return res;
  777. }
  778. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  779. inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  780. operator/(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
  781. {
  782. common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
  783. res /= rhs;
  784. return res;
  785. }
  786. template <class CTR, class CTI, bool B, class T>
  787. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  788. operator/(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
  789. {
  790. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  791. res /= rhs;
  792. return res;
  793. }
  794. template <class CTR, class CTI, bool B, class T>
  795. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  796. operator/(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
  797. {
  798. temporary_xcomplex_t<CTR, CTI, B> res(lhs);
  799. res /= rhs;
  800. return res;
  801. }
  802. /***************************
  803. * xcomplex free functions *
  804. ***************************/
  805. template <class CTR, class CTI, bool B>
  806. inline typename xcomplex<CTR, CTI, B>::value_type
  807. abs(const xcomplex<CTR, CTI, B>& rhs)
  808. {
  809. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  810. return std::abs(std::complex<value_type>(rhs));
  811. }
  812. template <class CTR, class CTI, bool B>
  813. inline typename xcomplex<CTR, CTI, B>::value_type
  814. arg(const xcomplex<CTR, CTI, B>& rhs)
  815. {
  816. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  817. return std::arg(std::complex<value_type>(rhs));
  818. }
  819. template <class CTR, class CTI, bool B>
  820. inline typename xcomplex<CTR, CTI, B>::value_type
  821. norm(const xcomplex<CTR, CTI, B>& rhs)
  822. {
  823. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  824. return std::norm(std::complex<value_type>(rhs));
  825. }
  826. template <class CTR, class CTI, bool B>
  827. inline temporary_xcomplex_t<CTR, CTI, B>
  828. conj(const xcomplex<CTR, CTI, B>& rhs)
  829. {
  830. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  831. return std::conj(std::complex<value_type>(rhs));
  832. }
  833. template <class CTR, class CTI, bool B>
  834. inline temporary_xcomplex_t<CTR, CTI, B>
  835. proj(const xcomplex<CTR, CTI, B>& rhs)
  836. {
  837. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  838. return std::proj(std::complex<value_type>(rhs));
  839. }
  840. /*************************************************
  841. * xcomplex exponential functions implementation *
  842. *************************************************/
  843. template <class CTR, class CTI, bool B>
  844. inline temporary_xcomplex_t<CTR, CTI, B>
  845. exp(const xcomplex<CTR, CTI, B>& rhs)
  846. {
  847. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  848. return std::exp(std::complex<value_type>(rhs));
  849. }
  850. template <class CTR, class CTI, bool B>
  851. inline temporary_xcomplex_t<CTR, CTI, B>
  852. log(const xcomplex<CTR, CTI, B>& rhs)
  853. {
  854. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  855. return std::log(std::complex<value_type>(rhs));
  856. }
  857. template <class CTR, class CTI, bool B>
  858. inline temporary_xcomplex_t<CTR, CTI, B>
  859. log10(const xcomplex<CTR, CTI, B>& rhs)
  860. {
  861. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  862. return std::log10(std::complex<value_type>(rhs));
  863. }
  864. /*******************************************
  865. * xcomplex power functions implementation *
  866. *******************************************/
  867. template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
  868. inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
  869. pow(const xcomplex<CTR1, CTI1, B1>& x, const xcomplex<CTR2, CTI2, B2>& y)
  870. {
  871. using value_type1 = typename xcomplex<CTR1, CTI1, B1>::value_type;
  872. using value_type2 = typename xcomplex<CTR2, CTI2, B2>::value_type;
  873. return std::pow(std::complex<value_type1>(x), std::complex<value_type2>(y));
  874. }
  875. template <class CTR, class CTI, bool B, class T>
  876. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  877. pow(const xcomplex<CTR, CTI, B>& x, const T& y)
  878. {
  879. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  880. return std::pow(std::complex<value_type>(x), y);
  881. }
  882. template <class CTR, class CTI, bool B, class T>
  883. inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
  884. pow(const T& x, const xcomplex<CTR, CTI, B>& y)
  885. {
  886. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  887. return std::pow(x, std::complex<value_type>(y));
  888. }
  889. template <class CTR, class CTI, bool B>
  890. inline temporary_xcomplex_t<CTR, CTI, B>
  891. sqrt(const xcomplex<CTR, CTI, B>& x)
  892. {
  893. using value_type = typename xcomplex<CTR, CTI, B>::value_type;
  894. return std::sqrt(std::complex<value_type>(x));
  895. }
  896. /***************************************************
  897. * xcomplex trigonometric functions implementation *
  898. ***************************************************/
  899. template <class CTR, class CTI, bool B>
  900. inline temporary_xcomplex_t<CTR, CTI, B>
  901. sin(const xcomplex<CTR, CTI, B>& x)
  902. {
  903. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  904. return std::sin(std::complex<value_type>(x));
  905. }
  906. template <class CTR, class CTI, bool B>
  907. inline temporary_xcomplex_t<CTR, CTI, B>
  908. cos(const xcomplex<CTR, CTI, B>& x)
  909. {
  910. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  911. return std::cos(std::complex<value_type>(x));
  912. }
  913. template <class CTR, class CTI, bool B>
  914. inline temporary_xcomplex_t<CTR, CTI, B>
  915. tan(const xcomplex<CTR, CTI, B>& x)
  916. {
  917. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  918. return std::tan(std::complex<value_type>(x));
  919. }
  920. template <class CTR, class CTI, bool B>
  921. inline temporary_xcomplex_t<CTR, CTI, B>
  922. asin(const xcomplex<CTR, CTI, B>& x)
  923. {
  924. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  925. return std::asin(std::complex<value_type>(x));
  926. }
  927. template <class CTR, class CTI, bool B>
  928. inline temporary_xcomplex_t<CTR, CTI, B>
  929. acos(const xcomplex<CTR, CTI, B>& x)
  930. {
  931. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  932. return std::acos(std::complex<value_type>(x));
  933. }
  934. template <class CTR, class CTI, bool B>
  935. inline temporary_xcomplex_t<CTR, CTI, B>
  936. atan(const xcomplex<CTR, CTI, B>& x)
  937. {
  938. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  939. return std::atan(std::complex<value_type>(x));
  940. }
  941. /************************************************
  942. * xcomplex hyperbolic functions implementation *
  943. ************************************************/
  944. template <class CTR, class CTI, bool B>
  945. inline temporary_xcomplex_t<CTR, CTI, B>
  946. sinh(const xcomplex<CTR, CTI, B>& x)
  947. {
  948. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  949. return std::sinh(std::complex<value_type>(x));
  950. }
  951. template <class CTR, class CTI, bool B>
  952. inline temporary_xcomplex_t<CTR, CTI, B>
  953. cosh(const xcomplex<CTR, CTI, B>& x)
  954. {
  955. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  956. return std::cosh(std::complex<value_type>(x));
  957. }
  958. template <class CTR, class CTI, bool B>
  959. inline temporary_xcomplex_t<CTR, CTI, B>
  960. tanh(const xcomplex<CTR, CTI, B>& x)
  961. {
  962. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  963. return std::tanh(std::complex<value_type>(x));
  964. }
  965. template <class CTR, class CTI, bool B>
  966. inline temporary_xcomplex_t<CTR, CTI, B>
  967. asinh(const xcomplex<CTR, CTI, B>& x)
  968. {
  969. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  970. return std::asinh(std::complex<value_type>(x));
  971. }
  972. template <class CTR, class CTI, bool B>
  973. inline temporary_xcomplex_t<CTR, CTI, B>
  974. acosh(const xcomplex<CTR, CTI, B>& x)
  975. {
  976. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  977. return std::acosh(std::complex<value_type>(x));
  978. }
  979. template <class CTR, class CTI, bool B>
  980. inline temporary_xcomplex_t<CTR, CTI, B>
  981. atanh(const xcomplex<CTR, CTI, B>& x)
  982. {
  983. using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
  984. return std::atanh(std::complex<value_type>(x));
  985. }
  986. /*********************************
  987. * forward_offset implementation *
  988. *********************************/
  989. namespace detail
  990. {
  991. template <class T, class M>
  992. struct forward_type
  993. {
  994. using type = apply_cv_t<T, M>;
  995. };
  996. template <class T, class M>
  997. struct forward_type<T&, M>
  998. {
  999. using type = apply_cv_t<T, M>&;
  1000. };
  1001. template <class T, class M>
  1002. using forward_type_t = typename forward_type<T, M>::type;
  1003. }
  1004. template <class M, std::size_t I, class T>
  1005. constexpr detail::forward_type_t<T, M> forward_offset(T&& v) noexcept
  1006. {
  1007. using forward_type = detail::forward_type_t<T, M>;
  1008. using cv_value_type = std::remove_reference_t<forward_type>;
  1009. using byte_type = apply_cv_t<std::remove_reference_t<T>, char>;
  1010. return static_cast<forward_type>(
  1011. *reinterpret_cast<cv_value_type*>(
  1012. reinterpret_cast<byte_type*>(&v) + I
  1013. )
  1014. );
  1015. }
  1016. /**********************************************
  1017. * forward_real & forward_imag implementation *
  1018. **********************************************/
  1019. // forward_real
  1020. template <class T>
  1021. auto forward_real(T&& v)
  1022. -> std::enable_if_t<!is_gen_complex<T>::value, detail::forward_type_t<T, T>> // real case -> forward
  1023. {
  1024. return static_cast<detail::forward_type_t<T, T>>(v);
  1025. }
  1026. template <class T>
  1027. auto forward_real(T&& v)
  1028. -> std::enable_if_t<is_complex<T>::value, detail::forward_type_t<T, typename std::decay_t<T>::value_type>> // complex case -> forward the real part
  1029. {
  1030. return forward_offset<typename std::decay_t<T>::value_type, 0>(v);
  1031. }
  1032. template <class T>
  1033. auto forward_real(T&& v)
  1034. -> std::enable_if_t<is_xcomplex<T>::value, decltype(std::forward<T>(v).real())>
  1035. {
  1036. return std::forward<T>(v).real();
  1037. }
  1038. // forward_imag
  1039. template <class T>
  1040. auto forward_imag(T &&)
  1041. -> std::enable_if_t<!is_gen_complex<T>::value, std::decay_t<T>> // real case -> always return 0 by value
  1042. {
  1043. return 0;
  1044. }
  1045. template <class T>
  1046. auto forward_imag(T&& v)
  1047. -> std::enable_if_t<is_complex<T>::value, detail::forward_type_t<T, typename std::decay_t<T>::value_type>> // complex case -> forwards the imaginary part
  1048. {
  1049. using real_type = typename std::decay_t<T>::value_type;
  1050. return forward_offset<real_type, sizeof(real_type)>(v);
  1051. }
  1052. template <class T>
  1053. auto forward_imag(T&& v)
  1054. -> std::enable_if_t<is_xcomplex<T>::value, decltype(std::forward<T>(v).imag())>
  1055. {
  1056. return std::forward<T>(v).imag();
  1057. }
  1058. /******************************
  1059. * real & imag implementation *
  1060. ******************************/
  1061. template <class E>
  1062. inline decltype(auto) real(E&& e) noexcept
  1063. {
  1064. return forward_real(std::forward<E>(e));
  1065. }
  1066. template <class E>
  1067. inline decltype(auto) imag(E&& e) noexcept
  1068. {
  1069. return forward_imag(std::forward<E>(e));
  1070. }
  1071. /**********************
  1072. * complex_value_type *
  1073. **********************/
  1074. template <class T>
  1075. struct complex_value_type
  1076. {
  1077. using type = T;
  1078. };
  1079. template <class T>
  1080. struct complex_value_type<std::complex<T>>
  1081. {
  1082. using type = T;
  1083. };
  1084. template <class CTR, class CTI, bool B>
  1085. struct complex_value_type<xcomplex<CTR, CTI, B>>
  1086. {
  1087. using type = xcomplex<CTR, CTI, B>;
  1088. };
  1089. template <class T>
  1090. using complex_value_type_t = typename complex_value_type<T>::type;
  1091. /******************************************************
  1092. * operator overloads for complex and closure wrapper *
  1093. *****************************************************/
  1094. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1095. std::complex<C> operator+(const std::complex<C>& c, const T& t)
  1096. {
  1097. std::complex<C> result(c);
  1098. result += t;
  1099. return result;
  1100. }
  1101. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1102. std::complex<C> operator+(const T& t, const std::complex<C>& c)
  1103. {
  1104. std::complex<C> result(t);
  1105. result += c;
  1106. return result;
  1107. }
  1108. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1109. std::complex<C> operator-(const std::complex<C>& c, const T& t)
  1110. {
  1111. std::complex<C> result(c);
  1112. result -= t;
  1113. return result;
  1114. }
  1115. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1116. std::complex<C> operator-(const T& t, const std::complex<C>& c)
  1117. {
  1118. std::complex<C> result(t);
  1119. result -= c;
  1120. return result;
  1121. }
  1122. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1123. std::complex<C> operator*(const std::complex<C>& c, const T& t)
  1124. {
  1125. std::complex<C> result(c);
  1126. result *= t;
  1127. return result;
  1128. }
  1129. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1130. std::complex<C> operator*(const T& t, const std::complex<C>& c)
  1131. {
  1132. std::complex<C> result(t);
  1133. result *= c;
  1134. return result;
  1135. }
  1136. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1137. std::complex<C> operator/(const std::complex<C>& c, const T& t)
  1138. {
  1139. std::complex<C> result(c);
  1140. result /= t;
  1141. return result;
  1142. }
  1143. template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
  1144. std::complex<C> operator/(const T& t, const std::complex<C>& c)
  1145. {
  1146. std::complex<C> result(t);
  1147. result /= c;
  1148. return result;
  1149. }
  1150. }
  1151. #endif