complex_adaptor.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  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_MULTIPRECISION_COMPLEX_ADAPTOR_HPP
  6. #define BOOST_MULTIPRECISION_COMPLEX_ADAPTOR_HPP
  7. #include <boost/multiprecision/number.hpp>
  8. #include <boost/cstdint.hpp>
  9. #include <boost/multiprecision/detail/digits.hpp>
  10. #include <boost/functional/hash_fwd.hpp>
  11. #include <boost/type_traits/is_complex.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. typedef typename Backend::signed_types signed_types;
  41. typedef typename Backend::unsigned_types unsigned_types;
  42. typedef typename Backend::float_types float_types;
  43. typedef typename Backend::exponent_type exponent_type;
  44. complex_adaptor() {}
  45. complex_adaptor(const complex_adaptor& o) : m_real(o.real_data()), m_imag(o.imag_data()) {}
  46. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  47. complex_adaptor(complex_adaptor&& o) : m_real(std::move(o.real_data())), m_imag(std::move(o.imag_data()))
  48. {}
  49. #endif
  50. complex_adaptor(const Backend& val)
  51. : m_real(val)
  52. {}
  53. complex_adaptor(const std::complex<float>& val)
  54. {
  55. m_real = (long double)val.real();
  56. m_imag = (long double)val.imag();
  57. }
  58. complex_adaptor(const std::complex<double>& val)
  59. {
  60. m_real = (long double)val.real();
  61. m_imag = (long double)val.imag();
  62. }
  63. complex_adaptor(const std::complex<long double>& val)
  64. {
  65. m_real = val.real();
  66. m_imag = val.imag();
  67. }
  68. complex_adaptor& operator=(const complex_adaptor& o)
  69. {
  70. m_real = o.real_data();
  71. m_imag = o.imag_data();
  72. return *this;
  73. }
  74. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  75. complex_adaptor& operator=(complex_adaptor&& o) BOOST_NOEXCEPT
  76. {
  77. m_real = std::move(o.real_data());
  78. m_imag = std::move(o.imag_data());
  79. return *this;
  80. }
  81. #endif
  82. template <class V>
  83. complex_adaptor& operator=(const V& v)
  84. {
  85. typedef typename mpl::front<unsigned_types>::type ui_type;
  86. m_real = v;
  87. m_imag = ui_type(0u);
  88. return *this;
  89. }
  90. template <class T>
  91. complex_adaptor& operator=(const std::complex<T>& val)
  92. {
  93. m_real = (long double)val.real();
  94. m_imag = (long double)val.imag();
  95. return *this;
  96. }
  97. complex_adaptor& operator=(const char* s)
  98. {
  99. typedef typename mpl::front<unsigned_types>::type ui_type;
  100. ui_type zero = 0u;
  101. using default_ops::eval_fpclassify;
  102. if (s && (*s == '('))
  103. {
  104. std::string part;
  105. const char* p = ++s;
  106. while (*p && (*p != ',') && (*p != ')'))
  107. ++p;
  108. part.assign(s, p);
  109. if (part.size())
  110. real_data() = part.c_str();
  111. else
  112. real_data() = zero;
  113. s = p;
  114. if (*p && (*p != ')'))
  115. {
  116. ++p;
  117. while (*p && (*p != ')'))
  118. ++p;
  119. part.assign(s + 1, p);
  120. }
  121. else
  122. part.erase();
  123. if (part.size())
  124. imag_data() = part.c_str();
  125. else
  126. imag_data() = zero;
  127. if (eval_fpclassify(imag_data()) == (int)FP_NAN)
  128. {
  129. real_data() = imag_data();
  130. }
  131. }
  132. else
  133. {
  134. real_data() = s;
  135. imag_data() = zero;
  136. }
  137. return *this;
  138. }
  139. int compare(const complex_adaptor& o) const
  140. {
  141. // They are either equal or not:
  142. return (m_real.compare(o.real_data()) == 0) && (m_imag.compare(o.imag_data()) == 0) ? 0 : 1;
  143. }
  144. template <class T>
  145. int compare(const T& val) const
  146. {
  147. using default_ops::eval_is_zero;
  148. return (m_real.compare(val) == 0) && eval_is_zero(m_imag) ? 0 : 1;
  149. }
  150. void swap(complex_adaptor& o)
  151. {
  152. real_data().swap(o.real_data());
  153. imag_data().swap(o.imag_data());
  154. }
  155. std::string str(std::streamsize dig, std::ios_base::fmtflags f) const
  156. {
  157. using default_ops::eval_is_zero;
  158. if (eval_is_zero(imag_data()))
  159. return m_real.str(dig, f);
  160. return "(" + m_real.str(dig, f) + "," + m_imag.str(dig, f) + ")";
  161. }
  162. void negate()
  163. {
  164. m_real.negate();
  165. m_imag.negate();
  166. }
  167. };
  168. template <class Backend, class T>
  169. inline typename enable_if<is_arithmetic<T>, bool>::type eval_eq(const complex_adaptor<Backend>& a, const T& b) BOOST_NOEXCEPT
  170. {
  171. return a.compare(b) == 0;
  172. }
  173. template <class Backend>
  174. inline void eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
  175. {
  176. eval_add(result.real_data(), o.real_data());
  177. eval_add(result.imag_data(), o.imag_data());
  178. }
  179. template <class Backend>
  180. inline void eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
  181. {
  182. eval_subtract(result.real_data(), o.real_data());
  183. eval_subtract(result.imag_data(), o.imag_data());
  184. }
  185. template <class Backend>
  186. inline void eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
  187. {
  188. Backend t1, t2, t3;
  189. eval_multiply(t1, result.real_data(), o.real_data());
  190. eval_multiply(t2, result.imag_data(), o.imag_data());
  191. eval_subtract(t3, t1, t2);
  192. eval_multiply(t1, result.real_data(), o.imag_data());
  193. eval_multiply(t2, result.imag_data(), o.real_data());
  194. eval_add(t1, t2);
  195. result.real_data() = BOOST_MP_MOVE(t3);
  196. result.imag_data() = BOOST_MP_MOVE(t1);
  197. }
  198. template <class Backend>
  199. inline void eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& z)
  200. {
  201. // (a+bi) / (c + di)
  202. using default_ops::eval_add;
  203. using default_ops::eval_divide;
  204. using default_ops::eval_fabs;
  205. using default_ops::eval_is_zero;
  206. using default_ops::eval_multiply;
  207. using default_ops::eval_subtract;
  208. Backend t1, t2;
  209. if (eval_is_zero(z.imag_data()))
  210. {
  211. eval_divide(result.real_data(), z.real_data());
  212. eval_divide(result.imag_data(), z.real_data());
  213. return;
  214. }
  215. eval_fabs(t1, z.real_data());
  216. eval_fabs(t2, z.imag_data());
  217. if (t1.compare(t2) < 0)
  218. {
  219. eval_divide(t1, z.real_data(), z.imag_data()); // t1 = c/d
  220. eval_multiply(t2, z.real_data(), t1);
  221. eval_add(t2, z.imag_data()); // denom = c * (c/d) + d
  222. Backend t_real(result.real_data());
  223. // real = (a * (c/d) + b) / (denom)
  224. eval_multiply(result.real_data(), t1);
  225. eval_add(result.real_data(), result.imag_data());
  226. eval_divide(result.real_data(), t2);
  227. // imag = (b * c/d - a) / denom
  228. eval_multiply(result.imag_data(), t1);
  229. eval_subtract(result.imag_data(), t_real);
  230. eval_divide(result.imag_data(), t2);
  231. }
  232. else
  233. {
  234. eval_divide(t1, z.imag_data(), z.real_data()); // t1 = d/c
  235. eval_multiply(t2, z.imag_data(), t1);
  236. eval_add(t2, z.real_data()); // denom = d * d/c + c
  237. Backend r_t(result.real_data());
  238. Backend i_t(result.imag_data());
  239. // real = (b * d/c + a) / denom
  240. eval_multiply(result.real_data(), result.imag_data(), t1);
  241. eval_add(result.real_data(), r_t);
  242. eval_divide(result.real_data(), t2);
  243. // imag = (-a * d/c + b) / denom
  244. eval_multiply(result.imag_data(), r_t, t1);
  245. result.imag_data().negate();
  246. eval_add(result.imag_data(), i_t);
  247. eval_divide(result.imag_data(), t2);
  248. }
  249. }
  250. template <class Backend, class T>
  251. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const T& scalar)
  252. {
  253. using default_ops::eval_add;
  254. eval_add(result.real_data(), scalar);
  255. }
  256. template <class Backend, class T>
  257. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const T& scalar)
  258. {
  259. using default_ops::eval_subtract;
  260. eval_subtract(result.real_data(), scalar);
  261. }
  262. template <class Backend, class T>
  263. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const T& scalar)
  264. {
  265. using default_ops::eval_multiply;
  266. eval_multiply(result.real_data(), scalar);
  267. eval_multiply(result.imag_data(), scalar);
  268. }
  269. template <class Backend, class T>
  270. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const T& scalar)
  271. {
  272. using default_ops::eval_divide;
  273. eval_divide(result.real_data(), scalar);
  274. eval_divide(result.imag_data(), scalar);
  275. }
  276. // Optimised 3 arg versions:
  277. template <class Backend, class T>
  278. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  279. {
  280. using default_ops::eval_add;
  281. eval_add(result.real_data(), a.real_data(), scalar);
  282. result.imag_data() = a.imag_data();
  283. }
  284. template <class Backend, class T>
  285. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  286. {
  287. using default_ops::eval_subtract;
  288. eval_subtract(result.real_data(), a.real_data(), scalar);
  289. result.imag_data() = a.imag_data();
  290. }
  291. template <class Backend, class T>
  292. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  293. {
  294. using default_ops::eval_multiply;
  295. eval_multiply(result.real_data(), a.real_data(), scalar);
  296. eval_multiply(result.imag_data(), a.imag_data(), scalar);
  297. }
  298. template <class Backend, class T>
  299. inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
  300. {
  301. using default_ops::eval_divide;
  302. eval_divide(result.real_data(), a.real_data(), scalar);
  303. eval_divide(result.imag_data(), a.imag_data(), scalar);
  304. }
  305. template <class Backend>
  306. inline bool eval_is_zero(const complex_adaptor<Backend>& val) BOOST_NOEXCEPT
  307. {
  308. using default_ops::eval_is_zero;
  309. return eval_is_zero(val.real_data()) && eval_is_zero(val.imag_data());
  310. }
  311. template <class Backend>
  312. inline int eval_get_sign(const complex_adaptor<Backend>&)
  313. {
  314. BOOST_STATIC_ASSERT_MSG(sizeof(Backend) == UINT_MAX, "Complex numbers have no sign bit."); // designed to always fail
  315. return 0;
  316. }
  317. template <class Result, class Backend>
  318. inline typename disable_if_c<boost::is_complex<Result>::value>::type eval_convert_to(Result* result, const complex_adaptor<Backend>& val)
  319. {
  320. using default_ops::eval_convert_to;
  321. using default_ops::eval_is_zero;
  322. if (!eval_is_zero(val.imag_data()))
  323. {
  324. BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar."));
  325. }
  326. eval_convert_to(result, val.real_data());
  327. }
  328. template <class Backend, class T>
  329. inline void assign_components(complex_adaptor<Backend>& result, const T& a, const T& b)
  330. {
  331. result.real_data() = a;
  332. result.imag_data() = b;
  333. }
  334. //
  335. // Native non-member operations:
  336. //
  337. template <class Backend>
  338. inline void eval_sqrt(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& val)
  339. {
  340. // Use the following:
  341. // sqrt(z) = (s, zi / 2s) for zr >= 0
  342. // (|zi| / 2s, +-s) for zr < 0
  343. // where s = sqrt{ [ |zr| + sqrt(zr^2 + zi^2) ] / 2 },
  344. // and the +- sign is the same as the sign of zi.
  345. using default_ops::eval_abs;
  346. using default_ops::eval_add;
  347. using default_ops::eval_divide;
  348. using default_ops::eval_get_sign;
  349. using default_ops::eval_is_zero;
  350. if (eval_is_zero(val.imag_data()) && (eval_get_sign(val.real_data()) >= 0))
  351. {
  352. static const typename mpl::front<typename Backend::unsigned_types>::type zero = 0u;
  353. eval_sqrt(result.real_data(), val.real_data());
  354. result.imag_data() = zero;
  355. return;
  356. }
  357. const bool __my_real_part_is_neg(eval_get_sign(val.real_data()) < 0);
  358. Backend __my_real_part_fabs(val.real_data());
  359. if (__my_real_part_is_neg)
  360. __my_real_part_fabs.negate();
  361. Backend t, __my_sqrt_part;
  362. eval_abs(__my_sqrt_part, val);
  363. eval_add(__my_sqrt_part, __my_real_part_fabs);
  364. eval_ldexp(t, __my_sqrt_part, -1);
  365. eval_sqrt(__my_sqrt_part, t);
  366. if (__my_real_part_is_neg == false)
  367. {
  368. eval_ldexp(t, __my_sqrt_part, 1);
  369. eval_divide(result.imag_data(), val.imag_data(), t);
  370. result.real_data() = __my_sqrt_part;
  371. }
  372. else
  373. {
  374. const bool __my_imag_part_is_neg(eval_get_sign(val.imag_data()) < 0);
  375. Backend __my_imag_part_fabs(val.imag_data());
  376. if (__my_imag_part_is_neg)
  377. __my_imag_part_fabs.negate();
  378. eval_ldexp(t, __my_sqrt_part, 1);
  379. eval_divide(result.real_data(), __my_imag_part_fabs, t);
  380. if (__my_imag_part_is_neg)
  381. __my_sqrt_part.negate();
  382. result.imag_data() = __my_sqrt_part;
  383. }
  384. }
  385. template <class Backend>
  386. inline void eval_abs(Backend& result, const complex_adaptor<Backend>& val)
  387. {
  388. Backend t1, t2;
  389. eval_multiply(t1, val.real_data(), val.real_data());
  390. eval_multiply(t2, val.imag_data(), val.imag_data());
  391. eval_add(t1, t2);
  392. eval_sqrt(result, t1);
  393. }
  394. template <class Backend>
  395. inline void eval_pow(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& b, const complex_adaptor<Backend>& e)
  396. {
  397. using default_ops::eval_acos;
  398. using default_ops::eval_cos;
  399. using default_ops::eval_exp;
  400. using default_ops::eval_get_sign;
  401. using default_ops::eval_is_zero;
  402. using default_ops::eval_multiply;
  403. using default_ops::eval_sin;
  404. if (eval_is_zero(e))
  405. {
  406. typename mpl::front<typename Backend::unsigned_types>::type one(1);
  407. result = one;
  408. return;
  409. }
  410. else if (eval_is_zero(b))
  411. {
  412. if (eval_is_zero(e.real_data()))
  413. {
  414. Backend n = std::numeric_limits<number<Backend> >::quiet_NaN().backend();
  415. result.real_data() = n;
  416. result.imag_data() = n;
  417. }
  418. else if (eval_get_sign(e.real_data()) < 0)
  419. {
  420. Backend n = std::numeric_limits<number<Backend> >::infinity().backend();
  421. result.real_data() = n;
  422. typename mpl::front<typename Backend::unsigned_types>::type zero(0);
  423. if (eval_is_zero(e.imag_data()))
  424. result.imag_data() = zero;
  425. else
  426. result.imag_data() = n;
  427. }
  428. else
  429. {
  430. typename mpl::front<typename Backend::unsigned_types>::type zero(0);
  431. result = zero;
  432. }
  433. return;
  434. }
  435. complex_adaptor<Backend> t;
  436. eval_log(t, b);
  437. eval_multiply(t, e);
  438. eval_exp(result, t);
  439. }
  440. template <class Backend>
  441. inline void eval_exp(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  442. {
  443. using default_ops::eval_cos;
  444. using default_ops::eval_exp;
  445. using default_ops::eval_is_zero;
  446. using default_ops::eval_multiply;
  447. using default_ops::eval_sin;
  448. if (eval_is_zero(arg.imag_data()))
  449. {
  450. eval_exp(result.real_data(), arg.real_data());
  451. typename mpl::front<typename Backend::unsigned_types>::type zero(0);
  452. result.imag_data() = zero;
  453. return;
  454. }
  455. eval_cos(result.real_data(), arg.imag_data());
  456. eval_sin(result.imag_data(), arg.imag_data());
  457. Backend e;
  458. eval_exp(e, arg.real_data());
  459. if (eval_is_zero(result.real_data()))
  460. eval_multiply(result.imag_data(), e);
  461. else if (eval_is_zero(result.imag_data()))
  462. eval_multiply(result.real_data(), e);
  463. else
  464. eval_multiply(result, e);
  465. }
  466. template <class Backend>
  467. inline void eval_log(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  468. {
  469. using default_ops::eval_add;
  470. using default_ops::eval_atan2;
  471. using default_ops::eval_get_sign;
  472. using default_ops::eval_is_zero;
  473. using default_ops::eval_log;
  474. using default_ops::eval_multiply;
  475. if (eval_is_zero(arg.imag_data()) && (eval_get_sign(arg.real_data()) >= 0))
  476. {
  477. eval_log(result.real_data(), arg.real_data());
  478. typename mpl::front<typename Backend::unsigned_types>::type zero(0);
  479. result.imag_data() = zero;
  480. return;
  481. }
  482. Backend t1, t2;
  483. eval_multiply(t1, arg.real_data(), arg.real_data());
  484. eval_multiply(t2, arg.imag_data(), arg.imag_data());
  485. eval_add(t1, t2);
  486. eval_log(t2, t1);
  487. eval_ldexp(result.real_data(), t2, -1);
  488. eval_atan2(result.imag_data(), arg.imag_data(), arg.real_data());
  489. }
  490. template <class Backend>
  491. inline void eval_log10(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  492. {
  493. using default_ops::eval_divide;
  494. using default_ops::eval_log;
  495. typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
  496. Backend ten;
  497. ten = ui_type(10);
  498. Backend l_ten;
  499. eval_log(l_ten, ten);
  500. eval_log(result, arg);
  501. eval_divide(result, l_ten);
  502. }
  503. template <class Backend>
  504. inline void eval_sin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  505. {
  506. using default_ops::eval_cos;
  507. using default_ops::eval_cosh;
  508. using default_ops::eval_sin;
  509. using default_ops::eval_sinh;
  510. Backend t1, t2;
  511. eval_sin(t1, arg.real_data());
  512. eval_cosh(t2, arg.imag_data());
  513. eval_multiply(result.real_data(), t1, t2);
  514. eval_cos(t1, arg.real_data());
  515. eval_sinh(t2, arg.imag_data());
  516. eval_multiply(result.imag_data(), t1, t2);
  517. }
  518. template <class Backend>
  519. inline void eval_cos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  520. {
  521. using default_ops::eval_cos;
  522. using default_ops::eval_cosh;
  523. using default_ops::eval_sin;
  524. using default_ops::eval_sinh;
  525. Backend t1, t2;
  526. eval_cos(t1, arg.real_data());
  527. eval_cosh(t2, arg.imag_data());
  528. eval_multiply(result.real_data(), t1, t2);
  529. eval_sin(t1, arg.real_data());
  530. eval_sinh(t2, arg.imag_data());
  531. eval_multiply(result.imag_data(), t1, t2);
  532. result.imag_data().negate();
  533. }
  534. template <class Backend>
  535. inline void eval_tan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  536. {
  537. complex_adaptor<Backend> c;
  538. eval_cos(c, arg);
  539. eval_sin(result, arg);
  540. eval_divide(result, c);
  541. }
  542. template <class Backend>
  543. inline void eval_asin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  544. {
  545. using default_ops::eval_add;
  546. using default_ops::eval_multiply;
  547. if (eval_is_zero(arg))
  548. {
  549. result = arg;
  550. return;
  551. }
  552. complex_adaptor<Backend> t1, t2;
  553. assign_components(t1, arg.imag_data(), arg.real_data());
  554. t1.real_data().negate();
  555. eval_asinh(t2, t1);
  556. assign_components(result, t2.imag_data(), t2.real_data());
  557. result.imag_data().negate();
  558. }
  559. template <class Backend>
  560. inline void eval_acos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  561. {
  562. typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
  563. using default_ops::eval_asin;
  564. Backend half_pi, t1;
  565. t1 = static_cast<ui_type>(1u);
  566. eval_asin(half_pi, t1);
  567. eval_asin(result, arg);
  568. result.negate();
  569. eval_add(result.real_data(), half_pi);
  570. }
  571. template <class Backend>
  572. inline void eval_atan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  573. {
  574. typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
  575. ui_type one = (ui_type)1u;
  576. using default_ops::eval_add;
  577. using default_ops::eval_is_zero;
  578. using default_ops::eval_log;
  579. using default_ops::eval_subtract;
  580. complex_adaptor<Backend> __my_z_times_i, t1, t2, t3;
  581. assign_components(__my_z_times_i, arg.imag_data(), arg.real_data());
  582. __my_z_times_i.real_data().negate();
  583. eval_add(t1, __my_z_times_i, one);
  584. eval_log(t2, t1);
  585. eval_subtract(t1, one, __my_z_times_i);
  586. eval_log(t3, t1);
  587. eval_subtract(t1, t3, t2);
  588. eval_ldexp(result.real_data(), t1.imag_data(), -1);
  589. eval_ldexp(result.imag_data(), t1.real_data(), -1);
  590. if (!eval_is_zero(result.real_data()))
  591. result.real_data().negate();
  592. }
  593. template <class Backend>
  594. inline void eval_sinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  595. {
  596. using default_ops::eval_cos;
  597. using default_ops::eval_cosh;
  598. using default_ops::eval_sin;
  599. using default_ops::eval_sinh;
  600. Backend t1, t2;
  601. eval_cos(t1, arg.imag_data());
  602. eval_sinh(t2, arg.real_data());
  603. eval_multiply(result.real_data(), t1, t2);
  604. eval_cosh(t1, arg.real_data());
  605. eval_sin(t2, arg.imag_data());
  606. eval_multiply(result.imag_data(), t1, t2);
  607. }
  608. template <class Backend>
  609. inline void eval_cosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  610. {
  611. using default_ops::eval_cos;
  612. using default_ops::eval_cosh;
  613. using default_ops::eval_sin;
  614. using default_ops::eval_sinh;
  615. Backend t1, t2;
  616. eval_cos(t1, arg.imag_data());
  617. eval_cosh(t2, arg.real_data());
  618. eval_multiply(result.real_data(), t1, t2);
  619. eval_sin(t1, arg.imag_data());
  620. eval_sinh(t2, arg.real_data());
  621. eval_multiply(result.imag_data(), t1, t2);
  622. }
  623. template <class Backend>
  624. inline void eval_tanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  625. {
  626. using default_ops::eval_divide;
  627. complex_adaptor<Backend> s, c;
  628. eval_sinh(s, arg);
  629. eval_cosh(c, arg);
  630. eval_divide(result, s, c);
  631. }
  632. template <class Backend>
  633. inline void eval_asinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  634. {
  635. typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
  636. ui_type one = (ui_type)1u;
  637. using default_ops::eval_add;
  638. using default_ops::eval_log;
  639. using default_ops::eval_multiply;
  640. complex_adaptor<Backend> t1, t2;
  641. eval_multiply(t1, arg, arg);
  642. eval_add(t1, one);
  643. eval_sqrt(t2, t1);
  644. eval_add(t2, arg);
  645. eval_log(result, t2);
  646. }
  647. template <class Backend>
  648. inline void eval_acosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  649. {
  650. typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
  651. ui_type one = (ui_type)1u;
  652. using default_ops::eval_add;
  653. using default_ops::eval_divide;
  654. using default_ops::eval_log;
  655. using default_ops::eval_multiply;
  656. using default_ops::eval_subtract;
  657. complex_adaptor<Backend> __my_zp(arg);
  658. eval_add(__my_zp.real_data(), one);
  659. complex_adaptor<Backend> __my_zm(arg);
  660. eval_subtract(__my_zm.real_data(), one);
  661. complex_adaptor<Backend> t1, t2;
  662. eval_divide(t1, __my_zm, __my_zp);
  663. eval_sqrt(t2, t1);
  664. eval_multiply(t2, __my_zp);
  665. eval_add(t2, arg);
  666. eval_log(result, t2);
  667. }
  668. template <class Backend>
  669. inline void eval_atanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  670. {
  671. typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
  672. ui_type one = (ui_type)1u;
  673. using default_ops::eval_add;
  674. using default_ops::eval_divide;
  675. using default_ops::eval_log;
  676. using default_ops::eval_multiply;
  677. using default_ops::eval_subtract;
  678. complex_adaptor<Backend> t1, t2, t3;
  679. eval_add(t1, arg, one);
  680. eval_log(t2, t1);
  681. eval_subtract(t1, one, arg);
  682. eval_log(t3, t1);
  683. eval_subtract(t2, t3);
  684. eval_ldexp(result.real_data(), t2.real_data(), -1);
  685. eval_ldexp(result.imag_data(), t2.imag_data(), -1);
  686. }
  687. template <class Backend>
  688. inline void eval_conj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  689. {
  690. result = arg;
  691. result.imag_data().negate();
  692. }
  693. template <class Backend>
  694. inline void eval_proj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
  695. {
  696. using default_ops::eval_get_sign;
  697. typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
  698. ui_type zero = (ui_type)0u;
  699. int c1 = eval_fpclassify(arg.real_data());
  700. int c2 = eval_fpclassify(arg.imag_data());
  701. if (c1 == FP_INFINITE)
  702. {
  703. result.real_data() = arg.real_data();
  704. if (eval_get_sign(result.real_data()) < 0)
  705. result.real_data().negate();
  706. result.imag_data() = zero;
  707. if (eval_get_sign(arg.imag_data()) < 0)
  708. result.imag_data().negate();
  709. }
  710. else if (c2 == FP_INFINITE)
  711. {
  712. result.real_data() = arg.imag_data();
  713. if (eval_get_sign(result.real_data()) < 0)
  714. result.real_data().negate();
  715. result.imag_data() = zero;
  716. if (eval_get_sign(arg.imag_data()) < 0)
  717. result.imag_data().negate();
  718. }
  719. else
  720. result = arg;
  721. }
  722. template <class Backend>
  723. inline void eval_real(Backend& result, const complex_adaptor<Backend>& arg)
  724. {
  725. result = arg.real_data();
  726. }
  727. template <class Backend>
  728. inline void eval_imag(Backend& result, const complex_adaptor<Backend>& arg)
  729. {
  730. result = arg.imag_data();
  731. }
  732. template <class Backend, class T>
  733. inline void eval_set_imag(complex_adaptor<Backend>& result, const T& arg)
  734. {
  735. result.imag_data() = arg;
  736. }
  737. template <class Backend, class T>
  738. inline void eval_set_real(complex_adaptor<Backend>& result, const T& arg)
  739. {
  740. result.real_data() = arg;
  741. }
  742. template <class Backend>
  743. inline std::size_t hash_value(const complex_adaptor<Backend>& val)
  744. {
  745. std::size_t result = hash_value(val.real_data());
  746. std::size_t result2 = hash_value(val.imag_data());
  747. boost::hash_combine(result, result2);
  748. return result;
  749. }
  750. } // namespace backends
  751. using boost::multiprecision::backends::complex_adaptor;
  752. template <class Backend>
  753. struct number_category<complex_adaptor<Backend> > : public boost::mpl::int_<boost::multiprecision::number_kind_complex>
  754. {};
  755. template <class Backend, expression_template_option ExpressionTemplates>
  756. struct component_type<number<complex_adaptor<Backend>, ExpressionTemplates> >
  757. {
  758. typedef number<Backend, ExpressionTemplates> type;
  759. };
  760. template <class Backend, expression_template_option ExpressionTemplates>
  761. struct complex_result_from_scalar<number<Backend, ExpressionTemplates> >
  762. {
  763. typedef number<complex_adaptor<Backend>, ExpressionTemplates> type;
  764. };
  765. }
  766. } // namespace boost::multiprecision
  767. #endif