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