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