complex_adaptor.hpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2018 John Maddock. Distributed under the Boost
  3. // Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MP_COMPLEX_ADAPTOR_HPP
  6. #define BOOST_MP_COMPLEX_ADAPTOR_HPP
  7. #include <boost/multiprecision/number.hpp>
  8. #include <cstdint>
  9. #include <boost/multiprecision/detail/digits.hpp>
  10. #include <boost/multiprecision/detail/hash.hpp>
  11. #include <boost/multiprecision/detail/no_exceptions_support.hpp>
  12. #include <cmath>
  13. #include <algorithm>
  14. #include <complex>
  15. namespace boost {
  16. namespace multiprecision {
  17. namespace backends {
  18. template <class Backend>
  19. struct complex_adaptor
  20. {
  21. protected:
  22. Backend m_real, m_imag;
  23. public:
  24. Backend& real_data()
  25. {
  26. return m_real;
  27. }
  28. const Backend& real_data() const
  29. {
  30. return m_real;
  31. }
  32. Backend& imag_data()
  33. {
  34. return m_imag;
  35. }
  36. const Backend& imag_data() const
  37. {
  38. return m_imag;
  39. }
  40. using signed_types = typename Backend::signed_types ;
  41. using unsigned_types = typename Backend::unsigned_types;
  42. using float_types = typename Backend::float_types ;
  43. using exponent_type = typename Backend::exponent_type ;
  44. complex_adaptor() {}
  45. complex_adaptor(const complex_adaptor& o) : m_real(o.real_data()), m_imag(o.imag_data()) {}
  46. // Rvalue construct:
  47. complex_adaptor(complex_adaptor&& o) : m_real(std::move(o.real_data())), m_imag(std::move(o.imag_data()))
  48. {}
  49. complex_adaptor(const Backend& val)
  50. : m_real(val)
  51. {}
  52. template <class T>
  53. complex_adaptor(const T& val, const typename std::enable_if<std::is_convertible<T, Backend>::value>::type* = nullptr)
  54. : m_real(val)
  55. {}
  56. complex_adaptor(const std::complex<float>& val)
  57. {
  58. m_real = (long double)val.real();
  59. m_imag = (long double)val.imag();
  60. }
  61. complex_adaptor(const std::complex<double>& val)
  62. {
  63. m_real = (long double)val.real();
  64. m_imag = (long double)val.imag();
  65. }
  66. complex_adaptor(const std::complex<long double>& val)
  67. {
  68. m_real = val.real();
  69. m_imag = val.imag();
  70. }
  71. template <class T, class U>
  72. complex_adaptor(const T& a, const U& b, typename std::enable_if<std::is_constructible<Backend, T const&>::value&& std::is_constructible<Backend, U const&>::value>::type const* = nullptr)
  73. : m_real(a), m_imag(b) {}
  74. template <class T, class U>
  75. complex_adaptor(T&& a, const U& b, typename std::enable_if<std::is_constructible<Backend, T>::value&& std::is_constructible<Backend, U>::value>::type const* = nullptr)
  76. : m_real(static_cast<T&&>(a)), m_imag(b) {}
  77. template <class T, class U>
  78. complex_adaptor(T&& a, U&& b, typename std::enable_if<std::is_constructible<Backend, T>::value&& std::is_constructible<Backend, U>::value>::type const* = nullptr)
  79. : m_real(static_cast<T&&>(a)), m_imag(static_cast<U&&>(b)) {}
  80. template <class T, class U>
  81. complex_adaptor(const T& a, U&& b, typename std::enable_if<std::is_constructible<Backend, T>::value&& std::is_constructible<Backend, U>::value>::type const* = nullptr)
  82. : m_real(a), m_imag(static_cast<U&&>(b)) {}
  83. complex_adaptor& operator=(const complex_adaptor& o)
  84. {
  85. m_real = o.real_data();
  86. m_imag = o.imag_data();
  87. return *this;
  88. }
  89. // rvalue assign:
  90. complex_adaptor& operator=(complex_adaptor&& o) noexcept
  91. {
  92. m_real = std::move(o.real_data());
  93. m_imag = std::move(o.imag_data());
  94. return *this;
  95. }
  96. template <class V>
  97. typename std::enable_if<std::is_assignable<Backend, V>::value, complex_adaptor&>::type operator=(const V& v)
  98. {
  99. using ui_type = typename std::tuple_element<0, unsigned_types>::type;
  100. m_real = v;
  101. m_imag = ui_type(0u);
  102. return *this;
  103. }
  104. template <class T>
  105. complex_adaptor& operator=(const std::complex<T>& val)
  106. {
  107. m_real = (long double)val.real();
  108. m_imag = (long double)val.imag();
  109. return *this;
  110. }
  111. complex_adaptor& operator=(const char* s)
  112. {
  113. using ui_type = typename std::tuple_element<0, unsigned_types>::type;
  114. ui_type zero = 0u;
  115. using default_ops::eval_fpclassify;
  116. if (s && (*s == '('))
  117. {
  118. std::string part;
  119. const char* p = ++s;
  120. while (*p && (*p != ',') && (*p != ')'))
  121. ++p;
  122. part.assign(s, p);
  123. if (part.size())
  124. real_data() = part.c_str();
  125. else
  126. real_data() = zero;
  127. s = p;
  128. if (*p && (*p != ')'))
  129. {
  130. ++p;
  131. while (*p && (*p != ')'))
  132. ++p;
  133. part.assign(s + 1, p);
  134. }
  135. else
  136. part.erase();
  137. if (part.size())
  138. imag_data() = part.c_str();
  139. else
  140. imag_data() = zero;
  141. if (eval_fpclassify(imag_data()) == static_cast<int>(FP_NAN))
  142. {
  143. real_data() = imag_data();
  144. }
  145. }
  146. else
  147. {
  148. real_data() = s;
  149. imag_data() = zero;
  150. }
  151. return *this;
  152. }
  153. int compare(const complex_adaptor& o) const
  154. {
  155. // They are either equal or not:
  156. return (m_real.compare(o.real_data()) == 0) && (m_imag.compare(o.imag_data()) == 0) ? 0 : 1;
  157. }
  158. template <class T>
  159. int compare(const T& val) const
  160. {
  161. using default_ops::eval_is_zero;
  162. return (m_real.compare(val) == 0) && eval_is_zero(m_imag) ? 0 : 1;
  163. }
  164. void swap(complex_adaptor& o)
  165. {
  166. real_data().swap(o.real_data());
  167. imag_data().swap(o.imag_data());
  168. }
  169. std::string str(std::streamsize dig, std::ios_base::fmtflags f) const
  170. {
  171. using default_ops::eval_is_zero;
  172. if (eval_is_zero(imag_data()))
  173. return m_real.str(dig, f);
  174. return "(" + m_real.str(dig, f) + "," + m_imag.str(dig, f) + ")";
  175. }
  176. void negate()
  177. {
  178. m_real.negate();
  179. m_imag.negate();
  180. }
  181. //
  182. // Default precision:
  183. //
  184. static BOOST_MP_CXX14_CONSTEXPR unsigned default_precision() noexcept
  185. {
  186. return Backend::default_precision();
  187. }
  188. static BOOST_MP_CXX14_CONSTEXPR void default_precision(unsigned digits10)
  189. {
  190. Backend::default_precision(digits10);
  191. Backend::thread_default_precision(digits10);
  192. }
  193. static BOOST_MP_CXX14_CONSTEXPR unsigned thread_default_precision() noexcept
  194. {
  195. return Backend::thread_default_precision();
  196. }
  197. static BOOST_MP_CXX14_CONSTEXPR void thread_default_precision(unsigned digits10)
  198. {
  199. Backend::thread_default_precision(digits10);
  200. }
  201. BOOST_MP_CXX14_CONSTEXPR unsigned precision() const noexcept
  202. {
  203. return m_real.precision();
  204. }
  205. BOOST_MP_CXX14_CONSTEXPR void precision(unsigned digits10)
  206. {
  207. m_real.precision(digits10);
  208. m_imag.precision(digits10);
  209. }
  210. //
  211. // Variable precision options:
  212. //
  213. static constexpr variable_precision_options default_variable_precision_options()noexcept
  214. {
  215. return Backend::default_variable_precision_options();
  216. }
  217. static constexpr variable_precision_options thread_default_variable_precision_options()noexcept
  218. {
  219. return Backend::thread_default_variable_precision_options();
  220. }
  221. static BOOST_MP_CXX14_CONSTEXPR void default_variable_precision_options(variable_precision_options opts)
  222. {
  223. Backend::default_variable_precision_options(opts);
  224. Backend::thread_default_variable_precision_options(opts);
  225. }
  226. static BOOST_MP_CXX14_CONSTEXPR void thread_default_variable_precision_options(variable_precision_options opts)
  227. {
  228. Backend::thread_default_variable_precision_options(opts);
  229. }
  230. };
  231. template <class Backend, class T>
  232. inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_eq(const complex_adaptor<Backend>& a, const T& b) noexcept
  233. {
  234. return a.compare(b) == 0;
  235. }
  236. template <class Backend>
  237. inline void eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
  238. {
  239. eval_add(result.real_data(), o.real_data());
  240. eval_add(result.imag_data(), o.imag_data());
  241. }
  242. template <class Backend>
  243. inline void eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
  244. {
  245. eval_subtract(result.real_data(), o.real_data());
  246. eval_subtract(result.imag_data(), o.imag_data());
  247. }
  248. template <class Backend>
  249. inline void eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
  250. {
  251. Backend t1, t2, t3;
  252. eval_multiply(t1, result.real_data(), o.real_data());
  253. eval_multiply(t2, result.imag_data(), o.imag_data());
  254. eval_subtract(t3, t1, t2);
  255. eval_multiply(t1, result.real_data(), o.imag_data());
  256. eval_multiply(t2, result.imag_data(), o.real_data());
  257. eval_add(t1, t2);
  258. result.real_data() = std::move(t3);
  259. result.imag_data() = std::move(t1);
  260. }
  261. template <class Backend>
  262. inline void eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& z)
  263. {
  264. // (a+bi) / (c + di)
  265. using default_ops::eval_add;
  266. using default_ops::eval_divide;
  267. using default_ops::eval_fabs;
  268. using default_ops::eval_is_zero;
  269. using default_ops::eval_multiply;
  270. using default_ops::eval_subtract;
  271. Backend t1, t2;
  272. //
  273. // Backup sign bits for later, so we can fix up
  274. // signed zeros at the end:
  275. //
  276. int a_sign = eval_signbit(result.real_data());
  277. int b_sign = eval_signbit(result.imag_data());
  278. int c_sign = eval_signbit(z.real_data());
  279. int d_sign = eval_signbit(z.imag_data());
  280. if (eval_is_zero(z.imag_data()))
  281. {
  282. eval_divide(result.real_data(), z.real_data());
  283. eval_divide(result.imag_data(), z.real_data());
  284. }
  285. else
  286. {
  287. eval_fabs(t1, z.real_data());
  288. eval_fabs(t2, z.imag_data());
  289. if (t1.compare(t2) < 0)
  290. {
  291. eval_divide(t1, z.real_data(), z.imag_data()); // t1 = c/d
  292. eval_multiply(t2, z.real_data(), t1);
  293. eval_add(t2, z.imag_data()); // denom = c * (c/d) + d
  294. Backend t_real(result.real_data());
  295. // real = (a * (c/d) + b) / (denom)
  296. eval_multiply(result.real_data(), t1);
  297. eval_add(result.real_data(), result.imag_data());
  298. eval_divide(result.real_data(), t2);
  299. // imag = (b * c/d - a) / denom
  300. eval_multiply(result.imag_data(), t1);
  301. eval_subtract(result.imag_data(), t_real);
  302. eval_divide(result.imag_data(), t2);
  303. }
  304. else
  305. {
  306. eval_divide(t1, z.imag_data(), z.real_data()); // t1 = d/c
  307. eval_multiply(t2, z.imag_data(), t1);
  308. eval_add(t2, z.real_data()); // denom = d * d/c + c
  309. Backend r_t(result.real_data());
  310. Backend i_t(result.imag_data());
  311. // real = (b * d/c + a) / denom
  312. eval_multiply(result.real_data(), result.imag_data(), t1);
  313. eval_add(result.real_data(), r_t);
  314. eval_divide(result.real_data(), t2);
  315. // imag = (-a * d/c + b) / denom
  316. eval_multiply(result.imag_data(), r_t, t1);
  317. result.imag_data().negate();
  318. eval_add(result.imag_data(), i_t);
  319. eval_divide(result.imag_data(), t2);
  320. }
  321. }
  322. //
  323. // Finish off by fixing up signed zeros.
  324. //
  325. // This sets the signs "as if" we had evaluated the result using:
  326. //
  327. // real = (ac + bd) / (c^2 + d^2)
  328. // imag = (bc - ad) / (c^2 + d^2)
  329. //
  330. // ie a zero is negative only if the two parts of the numerator
  331. // are both negative and zero.
  332. //
  333. if (eval_is_zero(result.real_data()))
  334. {
  335. int r_sign = eval_signbit(result.real_data());
  336. int r_required = (a_sign != c_sign) && (b_sign != d_sign);
  337. if (r_required != r_sign)
  338. result.real_data().negate();
  339. }
  340. if (eval_is_zero(result.imag_data()))
  341. {
  342. int i_sign = eval_signbit(result.imag_data());
  343. int i_required = (b_sign != c_sign) && (a_sign == d_sign);
  344. if (i_required != i_sign)
  345. result.imag_data().negate();
  346. }
  347. }
  348. template <class Backend, class T>
  349. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const T& scalar)
  350. {
  351. using default_ops::eval_add;
  352. eval_add(result.real_data(), scalar);
  353. }
  354. template <class Backend, class T>
  355. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const T& scalar)
  356. {
  357. using default_ops::eval_subtract;
  358. eval_subtract(result.real_data(), scalar);
  359. }
  360. template <class Backend, class T>
  361. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const T& scalar)
  362. {
  363. using default_ops::eval_multiply;
  364. eval_multiply(result.real_data(), scalar);
  365. eval_multiply(result.imag_data(), scalar);
  366. }
  367. template <class Backend, class T>
  368. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const T& scalar)
  369. {
  370. using default_ops::eval_divide;
  371. eval_divide(result.real_data(), scalar);
  372. eval_divide(result.imag_data(), scalar);
  373. }
  374. // Optimised 3 arg versions:
  375. template <class Backend, class T>
  376. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  377. {
  378. using default_ops::eval_add;
  379. eval_add(result.real_data(), a.real_data(), scalar);
  380. result.imag_data() = a.imag_data();
  381. }
  382. template <class Backend, class T>
  383. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  384. {
  385. using default_ops::eval_subtract;
  386. eval_subtract(result.real_data(), a.real_data(), scalar);
  387. result.imag_data() = a.imag_data();
  388. }
  389. template <class Backend, class T>
  390. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  391. {
  392. using default_ops::eval_multiply;
  393. eval_multiply(result.real_data(), a.real_data(), scalar);
  394. eval_multiply(result.imag_data(), a.imag_data(), scalar);
  395. }
  396. template <class Backend, class T>
  397. inline typename std::enable_if< !std::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  398. {
  399. using default_ops::eval_divide;
  400. eval_divide(result.real_data(), a.real_data(), scalar);
  401. eval_divide(result.imag_data(), a.imag_data(), scalar);
  402. }
  403. template <class Backend>
  404. inline bool eval_is_zero(const complex_adaptor<Backend>& val) noexcept
  405. {
  406. using default_ops::eval_is_zero;
  407. return eval_is_zero(val.real_data()) && eval_is_zero(val.imag_data());
  408. }
  409. template <class Backend>
  410. inline int eval_get_sign(const complex_adaptor<Backend>&)
  411. {
  412. static_assert(sizeof(Backend) == UINT_MAX, "Complex numbers have no sign bit."); // designed to always fail
  413. return 0;
  414. }
  415. template <class Result, class Backend>
  416. inline typename std::enable_if< !boost::multiprecision::detail::is_complex<Result>::value>::type eval_convert_to(Result* result, const complex_adaptor<Backend>& val)
  417. {
  418. using default_ops::eval_convert_to;
  419. using default_ops::eval_is_zero;
  420. if (!eval_is_zero(val.imag_data()))
  421. {
  422. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar."));
  423. }
  424. eval_convert_to(result, val.real_data());
  425. }
  426. template <class Backend, class T>
  427. inline void assign_components(complex_adaptor<Backend>& result, const T& a, const T& b)
  428. {
  429. result.real_data() = a;
  430. result.imag_data() = b;
  431. }
  432. //
  433. // Native non-member operations:
  434. //
  435. template <class Backend>
  436. inline void eval_sqrt(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& val)
  437. {
  438. // Use the following:
  439. // sqrt(z) = (s, zi / 2s) for zr >= 0
  440. // (|zi| / 2s, +-s) for zr < 0
  441. // where s = sqrt{ [ |zr| + sqrt(zr^2 + zi^2) ] / 2 },
  442. // and the +- sign is the same as the sign of zi.
  443. using default_ops::eval_abs;
  444. using default_ops::eval_add;
  445. using default_ops::eval_divide;
  446. using default_ops::eval_get_sign;
  447. using default_ops::eval_is_zero;
  448. if (eval_is_zero(val.imag_data()) && (eval_get_sign(val.real_data()) >= 0))
  449. {
  450. constexpr typename std::tuple_element<0, typename Backend::unsigned_types>::type zero = 0u;
  451. eval_sqrt(result.real_data(), val.real_data());
  452. result.imag_data() = zero;
  453. return;
  454. }
  455. const bool __my_real_part_is_neg(eval_get_sign(val.real_data()) < 0);
  456. Backend __my_real_part_fabs(val.real_data());
  457. if (__my_real_part_is_neg)
  458. __my_real_part_fabs.negate();
  459. Backend t, __my_sqrt_part;
  460. eval_abs(__my_sqrt_part, val);
  461. eval_add(__my_sqrt_part, __my_real_part_fabs);
  462. eval_ldexp(t, __my_sqrt_part, -1);
  463. eval_sqrt(__my_sqrt_part, t);
  464. if (__my_real_part_is_neg == false)
  465. {
  466. eval_ldexp(t, __my_sqrt_part, 1);
  467. eval_divide(result.imag_data(), val.imag_data(), t);
  468. result.real_data() = __my_sqrt_part;
  469. }
  470. else
  471. {
  472. const bool __my_imag_part_is_neg(eval_get_sign(val.imag_data()) < 0);
  473. Backend __my_imag_part_fabs(val.imag_data());
  474. if (__my_imag_part_is_neg)
  475. __my_imag_part_fabs.negate();
  476. eval_ldexp(t, __my_sqrt_part, 1);
  477. eval_divide(result.real_data(), __my_imag_part_fabs, t);
  478. if (__my_imag_part_is_neg)
  479. __my_sqrt_part.negate();
  480. result.imag_data() = __my_sqrt_part;
  481. }
  482. }
  483. template <class Backend>
  484. inline void eval_abs(Backend& result, const complex_adaptor<Backend>& val)
  485. {
  486. Backend t1, t2;
  487. eval_multiply(t1, val.real_data(), val.real_data());
  488. eval_multiply(t2, val.imag_data(), val.imag_data());
  489. eval_add(t1, t2);
  490. eval_sqrt(result, t1);
  491. }
  492. template <class Backend>
  493. inline void eval_pow(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& b, const complex_adaptor<Backend>& e)
  494. {
  495. using default_ops::eval_acos;
  496. using default_ops::eval_cos;
  497. using default_ops::eval_exp;
  498. using default_ops::eval_get_sign;
  499. using default_ops::eval_is_zero;
  500. using default_ops::eval_multiply;
  501. using default_ops::eval_sin;
  502. if (eval_is_zero(e))
  503. {
  504. typename std::tuple_element<0, typename Backend::unsigned_types>::type one(1);
  505. result = one;
  506. return;
  507. }
  508. else if (eval_is_zero(b))
  509. {
  510. if (eval_is_zero(e.real_data()))
  511. {
  512. Backend n = std::numeric_limits<number<Backend> >::quiet_NaN().backend();
  513. result.real_data() = n;
  514. result.imag_data() = n;
  515. }
  516. else if (eval_get_sign(e.real_data()) < 0)
  517. {
  518. Backend n = std::numeric_limits<number<Backend> >::infinity().backend();
  519. result.real_data() = n;
  520. typename std::tuple_element<0, typename Backend::unsigned_types>::type zero(0);
  521. if (eval_is_zero(e.imag_data()))
  522. result.imag_data() = zero;
  523. else
  524. result.imag_data() = n;
  525. }
  526. else
  527. {
  528. typename std::tuple_element<0, typename Backend::unsigned_types>::type zero(0);
  529. result = zero;
  530. }
  531. return;
  532. }
  533. complex_adaptor<Backend> t;
  534. eval_log(t, b);
  535. eval_multiply(t, e);
  536. eval_exp(result, t);
  537. }
  538. template <class Backend>
  539. inline void eval_exp(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  540. {
  541. using default_ops::eval_cos;
  542. using default_ops::eval_exp;
  543. using default_ops::eval_is_zero;
  544. using default_ops::eval_multiply;
  545. using default_ops::eval_sin;
  546. if (eval_is_zero(arg.imag_data()))
  547. {
  548. eval_exp(result.real_data(), arg.real_data());
  549. typename std::tuple_element<0, typename Backend::unsigned_types>::type zero(0);
  550. result.imag_data() = zero;
  551. return;
  552. }
  553. eval_cos(result.real_data(), arg.imag_data());
  554. eval_sin(result.imag_data(), arg.imag_data());
  555. Backend e;
  556. eval_exp(e, arg.real_data());
  557. if (eval_is_zero(result.real_data()))
  558. eval_multiply(result.imag_data(), e);
  559. else if (eval_is_zero(result.imag_data()))
  560. eval_multiply(result.real_data(), e);
  561. else
  562. eval_multiply(result, e);
  563. }
  564. template <class Backend>
  565. inline void eval_log(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  566. {
  567. using default_ops::eval_add;
  568. using default_ops::eval_atan2;
  569. using default_ops::eval_get_sign;
  570. using default_ops::eval_is_zero;
  571. using default_ops::eval_log;
  572. using default_ops::eval_multiply;
  573. if (eval_is_zero(arg.imag_data()) && (eval_get_sign(arg.real_data()) >= 0))
  574. {
  575. eval_log(result.real_data(), arg.real_data());
  576. typename std::tuple_element<0, typename Backend::unsigned_types>::type zero(0);
  577. result.imag_data() = zero;
  578. return;
  579. }
  580. Backend t1, t2;
  581. eval_multiply(t1, arg.real_data(), arg.real_data());
  582. eval_multiply(t2, arg.imag_data(), arg.imag_data());
  583. eval_add(t1, t2);
  584. eval_log(t2, t1);
  585. eval_ldexp(result.real_data(), t2, -1);
  586. eval_atan2(result.imag_data(), arg.imag_data(), arg.real_data());
  587. }
  588. template <class Backend>
  589. inline void eval_log10(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  590. {
  591. using default_ops::eval_divide;
  592. using default_ops::eval_log;
  593. using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
  594. Backend ten;
  595. ten = ui_type(10);
  596. Backend l_ten;
  597. eval_log(l_ten, ten);
  598. eval_log(result, arg);
  599. eval_divide(result, l_ten);
  600. }
  601. template <class Backend>
  602. inline void eval_sin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  603. {
  604. using default_ops::eval_cos;
  605. using default_ops::eval_cosh;
  606. using default_ops::eval_sin;
  607. using default_ops::eval_sinh;
  608. Backend t1, t2, t3;
  609. eval_sin(t1, arg.real_data());
  610. eval_cosh(t2, arg.imag_data());
  611. eval_multiply(t3, t1, t2);
  612. eval_cos(t1, arg.real_data());
  613. eval_sinh(t2, arg.imag_data());
  614. eval_multiply(result.imag_data(), t1, t2);
  615. result.real_data() = t3;
  616. }
  617. template <class Backend>
  618. inline void eval_cos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  619. {
  620. using default_ops::eval_cos;
  621. using default_ops::eval_cosh;
  622. using default_ops::eval_sin;
  623. using default_ops::eval_sinh;
  624. Backend t1, t2, t3;
  625. eval_cos(t1, arg.real_data());
  626. eval_cosh(t2, arg.imag_data());
  627. eval_multiply(t3, t1, t2);
  628. eval_sin(t1, arg.real_data());
  629. eval_sinh(t2, arg.imag_data());
  630. eval_multiply(result.imag_data(), t1, t2);
  631. result.imag_data().negate();
  632. result.real_data() = t3;
  633. }
  634. template <class T>
  635. void tanh_imp(const T& r, const T& i, T& r_result, T& i_result)
  636. {
  637. using default_ops::eval_tan;
  638. using default_ops::eval_sinh;
  639. using default_ops::eval_add;
  640. using default_ops::eval_fpclassify;
  641. using default_ops::eval_get_sign;
  642. using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
  643. ui_type one(1);
  644. //
  645. // Set:
  646. // t = tan(i);
  647. // s = sinh(r);
  648. // b = s * (1 + t^2);
  649. // d = 1 + b * s;
  650. //
  651. T t, s, b, d;
  652. eval_tan(t, i);
  653. eval_sinh(s, r);
  654. eval_multiply(d, t, t);
  655. eval_add(d, one);
  656. eval_multiply(b, d, s);
  657. eval_multiply(d, b, s);
  658. eval_add(d, one);
  659. if (eval_fpclassify(d) == FP_INFINITE)
  660. {
  661. r_result = one;
  662. if (eval_get_sign(s) < 0)
  663. r_result.negate();
  664. //
  665. // Imaginary part is a signed zero:
  666. //
  667. ui_type zero(0);
  668. i_result = zero;
  669. if (eval_get_sign(t) < 0)
  670. i_result.negate();
  671. }
  672. //
  673. // Real part is sqrt(1 + s^2) * b / d;
  674. // Imaginary part is t / d;
  675. //
  676. eval_divide(i_result, t, d);
  677. //
  678. // variable t is now spare, as is r_result.
  679. //
  680. eval_multiply(t, s, s);
  681. eval_add(t, one);
  682. eval_sqrt(r_result, t);
  683. eval_multiply(t, r_result, b);
  684. eval_divide(r_result, t, d);
  685. }
  686. template <class Backend>
  687. inline void eval_tanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  688. {
  689. tanh_imp(arg.real_data(), arg.imag_data(), result.real_data(), result.imag_data());
  690. }
  691. template <class Backend>
  692. inline void eval_tan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  693. {
  694. Backend t(arg.imag_data());
  695. t.negate();
  696. tanh_imp(t, arg.real_data(), result.imag_data(), result.real_data());
  697. result.imag_data().negate();
  698. }
  699. template <class Backend>
  700. inline void eval_asin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  701. {
  702. using default_ops::eval_add;
  703. using default_ops::eval_multiply;
  704. if (eval_is_zero(arg))
  705. {
  706. result = arg;
  707. return;
  708. }
  709. complex_adaptor<Backend> t1, t2;
  710. assign_components(t1, arg.imag_data(), arg.real_data());
  711. t1.real_data().negate();
  712. eval_asinh(t2, t1);
  713. assign_components(result, t2.imag_data(), t2.real_data());
  714. result.imag_data().negate();
  715. }
  716. template <class Backend>
  717. inline void eval_acos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  718. {
  719. using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
  720. using default_ops::eval_asin;
  721. Backend half_pi, t1;
  722. t1 = static_cast<ui_type>(1u);
  723. eval_asin(half_pi, t1);
  724. eval_asin(result, arg);
  725. result.negate();
  726. eval_add(result.real_data(), half_pi);
  727. }
  728. template <class Backend>
  729. inline void eval_atan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  730. {
  731. using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
  732. ui_type one = (ui_type)1u;
  733. using default_ops::eval_add;
  734. using default_ops::eval_is_zero;
  735. using default_ops::eval_log;
  736. using default_ops::eval_subtract;
  737. complex_adaptor<Backend> __my_z_times_i, t1, t2, t3;
  738. assign_components(__my_z_times_i, arg.imag_data(), arg.real_data());
  739. __my_z_times_i.real_data().negate();
  740. eval_add(t1, __my_z_times_i, one);
  741. eval_log(t2, t1);
  742. eval_subtract(t1, one, __my_z_times_i);
  743. eval_log(t3, t1);
  744. eval_subtract(t1, t3, t2);
  745. eval_ldexp(result.real_data(), t1.imag_data(), -1);
  746. eval_ldexp(result.imag_data(), t1.real_data(), -1);
  747. if (!eval_is_zero(result.real_data()))
  748. result.real_data().negate();
  749. }
  750. template <class Backend>
  751. inline void eval_sinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  752. {
  753. using default_ops::eval_cos;
  754. using default_ops::eval_cosh;
  755. using default_ops::eval_sin;
  756. using default_ops::eval_sinh;
  757. Backend t1, t2, t3;
  758. eval_cos(t1, arg.imag_data());
  759. eval_sinh(t2, arg.real_data());
  760. eval_multiply(t3, t1, t2);
  761. eval_cosh(t1, arg.real_data());
  762. eval_sin(t2, arg.imag_data());
  763. eval_multiply(result.imag_data(), t1, t2);
  764. result.real_data() = t3;
  765. }
  766. template <class Backend>
  767. inline void eval_cosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  768. {
  769. using default_ops::eval_cos;
  770. using default_ops::eval_cosh;
  771. using default_ops::eval_sin;
  772. using default_ops::eval_sinh;
  773. Backend t1, t2, t3;
  774. eval_cos(t1, arg.imag_data());
  775. eval_cosh(t2, arg.real_data());
  776. eval_multiply(t3, t1, t2);
  777. eval_sin(t1, arg.imag_data());
  778. eval_sinh(t2, arg.real_data());
  779. eval_multiply(result.imag_data(), t1, t2);
  780. result.real_data() = t3;
  781. }
  782. template <class Backend>
  783. inline void eval_asinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  784. {
  785. using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
  786. ui_type one = (ui_type)1u;
  787. using default_ops::eval_add;
  788. using default_ops::eval_log;
  789. using default_ops::eval_multiply;
  790. complex_adaptor<Backend> t1, t2;
  791. eval_multiply(t1, arg, arg);
  792. eval_add(t1, one);
  793. eval_sqrt(t2, t1);
  794. eval_add(t2, arg);
  795. eval_log(result, t2);
  796. }
  797. template <class Backend>
  798. inline void eval_acosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  799. {
  800. using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
  801. ui_type one = (ui_type)1u;
  802. using default_ops::eval_add;
  803. using default_ops::eval_divide;
  804. using default_ops::eval_log;
  805. using default_ops::eval_multiply;
  806. using default_ops::eval_subtract;
  807. complex_adaptor<Backend> __my_zp(arg);
  808. eval_add(__my_zp.real_data(), one);
  809. complex_adaptor<Backend> __my_zm(arg);
  810. eval_subtract(__my_zm.real_data(), one);
  811. complex_adaptor<Backend> t1, t2;
  812. eval_divide(t1, __my_zm, __my_zp);
  813. eval_sqrt(t2, t1);
  814. eval_multiply(t2, __my_zp);
  815. eval_add(t2, arg);
  816. eval_log(result, t2);
  817. }
  818. template <class Backend>
  819. inline void eval_atanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  820. {
  821. using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
  822. ui_type one = (ui_type)1u;
  823. using default_ops::eval_add;
  824. using default_ops::eval_divide;
  825. using default_ops::eval_log;
  826. using default_ops::eval_multiply;
  827. using default_ops::eval_subtract;
  828. complex_adaptor<Backend> t1, t2, t3;
  829. eval_add(t1, arg, one);
  830. eval_log(t2, t1);
  831. eval_subtract(t1, one, arg);
  832. eval_log(t3, t1);
  833. eval_subtract(t2, t3);
  834. eval_ldexp(result.real_data(), t2.real_data(), -1);
  835. eval_ldexp(result.imag_data(), t2.imag_data(), -1);
  836. }
  837. template <class Backend>
  838. inline void eval_conj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  839. {
  840. result = arg;
  841. result.imag_data().negate();
  842. }
  843. template <class Backend>
  844. inline void eval_proj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  845. {
  846. using default_ops::eval_get_sign;
  847. using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
  848. ui_type zero = (ui_type)0u;
  849. int c1 = eval_fpclassify(arg.real_data());
  850. int c2 = eval_fpclassify(arg.imag_data());
  851. if (c1 == FP_INFINITE)
  852. {
  853. result.real_data() = arg.real_data();
  854. if (eval_get_sign(result.real_data()) < 0)
  855. result.real_data().negate();
  856. result.imag_data() = zero;
  857. if (eval_get_sign(arg.imag_data()) < 0)
  858. result.imag_data().negate();
  859. }
  860. else if (c2 == FP_INFINITE)
  861. {
  862. result.real_data() = arg.imag_data();
  863. if (eval_get_sign(result.real_data()) < 0)
  864. result.real_data().negate();
  865. result.imag_data() = zero;
  866. if (eval_get_sign(arg.imag_data()) < 0)
  867. result.imag_data().negate();
  868. }
  869. else
  870. result = arg;
  871. }
  872. template <class Backend>
  873. inline void eval_real(Backend& result, const complex_adaptor<Backend>& arg)
  874. {
  875. result = arg.real_data();
  876. }
  877. template <class Backend>
  878. inline void eval_imag(Backend& result, const complex_adaptor<Backend>& arg)
  879. {
  880. result = arg.imag_data();
  881. }
  882. template <class Backend, class T>
  883. inline void eval_set_imag(complex_adaptor<Backend>& result, const T& arg)
  884. {
  885. result.imag_data() = arg;
  886. }
  887. template <class Backend, class T>
  888. inline void eval_set_real(complex_adaptor<Backend>& result, const T& arg)
  889. {
  890. result.real_data() = arg;
  891. }
  892. template <class Backend>
  893. inline std::size_t hash_value(const complex_adaptor<Backend>& val)
  894. {
  895. std::size_t result = hash_value(val.real_data());
  896. std::size_t result2 = hash_value(val.imag_data());
  897. boost::multiprecision::detail::hash_combine(result, result2);
  898. return result;
  899. }
  900. } // namespace backends
  901. template <class Backend>
  902. struct number_category<complex_adaptor<Backend> > : public std::integral_constant<int, boost::multiprecision::number_kind_complex>
  903. {};
  904. template <class Backend, expression_template_option ExpressionTemplates>
  905. struct component_type<number<complex_adaptor<Backend>, ExpressionTemplates> >
  906. {
  907. using type = number<Backend, ExpressionTemplates>;
  908. };
  909. template <class Backend, expression_template_option ExpressionTemplates>
  910. struct complex_result_from_scalar<number<Backend, ExpressionTemplates> >
  911. {
  912. using type = number<complex_adaptor<Backend>, ExpressionTemplates>;
  913. };
  914. namespace detail {
  915. template <class Backend>
  916. struct is_variable_precision<complex_adaptor<Backend> > : public is_variable_precision<Backend>
  917. {};
  918. #ifdef BOOST_HAS_INT128
  919. template <class Backend>
  920. struct is_convertible_arithmetic<int128_type, complex_adaptor<Backend> > : is_convertible_arithmetic<int128_type, Backend>
  921. {};
  922. template <class Backend>
  923. struct is_convertible_arithmetic<uint128_type, complex_adaptor<Backend> > : is_convertible_arithmetic<uint128_type, Backend>
  924. {};
  925. #endif
  926. #ifdef BOOST_HAS_FLOAT128
  927. template <class Backend>
  928. struct is_convertible_arithmetic<float128_type, complex_adaptor<Backend> > : is_convertible_arithmetic<float128_type, Backend>
  929. {};
  930. #endif
  931. } // namespace detail
  932. template <class Backend, expression_template_option ExpressionTemplates>
  933. struct complex_result_from_scalar<number<backends::debug_adaptor<Backend>, ExpressionTemplates> >
  934. {
  935. using type = number<backends::debug_adaptor<complex_adaptor<Backend> >, ExpressionTemplates>;
  936. };
  937. template <class Backend, expression_template_option ExpressionTemplates>
  938. struct complex_result_from_scalar<number<backends::logged_adaptor<Backend>, ExpressionTemplates> >
  939. {
  940. using type = number<backends::logged_adaptor<complex_adaptor<Backend> >, ExpressionTemplates>;
  941. };
  942. }
  943. } // namespace boost::multiprecision
  944. #endif