1 ///////////////////////////////////////////////////////////////////////////////
2 //  Copyright 2011 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_MATH_BIG_NUM_DEF_OPS
7 #define BOOST_MATH_BIG_NUM_DEF_OPS
8 
9 #include <boost/math/policies/error_handling.hpp>
10 #include <boost/multiprecision/detail/number_base.hpp>
11 #include <boost/math/special_functions/fpclassify.hpp>
12 #include <boost/math/special_functions/next.hpp>
13 #include <boost/math/special_functions/hypot.hpp>
14 #include <boost/utility/enable_if.hpp>
15 #include <boost/mpl/front.hpp>
16 #include <boost/mpl/fold.hpp>
17 #include <boost/cstdint.hpp>
18 #include <boost/type_traits/make_unsigned.hpp>
19 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
20 #include <string_view>
21 #endif
22 
23 #ifndef INSTRUMENT_BACKEND
24 #ifndef BOOST_MP_INSTRUMENT
25 #define INSTRUMENT_BACKEND(x)
26 #else
27 #define INSTRUMENT_BACKEND(x)\
28    std::cout << BOOST_STRINGIZE(x) << " = " << x.str(0, std::ios_base::scientific) << std::endl;
29 #endif
30 #endif
31 
32 
33 namespace boost{ namespace multiprecision{
34 
35    namespace detail {
36 
37       template <class T>
38       struct is_backend;
39 
40       template <class To, class From>
41       void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/);
42       template <class To, class From>
43       void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/);
44       template <class To, class From>
45       void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/);
46       template <class To, class From>
47       void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/);
48       template <class To, class From>
49       void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/);
50 
51 }
52 
53 namespace default_ops{
54 
55 #ifdef BOOST_MSVC
56 // warning C4127: conditional expression is constant
57 // warning C4146: unary minus operator applied to unsigned type, result still unsigned
58 #pragma warning(push)
59 #pragma warning(disable:4127 4146)
60 #endif
61 //
62 // Default versions of mixed arithmetic, these just construct a temporary
63 // from the arithmetic value and then do the arithmetic on that, two versions
64 // of each depending on whether the backend can be directly constructed from type V.
65 //
66 // Note that we have to provide *all* the template parameters to class number when used in
67 // enable_if as MSVC-10 won't compile the code if we rely on a computed-default parameter.
68 // Since the result of the test doesn't depend on whether expression templates are on or off
69 // we just use et_on everywhere.  We could use a BOOST_WORKAROUND but that just obfuscates the
70 // code even more....
71 //
72 template <class T, class V>
73 inline typename disable_if_c<is_convertible<V, T>::value >::type
eval_add(T & result,V const & v)74    eval_add(T& result, V const& v)
75 {
76    T t;
77    t = v;
78    eval_add(result, t);
79 }
80 template <class T, class V>
81 inline typename enable_if_c<is_convertible<V, T>::value >::type
eval_add(T & result,V const & v)82    eval_add(T& result, V const& v)
83 {
84    T t(v);
85    eval_add(result, t);
86 }
87 template <class T, class V>
88 inline typename disable_if_c<is_convertible<V, T>::value>::type
eval_subtract(T & result,V const & v)89    eval_subtract(T& result, V const& v)
90 {
91    T t;
92    t = v;
93    eval_subtract(result, t);
94 }
95 template <class T, class V>
96 inline typename enable_if_c<is_convertible<V, T>::value>::type
eval_subtract(T & result,V const & v)97    eval_subtract(T& result, V const& v)
98 {
99    T t(v);
100    eval_subtract(result, t);
101 }
102 template <class T, class V>
103 inline typename disable_if_c<is_convertible<V, T>::value>::type
eval_multiply(T & result,V const & v)104    eval_multiply(T& result, V const& v)
105 {
106    T t;
107    t = v;
108    eval_multiply(result, t);
109 }
110 template <class T, class V>
111 inline typename enable_if_c<is_convertible<V, T>::value>::type
eval_multiply(T & result,V const & v)112    eval_multiply(T& result, V const& v)
113 {
114    T t(v);
115    eval_multiply(result, t);
116 }
117 
118 template <class T, class U, class V>
119 void eval_multiply(T& t, const U& u, const V& v);
120 
121 template <class T, class U, class V>
eval_multiply_add(T & t,const U & u,const V & v)122 inline typename disable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v)
123 {
124    T z;
125    eval_multiply(z, u, v);
126    eval_add(t, z);
127 }
128 template <class T, class U, class V>
eval_multiply_add(T & t,const U & u,const V & v)129 inline typename enable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v)
130 {
131    eval_multiply_add(t, v, u);
132 }
133 template <class T, class U, class V>
eval_multiply_subtract(T & t,const U & u,const V & v)134 inline typename disable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v)
135 {
136    T z;
137    eval_multiply(z, u, v);
138    eval_subtract(t, z);
139 }
140 template <class T, class U, class V>
eval_multiply_subtract(T & t,const U & u,const V & v)141 inline typename enable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v)
142 {
143    eval_multiply_subtract(t, v, u);
144 }
145 template <class T, class V>
146 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_divide(T & result,V const & v)147    eval_divide(T& result, V const& v)
148 {
149    T t;
150    t = v;
151    eval_divide(result, t);
152 }
153 template <class T, class V>
154 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
eval_divide(T & result,V const & v)155    eval_divide(T& result, V const& v)
156 {
157    T t(v);
158    eval_divide(result, t);
159 }
160 template <class T, class V>
161 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_modulus(T & result,V const & v)162    eval_modulus(T& result, V const& v)
163 {
164    T t;
165    t = v;
166    eval_modulus(result, t);
167 }
168 template <class T, class V>
169 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value&& is_convertible<V, T>::value>::type
eval_modulus(T & result,V const & v)170    eval_modulus(T& result, V const& v)
171 {
172    T t(v);
173    eval_modulus(result, t);
174 }
175 template <class T, class V>
176 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_bitwise_and(T & result,V const & v)177    eval_bitwise_and(T& result, V const& v)
178 {
179    T t;
180    t = v;
181    eval_bitwise_and(result, t);
182 }
183 template <class T, class V>
184 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
eval_bitwise_and(T & result,V const & v)185    eval_bitwise_and(T& result, V const& v)
186 {
187    T t(v);
188    eval_bitwise_and(result, t);
189 }
190 template <class T, class V>
191 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_bitwise_or(T & result,V const & v)192    eval_bitwise_or(T& result, V const& v)
193 {
194    T t;
195    t = v;
196    eval_bitwise_or(result, t);
197 }
198 template <class T, class V>
199 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
eval_bitwise_or(T & result,V const & v)200    eval_bitwise_or(T& result, V const& v)
201 {
202    T t(v);
203    eval_bitwise_or(result, t);
204 }
205 template <class T, class V>
206 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_bitwise_xor(T & result,V const & v)207    eval_bitwise_xor(T& result, V const& v)
208 {
209    T t;
210    t = v;
211    eval_bitwise_xor(result, t);
212 }
213 template <class T, class V>
214 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
eval_bitwise_xor(T & result,V const & v)215    eval_bitwise_xor(T& result, V const& v)
216 {
217    T t(v);
218    eval_bitwise_xor(result, t);
219 }
220 
221 template <class T, class V>
222 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_complement(T & result,V const & v)223    eval_complement(T& result, V const& v)
224 {
225    T t;
226    t = v;
227    eval_complement(result, t);
228 }
229 template <class T, class V>
230 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
eval_complement(T & result,V const & v)231    eval_complement(T& result, V const& v)
232 {
233    T t(v);
234    eval_complement(result, t);
235 }
236 
237 //
238 // Default versions of 3-arg arithmetic functions, these mostly just forward to the 2 arg versions:
239 //
240 template <class T, class U, class V>
241 void eval_add(T& t, const U& u, const V& v);
242 
243 template <class T>
eval_add_default(T & t,const T & u,const T & v)244 inline void eval_add_default(T& t, const T& u, const T& v)
245 {
246    if(&t == &v)
247    {
248       eval_add(t, u);
249    }
250    else if(&t == &u)
251    {
252       eval_add(t, v);
253    }
254    else
255    {
256       t = u;
257       eval_add(t, v);
258    }
259 }
260 template <class T, class U>
eval_add_default(T & t,const T & u,const U & v)261 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_add_default(T& t, const T& u, const U& v)
262 {
263    T vv;
264    vv = v;
265    eval_add(t, u, vv);
266 }
267 template <class T, class U>
eval_add_default(T & t,const T & u,const U & v)268 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_add_default(T& t, const T& u, const U& v)
269 {
270    T vv(v);
271    eval_add(t, u, vv);
272 }
273 template <class T, class U>
eval_add_default(T & t,const U & u,const T & v)274 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value>::type eval_add_default(T& t, const U& u, const T& v)
275 {
276    eval_add(t, v, u);
277 }
278 template <class T, class U, class V>
eval_add_default(T & t,const U & u,const V & v)279 inline void eval_add_default(T& t, const U& u, const V& v)
280 {
281    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
282    {
283       eval_add(t, u);
284    }
285    else
286    {
287       t = u;
288       eval_add(t, v);
289    }
290 }
291 template <class T, class U, class V>
eval_add(T & t,const U & u,const V & v)292 inline void eval_add(T& t, const U& u, const V& v)
293 {
294    eval_add_default(t, u, v);
295 }
296 
297 template <class T, class U, class V>
298 void eval_subtract(T& t, const U& u, const V& v);
299 
300 template <class T>
eval_subtract_default(T & t,const T & u,const T & v)301 inline void eval_subtract_default(T& t, const T& u, const T& v)
302 {
303    if((&t == &v) && is_signed_number<T>::value)
304    {
305       eval_subtract(t, u);
306       t.negate();
307    }
308    else if(&t == &u)
309    {
310       eval_subtract(t, v);
311    }
312    else
313    {
314       t = u;
315       eval_subtract(t, v);
316    }
317 }
318 template <class T, class U>
eval_subtract_default(T & t,const T & u,const U & v)319 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_subtract_default(T& t, const T& u, const U& v)
320 {
321    T vv;
322    vv = v;
323    eval_subtract(t, u, vv);
324 }
325 template <class T, class U>
eval_subtract_default(T & t,const T & u,const U & v)326 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_subtract_default(T& t, const T& u, const U& v)
327 {
328    T vv(v);
329    eval_subtract(t, u, vv);
330 }
331 template <class T, class U>
eval_subtract_default(T & t,const U & u,const T & v)332 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_signed_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
333 {
334    eval_subtract(t, v, u);
335    t.negate();
336 }
337 template <class T, class U>
eval_subtract_default(T & t,const U & u,const T & v)338 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
339 {
340    T temp;
341    temp = u;
342    eval_subtract(t, temp, v);
343 }
344 template <class T, class U>
eval_subtract_default(T & t,const U & u,const T & v)345 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
346 {
347    T temp(u);
348    eval_subtract(t, temp, v);
349 }
350 template <class T, class U, class V>
eval_subtract_default(T & t,const U & u,const V & v)351 inline void eval_subtract_default(T& t, const U& u, const V& v)
352 {
353    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
354    {
355       eval_subtract(t, u);
356       t.negate();
357    }
358    else
359    {
360       t = u;
361       eval_subtract(t, v);
362    }
363 }
364 template <class T, class U, class V>
eval_subtract(T & t,const U & u,const V & v)365 inline void eval_subtract(T& t, const U& u, const V& v)
366 {
367    eval_subtract_default(t, u, v);
368 }
369 
370 template <class T>
eval_multiply_default(T & t,const T & u,const T & v)371 inline void eval_multiply_default(T& t, const T& u, const T& v)
372 {
373    if(&t == &v)
374    {
375       eval_multiply(t, u);
376    }
377    else if(&t == &u)
378    {
379       eval_multiply(t, v);
380    }
381    else
382    {
383       t = u;
384       eval_multiply(t, v);
385    }
386 }
387 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
388 template <class T, class U>
eval_multiply_default(T & t,const T & u,const U & v)389 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_multiply_default(T& t, const T& u, const U& v)
390 {
391    T vv;
392    vv = v;
393    eval_multiply(t, u, vv);
394 }
395 template <class T, class U>
eval_multiply_default(T & t,const T & u,const U & v)396 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_multiply_default(T& t, const T& u, const U& v)
397 {
398    T vv(v);
399    eval_multiply(t, u, vv);
400 }
401 template <class T, class U>
eval_multiply_default(T & t,const U & u,const T & v)402 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value>::type eval_multiply_default(T& t, const U& u, const T& v)
403 {
404    eval_multiply(t, v, u);
405 }
406 #endif
407 template <class T, class U, class V>
eval_multiply_default(T & t,const U & u,const V & v)408 inline void eval_multiply_default(T& t, const U& u, const V& v)
409 {
410    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
411    {
412       eval_multiply(t, u);
413    }
414    else
415    {
416       t = number<T>::canonical_value(u);
417       eval_multiply(t, v);
418    }
419 }
420 template <class T, class U, class V>
eval_multiply(T & t,const U & u,const V & v)421 inline void eval_multiply(T& t, const U& u, const V& v)
422 {
423    eval_multiply_default(t, u, v);
424 }
425 
426 template <class T>
eval_multiply_add(T & t,const T & u,const T & v,const T & x)427 inline void eval_multiply_add(T& t, const T& u, const T& v, const T& x)
428 {
429    if((void*)&x == (void*)&t)
430    {
431       T z;
432       z = number<T>::canonical_value(x);
433       eval_multiply_add(t, u, v, z);
434    }
435    else
436    {
437       eval_multiply(t, u, v);
438       eval_add(t, x);
439    }
440 }
441 
442 template <class T, class U>
make_T(const U & u)443 inline typename boost::disable_if_c<boost::is_same<T, U>::value, T>::type make_T(const U& u)
444 {
445    T t;
446    t = number<T>::canonical_value(u);
447    return BOOST_MP_MOVE(t);
448 }
449 template <class T>
make_T(const T & t)450 inline const T& make_T(const T& t)
451 {
452    return t;
453 }
454 
455 template <class T, class U, class V, class X>
eval_multiply_add(T & t,const U & u,const V & v,const X & x)456 inline typename disable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x)
457 {
458    eval_multiply_add(t, make_T<T>(u), make_T<T>(v), make_T<T>(x));
459 }
460 template <class T, class U, class V, class X>
eval_multiply_add(T & t,const U & u,const V & v,const X & x)461 inline typename enable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x)
462 {
463    eval_multiply_add(t, v, u, x);
464 }
465 template <class T, class U, class V, class X>
eval_multiply_subtract(T & t,const U & u,const V & v,const X & x)466 inline typename disable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x)
467 {
468    if((void*)&x == (void*)&t)
469    {
470       T z;
471       z = x;
472       eval_multiply_subtract(t, u, v, z);
473    }
474    else
475    {
476       eval_multiply(t, u, v);
477       eval_subtract(t, x);
478    }
479 }
480 template <class T, class U, class V, class X>
eval_multiply_subtract(T & t,const U & u,const V & v,const X & x)481 inline typename enable_if_c<!is_same<T, U>::value && is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x)
482 {
483    eval_multiply_subtract(t, v, u, x);
484 }
485 
486 template <class T, class U, class V>
487 void eval_divide(T& t, const U& u, const V& v);
488 
489 template <class T>
eval_divide_default(T & t,const T & u,const T & v)490 inline void eval_divide_default(T& t, const T& u, const T& v)
491 {
492    if(&t == &u)
493       eval_divide(t, v);
494    else if(&t == &v)
495    {
496       T temp;
497       eval_divide(temp, u, v);
498       temp.swap(t);
499    }
500    else
501    {
502       t = u;
503       eval_divide(t, v);
504    }
505 }
506 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
507 template <class T, class U>
eval_divide_default(T & t,const T & u,const U & v)508 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_divide_default(T& t, const T& u, const U& v)
509 {
510    T vv;
511    vv = v;
512    eval_divide(t, u, vv);
513 }
514 template <class T, class U>
eval_divide_default(T & t,const T & u,const U & v)515 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_divide_default(T& t, const T& u, const U& v)
516 {
517    T vv(v);
518    eval_divide(t, u, vv);
519 }
520 template <class T, class U>
eval_divide_default(T & t,const U & u,const T & v)521 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_divide_default(T& t, const U& u, const T& v)
522 {
523    T uu;
524    uu = u;
525    eval_divide(t, uu, v);
526 }
527 template <class T, class U>
eval_divide_default(T & t,const U & u,const T & v)528 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_divide_default(T& t, const U& u, const T& v)
529 {
530    T uu(u);
531    eval_divide(t, uu, v);
532 }
533 #endif
534 template <class T, class U, class V>
eval_divide_default(T & t,const U & u,const V & v)535 inline void eval_divide_default(T& t, const U& u, const V& v)
536 {
537    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
538    {
539       T temp;
540       temp = u;
541       eval_divide(temp, v);
542       t = temp;
543    }
544    else
545    {
546       t = u;
547       eval_divide(t, v);
548    }
549 }
550 template <class T, class U, class V>
eval_divide(T & t,const U & u,const V & v)551 inline void eval_divide(T& t, const U& u, const V& v)
552 {
553    eval_divide_default(t, u, v);
554 }
555 
556 template <class T, class U, class V>
557 void eval_modulus(T& t, const U& u, const V& v);
558 
559 template <class T>
eval_modulus_default(T & t,const T & u,const T & v)560 inline void eval_modulus_default(T& t, const T& u, const T& v)
561 {
562    if(&t == &u)
563       eval_modulus(t, v);
564    else if(&t == &v)
565    {
566       T temp;
567       eval_modulus(temp, u, v);
568       temp.swap(t);
569    }
570    else
571    {
572       t = u;
573       eval_modulus(t, v);
574    }
575 }
576 template <class T, class U>
eval_modulus_default(T & t,const T & u,const U & v)577 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_modulus_default(T& t, const T& u, const U& v)
578 {
579    T vv;
580    vv = v;
581    eval_modulus(t, u, vv);
582 }
583 template <class T, class U>
eval_modulus_default(T & t,const T & u,const U & v)584 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_modulus_default(T& t, const T& u, const U& v)
585 {
586    T vv(v);
587    eval_modulus(t, u, vv);
588 }
589 template <class T, class U>
eval_modulus_default(T & t,const U & u,const T & v)590 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_modulus_default(T& t, const U& u, const T& v)
591 {
592    T uu;
593    uu = u;
594    eval_modulus(t, uu, v);
595 }
596 template <class T, class U>
eval_modulus_default(T & t,const U & u,const T & v)597 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_modulus_default(T& t, const U& u, const T& v)
598 {
599    T uu(u);
600    eval_modulus(t, uu, v);
601 }
602 template <class T, class U, class V>
eval_modulus_default(T & t,const U & u,const V & v)603 inline void eval_modulus_default(T& t, const U& u, const V& v)
604 {
605    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
606    {
607       T temp(u);
608       eval_modulus(temp, v);
609       t = temp;
610    }
611    else
612    {
613       t = u;
614       eval_modulus(t, v);
615    }
616 }
617 template <class T, class U, class V>
eval_modulus(T & t,const U & u,const V & v)618 inline void eval_modulus(T& t, const U& u, const V& v)
619 {
620    eval_modulus_default(t, u, v);
621 }
622 
623 template <class T, class U, class V>
624 void eval_bitwise_and(T& t, const U& u, const V& v);
625 
626 template <class T>
eval_bitwise_and_default(T & t,const T & u,const T & v)627 inline void eval_bitwise_and_default(T& t, const T& u, const T& v)
628 {
629    if(&t == &v)
630    {
631       eval_bitwise_and(t, u);
632    }
633    else if(&t == &u)
634    {
635       eval_bitwise_and(t, v);
636    }
637    else
638    {
639       t = u;
640       eval_bitwise_and(t, v);
641    }
642 }
643 template <class T, class U>
eval_bitwise_and_default(T & t,const T & u,const U & v)644 inline typename disable_if_c<is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
645 {
646    T vv;
647    vv = v;
648    eval_bitwise_and(t, u, vv);
649 }
650 template <class T, class U>
eval_bitwise_and_default(T & t,const T & u,const U & v)651 inline typename enable_if_c<is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
652 {
653    T vv(v);
654    eval_bitwise_and(t, u, vv);
655 }
656 template <class T, class U>
eval_bitwise_and_default(T & t,const U & u,const T & v)657 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v)
658 {
659    eval_bitwise_and(t, v, u);
660 }
661 template <class T, class U, class V>
eval_bitwise_and_default(T & t,const U & u,const V & v)662 inline typename disable_if_c<is_same<T, U>::value || is_same<T, V>::value>::type eval_bitwise_and_default(T& t, const U& u, const V& v)
663 {
664    t = u;
665    eval_bitwise_and(t, v);
666 }
667 template <class T, class U, class V>
eval_bitwise_and(T & t,const U & u,const V & v)668 inline void eval_bitwise_and(T& t, const U& u, const V& v)
669 {
670    eval_bitwise_and_default(t, u, v);
671 }
672 
673 template <class T, class U, class V>
674 void eval_bitwise_or(T& t, const U& u, const V& v);
675 
676 template <class T>
eval_bitwise_or_default(T & t,const T & u,const T & v)677 inline void eval_bitwise_or_default(T& t, const T& u, const T& v)
678 {
679    if(&t == &v)
680    {
681       eval_bitwise_or(t, u);
682    }
683    else if(&t == &u)
684    {
685       eval_bitwise_or(t, v);
686    }
687    else
688    {
689       t = u;
690       eval_bitwise_or(t, v);
691    }
692 }
693 template <class T, class U>
eval_bitwise_or_default(T & t,const T & u,const U & v)694 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v)
695 {
696    T vv;
697    vv = v;
698    eval_bitwise_or(t, u, vv);
699 }
700 template <class T, class U>
eval_bitwise_or_default(T & t,const T & u,const U & v)701 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v)
702 {
703    T vv(v);
704    eval_bitwise_or(t, u, vv);
705 }
706 template <class T, class U>
eval_bitwise_or_default(T & t,const U & u,const T & v)707 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v)
708 {
709    eval_bitwise_or(t, v, u);
710 }
711 template <class T, class U, class V>
eval_bitwise_or_default(T & t,const U & u,const V & v)712 inline void eval_bitwise_or_default(T& t, const U& u, const V& v)
713 {
714    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
715    {
716       eval_bitwise_or(t, u);
717    }
718    else
719    {
720       t = u;
721       eval_bitwise_or(t, v);
722    }
723 }
724 template <class T, class U, class V>
eval_bitwise_or(T & t,const U & u,const V & v)725 inline void eval_bitwise_or(T& t, const U& u, const V& v)
726 {
727    eval_bitwise_or_default(t, u, v);
728 }
729 
730 template <class T, class U, class V>
731 void eval_bitwise_xor(T& t, const U& u, const V& v);
732 
733 template <class T>
eval_bitwise_xor_default(T & t,const T & u,const T & v)734 inline void eval_bitwise_xor_default(T& t, const T& u, const T& v)
735 {
736    if(&t == &v)
737    {
738       eval_bitwise_xor(t, u);
739    }
740    else if(&t == &u)
741    {
742       eval_bitwise_xor(t, v);
743    }
744    else
745    {
746       t = u;
747       eval_bitwise_xor(t, v);
748    }
749 }
750 template <class T, class U>
eval_bitwise_xor_default(T & t,const T & u,const U & v)751 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v)
752 {
753    T vv;
754    vv = v;
755    eval_bitwise_xor(t, u, vv);
756 }
757 template <class T, class U>
eval_bitwise_xor_default(T & t,const T & u,const U & v)758 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v)
759 {
760    T vv(v);
761    eval_bitwise_xor(t, u, vv);
762 }
763 template <class T, class U>
eval_bitwise_xor_default(T & t,const U & u,const T & v)764 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v)
765 {
766    eval_bitwise_xor(t, v, u);
767 }
768 template <class T, class U, class V>
eval_bitwise_xor_default(T & t,const U & u,const V & v)769 inline void eval_bitwise_xor_default(T& t, const U& u, const V& v)
770 {
771    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
772    {
773       eval_bitwise_xor(t, u);
774    }
775    else
776    {
777       t = u;
778       eval_bitwise_xor(t, v);
779    }
780 }
781 template <class T, class U, class V>
eval_bitwise_xor(T & t,const U & u,const V & v)782 inline void eval_bitwise_xor(T& t, const U& u, const V& v)
783 {
784    eval_bitwise_xor_default(t, u, v);
785 }
786 
787 template <class T>
eval_increment(T & val)788 inline void eval_increment(T& val)
789 {
790    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
791    eval_add(val, static_cast<ui_type>(1u));
792 }
793 template <class T>
eval_decrement(T & val)794 inline void eval_decrement(T& val)
795 {
796    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
797    eval_subtract(val, static_cast<ui_type>(1u));
798 }
799 
800 template <class T, class V>
eval_left_shift(T & result,const T & arg,const V val)801 inline void eval_left_shift(T& result, const T& arg, const V val)
802 {
803    result = arg;
804    eval_left_shift(result, val);
805 }
806 
807 template <class T, class V>
eval_right_shift(T & result,const T & arg,const V val)808 inline void eval_right_shift(T& result, const T& arg, const V val)
809 {
810    result = arg;
811    eval_right_shift(result, val);
812 }
813 
814 template <class T>
eval_is_zero(const T & val)815 inline bool eval_is_zero(const T& val)
816 {
817    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
818    return val.compare(static_cast<ui_type>(0)) == 0;
819 }
820 template <class T>
eval_get_sign(const T & val)821 inline int eval_get_sign(const T& val)
822 {
823    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
824    return val.compare(static_cast<ui_type>(0));
825 }
826 
827 template <class T, class V, class U>
assign_components_imp(T & result,const V & v1,const U & v2,const mpl::int_<number_kind_rational> &)828 inline void assign_components_imp(T& result, const V& v1, const U& v2, const mpl::int_<number_kind_rational>&)
829 {
830    result = v1;
831    T t;
832    t = v2;
833    eval_divide(result, t);
834 }
835 
836 template <class T, class V, class U, int N>
assign_components_imp(T & result,const V & v1,const U & v2,const mpl::int_<N> &)837 inline void assign_components_imp(T& result, const V& v1, const U& v2, const mpl::int_<N>&)
838 {
839    typedef typename component_type<number<T> >::type component_number_type;
840 
841    component_number_type x(v1), y(v2);
842    assign_components(result, x.backend(), y.backend());
843 }
844 
845 template <class T, class V, class U>
assign_components(T & result,const V & v1,const U & v2)846 inline void assign_components(T& result, const V& v1, const U& v2)
847 {
848    return assign_components_imp(result, v1, v2, typename number_category<T>::type());
849 }
850 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
851 template <class Result, class Traits>
assign_from_string_view(Result & result,const std::basic_string_view<char,Traits> & view)852 inline void assign_from_string_view(Result& result, const std::basic_string_view<char, Traits>& view)
853 {
854    // since most (all?) backends require a const char* to construct from, we just
855    // convert to that:
856    std::string s(view);
857    result = s.c_str();
858 }
859 template <class Result, class Traits>
assign_from_string_view(Result & result,const std::basic_string_view<char,Traits> & view_x,const std::basic_string_view<char,Traits> & view_y)860 inline void assign_from_string_view(Result& result, const std::basic_string_view<char, Traits>& view_x, const std::basic_string_view<char, Traits>& view_y)
861 {
862    // since most (all?) backends require a const char* to construct from, we just
863    // convert to that:
864    std::string x(view_x), y(view_y);
865    assign_components(result, x.c_str(), y.c_str());
866 }
867 #endif
868 template <class R, int b>
869 struct has_enough_bits
870 {
871    template <class T>
872    struct type : public mpl::and_<mpl::not_<is_same<R, T> >, mpl::bool_<std::numeric_limits<T>::digits >= b> >{};
873 };
874 
875 template <class R>
876 struct terminal
877 {
terminalboost::multiprecision::default_ops::terminal878    terminal(const R& v) : value(v){}
terminalboost::multiprecision::default_ops::terminal879    terminal(){}
operator =boost::multiprecision::default_ops::terminal880    terminal& operator = (R val) { value = val;  return *this; }
881    R value;
operator Rboost::multiprecision::default_ops::terminal882    operator R()const {  return value;  }
883 };
884 
885 template<class R, class B>
886 struct calculate_next_larger_type
887 {
888    // Find which list we're looking through:
889    typedef typename mpl::if_<
890       is_signed<R>,
891       typename B::signed_types,
892       typename mpl::if_<
893          is_unsigned<R>,
894          typename B::unsigned_types,
895          typename B::float_types
896       >::type
897    >::type list_type;
898    // A predicate to find a type with enough bits:
899    typedef typename has_enough_bits<R, std::numeric_limits<R>::digits>::template type<mpl::_> pred_type;
900    // See if the last type is in the list, if so we have to start after this:
901    typedef typename mpl::find_if<
902       list_type,
903       is_same<R, mpl::_>
904    >::type start_last;
905    // Where we're starting from, either the start of the sequence or the last type found:
906    typedef typename mpl::if_<is_same<start_last, typename mpl::end<list_type>::type>, typename mpl::begin<list_type>::type, start_last>::type start_seq;
907    // The range we're searching:
908    typedef mpl::iterator_range<start_seq, typename mpl::end<list_type>::type> range;
909    // Find the next type:
910    typedef typename mpl::find_if<
911       range,
912       pred_type
913    >::type iter_type;
914    // Either the next type, or a "terminal" to indicate we've run out of types to search:
915    typedef typename mpl::eval_if<
916       is_same<typename mpl::end<list_type>::type, iter_type>,
917       mpl::identity<terminal<R> >,
918       mpl::deref<iter_type>
919       >::type type;
920 };
921 
922 template <class R, class T>
check_in_range(const T & t)923 inline typename boost::enable_if_c<boost::is_integral<R>::value, bool>::type check_in_range(const T& t)
924 {
925    // Can t fit in an R?
926    if((t > 0) && std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (t > (std::numeric_limits<R>::max)()))
927       return true;
928    else
929    return false;
930 }
931 
932 template <class R, class B>
eval_convert_to(R * result,const B & backend)933 inline typename boost::enable_if_c<boost::is_integral<R>::value>::type eval_convert_to(R* result, const B& backend)
934 {
935    typedef typename calculate_next_larger_type<R, B>::type next_type;
936    next_type n;
937    eval_convert_to(&n, backend);
938    if(!boost::is_unsigned<R>::value && std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (n > (next_type)(std::numeric_limits<R>::max)()))
939    {
940       *result = (std::numeric_limits<R>::max)();
941    }
942    else if (std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (n < (next_type)(std::numeric_limits<R>::min)()))
943    {
944       *result = (std::numeric_limits<R>::min)();
945    }
946    else
947       *result = static_cast<R>(n);
948 }
949 
950 template <class R, class B>
eval_convert_to(R * result,const B & backend)951 inline typename boost::disable_if_c<boost::is_integral<R>::value>::type eval_convert_to(R* result, const B& backend)
952 {
953    typedef typename calculate_next_larger_type<R, B>::type next_type;
954    next_type n;
955    eval_convert_to(&n, backend);
956    if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && ((n > (next_type)(std::numeric_limits<R>::max)() || (n < (next_type)-(std::numeric_limits<R>::max)()) )))
957    {
958       *result = n > 0 ? (std::numeric_limits<R>::max)() : -(std::numeric_limits<R>::max)();
959    }
960    else
961       *result = static_cast<R>(n);
962 }
963 
964 template <class R, class B>
last_chance_eval_convert_to(terminal<R> * result,const B & backend,const mpl::false_ &)965 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const mpl::false_&)
966 {
967    //
968    // We ran out of types to try for the conversion, try
969    // a lexical_cast and hope for the best:
970    //
971    if (std::numeric_limits<R>::is_integer && !std::numeric_limits<R>::is_signed && (eval_get_sign(backend) < 0))
972       BOOST_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour"));
973    try
974    {
975       result->value = boost::lexical_cast<R>(backend.str(0, std::ios_base::fmtflags(0)));
976    }
977    catch (const bad_lexical_cast&)
978    {
979       if (eval_get_sign(backend) < 0)
980       {
981          *result = std::numeric_limits<R>::is_integer && std::numeric_limits<R>::is_signed ? (std::numeric_limits<R>::min)() : -(std::numeric_limits<R>::max)();
982       }
983       else
984          *result = (std::numeric_limits<R>::max)();
985    }
986 }
987 
988 template <class R, class B>
last_chance_eval_convert_to(terminal<R> * result,const B & backend,const mpl::true_ &)989 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const mpl::true_&)
990 {
991    //
992    // We ran out of types to try for the conversion, try
993    // a lexical_cast and hope for the best:
994    //
995    if (std::numeric_limits<R>::is_integer && !std::numeric_limits<R>::is_signed && (eval_get_sign(backend) < 0))
996       BOOST_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour"));
997    try
998    {
999       B t(backend);
1000       R mask = ~static_cast<R>(0u);
1001       eval_bitwise_and(t, mask);
1002       result->value = boost::lexical_cast<R>(t.str(0, std::ios_base::fmtflags(0)));
1003    }
1004    catch (const bad_lexical_cast&)
1005    {
1006       if (eval_get_sign(backend) < 0)
1007       {
1008          *result = std::numeric_limits<R>::is_integer && std::numeric_limits<R>::is_signed ? (std::numeric_limits<R>::min)() : -(std::numeric_limits<R>::max)();
1009       }
1010       else
1011          *result = (std::numeric_limits<R>::max)();
1012    }
1013 }
1014 
1015 template <class R, class B>
eval_convert_to(terminal<R> * result,const B & backend)1016 inline void eval_convert_to(terminal<R>* result, const B& backend)
1017 {
1018    typedef mpl::bool_<boost::is_unsigned<R>::value && number_category<B>::value == number_kind_integer> tag_type;
1019    last_chance_eval_convert_to(result, backend, tag_type());
1020 }
1021 
1022 template <class B1, class B2, expression_template_option et>
eval_convert_to(terminal<number<B1,et>> * result,const B2 & backend)1023 inline void eval_convert_to(terminal<number<B1, et> >* result, const B2& backend)
1024 {
1025    //
1026    // We ran out of types to try for the conversion, try
1027    // a generic conversion and hope for the best:
1028    //
1029    boost::multiprecision::detail::generic_interconvert(result->value.backend(), backend, number_category<B1>(), number_category<B2>());
1030 }
1031 
1032 template <class B>
eval_convert_to(std::string * result,const B & backend)1033 inline void eval_convert_to(std::string* result, const B& backend)
1034 {
1035    *result = backend.str(0, std::ios_base::fmtflags(0));
1036 }
1037 
1038 template <class B>
eval_convert_to(std::complex<float> * result,const B & backend)1039 inline void eval_convert_to(std::complex<float>* result, const B& backend)
1040 {
1041    typedef typename scalar_result_from_possible_complex<multiprecision::number<B> >::type scalar_type;
1042    scalar_type re, im;
1043    eval_real(re.backend(), backend);
1044    eval_imag(im.backend(), backend);
1045 
1046    *result = std::complex<float>(re.template convert_to<float>(), im.template convert_to<float>());
1047 }
1048 
1049 template <class B>
eval_convert_to(std::complex<double> * result,const B & backend)1050 inline void eval_convert_to(std::complex<double>* result, const B& backend)
1051 {
1052    typedef typename scalar_result_from_possible_complex<multiprecision::number<B> >::type scalar_type;
1053    scalar_type re, im;
1054    eval_real(re.backend(), backend);
1055    eval_imag(im.backend(), backend);
1056 
1057    *result = std::complex<double>(re.template convert_to<double>(), im.template convert_to<double>());
1058 }
1059 
1060 template <class B>
eval_convert_to(std::complex<long double> * result,const B & backend)1061 inline void eval_convert_to(std::complex<long double>* result, const B& backend)
1062 {
1063    typedef typename scalar_result_from_possible_complex<multiprecision::number<B> >::type scalar_type;
1064    scalar_type re, im;
1065    eval_real(re.backend(), backend);
1066    eval_imag(im.backend(), backend);
1067 
1068    *result = std::complex<long double>(re.template convert_to<long double>(), im.template convert_to<long double>());
1069 }
1070 
1071 //
1072 // Functions:
1073 //
1074 template <class T>
eval_abs(T & result,const T & arg)1075 void eval_abs(T& result, const T& arg)
1076 {
1077    typedef typename T::signed_types type_list;
1078    typedef typename mpl::front<type_list>::type front;
1079    result = arg;
1080    if(arg.compare(front(0)) < 0)
1081       result.negate();
1082 }
1083 template <class T>
eval_fabs(T & result,const T & arg)1084 void eval_fabs(T& result, const T& arg)
1085 {
1086    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The fabs function is only valid for floating point types.");
1087    typedef typename T::signed_types type_list;
1088    typedef typename mpl::front<type_list>::type front;
1089    result = arg;
1090    if(arg.compare(front(0)) < 0)
1091       result.negate();
1092 }
1093 
1094 template <class Backend>
eval_fpclassify(const Backend & arg)1095 inline int eval_fpclassify(const Backend& arg)
1096 {
1097    BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_floating_point, "The fpclassify function is only valid for floating point types.");
1098    return eval_is_zero(arg) ? FP_ZERO : FP_NORMAL;
1099 }
1100 
1101 template <class T>
eval_fmod(T & result,const T & a,const T & b)1102 inline void eval_fmod(T& result, const T& a, const T& b)
1103 {
1104    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The fmod function is only valid for floating point types.");
1105    if((&result == &a) || (&result == &b))
1106    {
1107       T temp;
1108       eval_fmod(temp, a, b);
1109       result = temp;
1110       return;
1111    }
1112    switch(eval_fpclassify(a))
1113    {
1114    case FP_ZERO:
1115       result = a;
1116       return;
1117    case FP_INFINITE:
1118    case FP_NAN:
1119       result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1120       errno = EDOM;
1121       return;
1122    }
1123    switch(eval_fpclassify(b))
1124    {
1125    case FP_ZERO:
1126    case FP_NAN:
1127       result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1128       errno = EDOM;
1129       return;
1130    }
1131    T n;
1132    eval_divide(result, a, b);
1133    if(eval_get_sign(result) < 0)
1134       eval_ceil(n, result);
1135    else
1136       eval_floor(n, result);
1137    eval_multiply(n, b);
1138    eval_subtract(result, a, n);
1139 }
1140 template<class T, class A>
eval_fmod(T & result,const T & x,const A & a)1141 inline typename enable_if<is_arithmetic<A>, void>::type eval_fmod(T& result, const T& x, const A& a)
1142 {
1143    typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
1144    typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
1145    cast_type c;
1146    c = a;
1147    eval_fmod(result, x, c);
1148 }
1149 
1150 template<class T, class A>
eval_fmod(T & result,const A & x,const T & a)1151 inline typename enable_if<is_arithmetic<A>, void>::type eval_fmod(T& result, const A& x, const T& a)
1152 {
1153    typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
1154    typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
1155    cast_type c;
1156    c = x;
1157    eval_fmod(result, c, a);
1158 }
1159 
1160 template <class T>
1161 void eval_round(T& result, const T& a);
1162 
1163 template <class T>
eval_remquo(T & result,const T & a,const T & b,int * pi)1164 inline void eval_remquo(T& result, const T& a, const T& b, int* pi)
1165 {
1166    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The remquo function is only valid for floating point types.");
1167    if((&result == &a) || (&result == &b))
1168    {
1169       T temp;
1170       eval_remquo(temp, a, b, pi);
1171       result = temp;
1172       return;
1173    }
1174    T n;
1175    eval_divide(result, a, b);
1176    eval_round(n, result);
1177    eval_convert_to(pi, n);
1178    eval_multiply(n, b);
1179    eval_subtract(result, a, n);
1180 }
1181 template<class T, class A>
eval_remquo(T & result,const T & x,const A & a,int * pi)1182 inline typename enable_if<is_arithmetic<A>, void>::type eval_remquo(T& result, const T& x, const A& a, int* pi)
1183 {
1184    typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
1185    typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
1186    cast_type c;
1187    c = a;
1188    eval_remquo(result, x, c, pi);
1189 }
1190 template<class T, class A>
eval_remquo(T & result,const A & x,const T & a,int * pi)1191 inline typename enable_if<is_arithmetic<A>, void>::type eval_remquo(T& result, const A& x, const T& a, int* pi)
1192 {
1193    typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
1194    typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
1195    cast_type c;
1196    c = x;
1197    eval_remquo(result, c, a, pi);
1198 }
1199 template <class T, class U, class V>
eval_remainder(T & result,const U & a,const V & b)1200 inline void eval_remainder(T& result, const U& a, const V& b)
1201 {
1202    int i;
1203    eval_remquo(result, a, b, &i);
1204 }
1205 
1206 template <class B>
1207 bool eval_gt(const B& a, const B& b);
1208 template <class T, class U>
1209 bool eval_gt(const T& a, const U& b);
1210 template <class B>
1211 bool eval_lt(const B& a, const B& b);
1212 template <class T, class U>
1213 bool eval_lt(const T& a, const U& b);
1214 
1215 template<class T>
eval_fdim(T & result,const T & a,const T & b)1216 inline void eval_fdim(T& result, const T& a, const T& b)
1217 {
1218    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1219    static const ui_type zero = 0u;
1220    switch(eval_fpclassify(b))
1221    {
1222    case FP_NAN:
1223    case FP_INFINITE:
1224       result = zero;
1225       return;
1226    }
1227    switch(eval_fpclassify(a))
1228    {
1229    case FP_NAN:
1230       result = zero;
1231       return;
1232    case FP_INFINITE:
1233       result = a;
1234       return;
1235    }
1236    if(eval_gt(a, b))
1237    {
1238       eval_subtract(result, a, b);
1239    }
1240    else
1241       result = zero;
1242 }
1243 
1244 template<class T, class A>
eval_fdim(T & result,const T & a,const A & b)1245 inline typename boost::enable_if_c<boost::is_arithmetic<A>::value>::type eval_fdim(T& result, const T& a, const A& b)
1246 {
1247    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1248    typedef typename boost::multiprecision::detail::canonical<A, T>::type arithmetic_type;
1249    static const ui_type zero = 0u;
1250    arithmetic_type canonical_b = b;
1251    switch((::boost::math::fpclassify)(b))
1252    {
1253    case FP_NAN:
1254    case FP_INFINITE:
1255       result = zero;
1256       return;
1257    }
1258    switch(eval_fpclassify(a))
1259    {
1260    case FP_NAN:
1261       result = zero;
1262       return;
1263    case FP_INFINITE:
1264       result = a;
1265       return;
1266    }
1267    if(eval_gt(a, canonical_b))
1268    {
1269       eval_subtract(result, a, canonical_b);
1270    }
1271    else
1272       result = zero;
1273 }
1274 
1275 template<class T, class A>
eval_fdim(T & result,const A & a,const T & b)1276 inline typename boost::enable_if_c<boost::is_arithmetic<A>::value>::type eval_fdim(T& result, const A& a, const T& b)
1277 {
1278    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1279    typedef typename boost::multiprecision::detail::canonical<A, T>::type arithmetic_type;
1280    static const ui_type zero = 0u;
1281    arithmetic_type canonical_a = a;
1282    switch(eval_fpclassify(b))
1283    {
1284    case FP_NAN:
1285    case FP_INFINITE:
1286       result = zero;
1287       return;
1288    }
1289    switch((::boost::math::fpclassify)(a))
1290    {
1291    case FP_NAN:
1292       result = zero;
1293       return;
1294    case FP_INFINITE:
1295       result = std::numeric_limits<number<T> >::infinity().backend();
1296       return;
1297    }
1298    if(eval_gt(canonical_a, b))
1299    {
1300       eval_subtract(result, canonical_a, b);
1301    }
1302    else
1303       result = zero;
1304 }
1305 
1306 template <class T>
eval_trunc(T & result,const T & a)1307 inline void eval_trunc(T& result, const T& a)
1308 {
1309    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The trunc function is only valid for floating point types.");
1310    switch(eval_fpclassify(a))
1311    {
1312    case FP_NAN:
1313       errno = EDOM;
1314       // fallthrough...
1315    case FP_ZERO:
1316    case FP_INFINITE:
1317       result = a;
1318       return;
1319    }
1320    if(eval_get_sign(a) < 0)
1321       eval_ceil(result, a);
1322    else
1323       eval_floor(result, a);
1324 }
1325 
1326 template <class T>
eval_modf(T & result,T const & arg,T * pipart)1327 inline void eval_modf(T& result, T const& arg, T* pipart)
1328 {
1329    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1330    int c = eval_fpclassify(arg);
1331    if(c == (int)FP_NAN)
1332    {
1333       if(pipart)
1334          *pipart = arg;
1335       result = arg;
1336       return;
1337    }
1338    else if(c == (int)FP_INFINITE)
1339    {
1340       if(pipart)
1341          *pipart = arg;
1342       result = ui_type(0u);
1343       return;
1344    }
1345    if(pipart)
1346    {
1347       eval_trunc(*pipart, arg);
1348       eval_subtract(result, arg, *pipart);
1349    }
1350    else
1351    {
1352       T ipart;
1353       eval_trunc(ipart, arg);
1354       eval_subtract(result, arg, ipart);
1355    }
1356 }
1357 
1358 template <class T>
eval_round(T & result,const T & a)1359 inline void eval_round(T& result, const T& a)
1360 {
1361    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The round function is only valid for floating point types.");
1362    typedef typename boost::multiprecision::detail::canonical<float, T>::type fp_type;
1363    int c = eval_fpclassify(a);
1364    if(c == (int)FP_NAN)
1365    {
1366       result = a;
1367       errno = EDOM;
1368       return;
1369    }
1370    if((c == FP_ZERO) || (c == (int)FP_INFINITE))
1371    {
1372       result = a;
1373    }
1374    else if(eval_get_sign(a) < 0)
1375    {
1376       eval_subtract(result, a, fp_type(0.5f));
1377       eval_ceil(result, result);
1378    }
1379    else
1380    {
1381       eval_add(result, a, fp_type(0.5f));
1382       eval_floor(result, result);
1383    }
1384 }
1385 
1386 template <class B>
1387 void eval_lcm(B& result, const B& a, const B& b);
1388 template <class B>
1389 void eval_gcd(B& result, const B& a, const B& b);
1390 
1391 template <class T, class Arithmetic>
eval_gcd(T & result,const T & a,const Arithmetic & b)1392 inline typename enable_if<is_integral<Arithmetic> >::type eval_gcd(T& result, const T& a, const Arithmetic& b)
1393 {
1394    typedef typename boost::multiprecision::detail::canonical<Arithmetic, T>::type si_type;
1395    using default_ops::eval_gcd;
1396    T t;
1397    t = static_cast<si_type>(b);
1398    eval_gcd(result, a, t);
1399 }
1400 template <class T, class Arithmetic>
eval_gcd(T & result,const Arithmetic & a,const T & b)1401 inline typename enable_if<is_integral<Arithmetic> >::type eval_gcd(T& result, const Arithmetic& a, const T& b)
1402 {
1403    eval_gcd(result, b, a);
1404 }
1405 template <class T, class Arithmetic>
eval_lcm(T & result,const T & a,const Arithmetic & b)1406 inline typename enable_if<is_integral<Arithmetic> >::type eval_lcm(T& result, const T& a, const Arithmetic& b)
1407 {
1408    typedef typename boost::multiprecision::detail::canonical<Arithmetic, T>::type si_type;
1409    using default_ops::eval_lcm;
1410    T t;
1411    t = static_cast<si_type>(b);
1412    eval_lcm(result, a, t);
1413 }
1414 template <class T, class Arithmetic>
eval_lcm(T & result,const Arithmetic & a,const T & b)1415 inline typename enable_if<is_integral<Arithmetic> >::type eval_lcm(T& result, const Arithmetic& a, const T& b)
1416 {
1417    eval_lcm(result, b, a);
1418 }
1419 
1420 template <class T>
eval_lsb(const T & val)1421 inline unsigned eval_lsb(const T& val)
1422 {
1423    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1424    int c = eval_get_sign(val);
1425    if(c == 0)
1426    {
1427       BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
1428    }
1429    if(c < 0)
1430    {
1431       BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
1432    }
1433    unsigned result = 0;
1434    T mask, t;
1435    mask = ui_type(1);
1436    do
1437    {
1438       eval_bitwise_and(t, mask, val);
1439       ++result;
1440       eval_left_shift(mask, 1);
1441    }
1442    while(eval_is_zero(t));
1443 
1444    return --result;
1445 }
1446 
1447 template <class T>
eval_msb(const T & val)1448 inline int eval_msb(const T& val)
1449 {
1450    int c = eval_get_sign(val);
1451    if(c == 0)
1452    {
1453       BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
1454    }
1455    if(c < 0)
1456    {
1457       BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
1458    }
1459    //
1460    // This implementation is really really rubbish - it does
1461    // a linear scan for the most-significant-bit.  We should really
1462    // do a binary search, but as none of our backends actually needs
1463    // this implementation, we'll leave it for now.  In fact for most
1464    // backends it's likely that there will always be a more efficient
1465    // native implementation possible.
1466    //
1467    unsigned result = 0;
1468    T t(val);
1469    while(!eval_is_zero(t))
1470    {
1471       eval_right_shift(t, 1);
1472       ++result;
1473    }
1474    return --result;
1475 }
1476 
1477 template <class T>
eval_bit_test(const T & val,unsigned index)1478 inline bool eval_bit_test(const T& val, unsigned index)
1479 {
1480    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1481    T mask, t;
1482    mask = ui_type(1);
1483    eval_left_shift(mask, index);
1484    eval_bitwise_and(t, mask, val);
1485    return !eval_is_zero(t);
1486 }
1487 
1488 template <class T>
eval_bit_set(T & val,unsigned index)1489 inline void eval_bit_set(T& val, unsigned index)
1490 {
1491    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1492    T mask;
1493    mask = ui_type(1);
1494    eval_left_shift(mask, index);
1495    eval_bitwise_or(val, mask);
1496 }
1497 
1498 template <class T>
eval_bit_flip(T & val,unsigned index)1499 inline void eval_bit_flip(T& val, unsigned index)
1500 {
1501    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1502    T mask;
1503    mask = ui_type(1);
1504    eval_left_shift(mask, index);
1505    eval_bitwise_xor(val, mask);
1506 }
1507 
1508 template <class T>
eval_bit_unset(T & val,unsigned index)1509 inline void eval_bit_unset(T& val, unsigned index)
1510 {
1511    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1512    T mask, t;
1513    mask = ui_type(1);
1514    eval_left_shift(mask, index);
1515    eval_bitwise_and(t, mask, val);
1516    if(!eval_is_zero(t))
1517       eval_bitwise_xor(val, mask);
1518 }
1519 
1520 template <class B>
eval_integer_sqrt(B & s,B & r,const B & x)1521 void eval_integer_sqrt(B& s, B& r, const B& x)
1522 {
1523    //
1524    // This is slow bit-by-bit integer square root, see for example
1525    // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
1526    // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
1527    // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
1528    // at some point.
1529    //
1530    typedef typename boost::multiprecision::detail::canonical<unsigned char, B>::type ui_type;
1531 
1532    s = ui_type(0u);
1533    if(eval_get_sign(x) == 0)
1534    {
1535       r = ui_type(0u);
1536       return;
1537    }
1538    int g = eval_msb(x);
1539    if(g <= 1)
1540    {
1541       s = ui_type(1);
1542       eval_subtract(r, x, s);
1543       return;
1544    }
1545 
1546    B t;
1547    r = x;
1548    g /= 2;
1549    int org_g = g;
1550    eval_bit_set(s, g);
1551    eval_bit_set(t, 2 * g);
1552    eval_subtract(r, x, t);
1553    --g;
1554    if(eval_get_sign(r) == 0)
1555       return;
1556    int msbr = eval_msb(r);
1557    do
1558    {
1559       if(msbr >= org_g + g + 1)
1560       {
1561          t = s;
1562          eval_left_shift(t, g + 1);
1563          eval_bit_set(t, 2 * g);
1564          if(t.compare(r) <= 0)
1565          {
1566             BOOST_ASSERT(g >= 0);
1567             eval_bit_set(s, g);
1568             eval_subtract(r, t);
1569             if(eval_get_sign(r) == 0)
1570                return;
1571             msbr = eval_msb(r);
1572          }
1573       }
1574       --g;
1575    }
1576    while(g >= 0);
1577 }
1578 
1579 template <class B>
eval_conj(B & result,const B & val)1580 inline void eval_conj(B& result, const B& val)
1581 {
1582    result = val;  // assume non-complex result.
1583 }
1584 template <class B>
eval_proj(B & result,const B & val)1585 inline void eval_proj(B& result, const B& val)
1586 {
1587    result = val;  // assume non-complex result.
1588 }
1589 
1590 //
1591 // These have to implemented by the backend, declared here so that our macro generated code compiles OK.
1592 //
1593 template <class T>
1594 typename enable_if_c<sizeof(T) == 0>::type eval_floor();
1595 template <class T>
1596 typename enable_if_c<sizeof(T) == 0>::type eval_ceil();
1597 template <class T>
1598 typename enable_if_c<sizeof(T) == 0>::type eval_trunc();
1599 template <class T>
1600 typename enable_if_c<sizeof(T) == 0>::type eval_sqrt();
1601 template <class T>
1602 typename enable_if_c<sizeof(T) == 0>::type eval_ldexp();
1603 template <class T>
1604 typename enable_if_c<sizeof(T) == 0>::type eval_frexp();
1605 // TODO implement default versions of these:
1606 template <class T>
1607 typename enable_if_c<sizeof(T) == 0>::type eval_asinh();
1608 template <class T>
1609 typename enable_if_c<sizeof(T) == 0>::type eval_acosh();
1610 template <class T>
1611 typename enable_if_c<sizeof(T) == 0>::type eval_atanh();
1612 
1613 //
1614 // eval_logb and eval_scalbn simply assume base 2 and forward to
1615 // eval_ldexp and eval_frexp:
1616 //
1617 template <class B>
eval_ilogb(const B & val)1618 inline typename B::exponent_type eval_ilogb(const B& val)
1619 {
1620    BOOST_STATIC_ASSERT_MSG(!std::numeric_limits<number<B> >::is_specialized || (std::numeric_limits<number<B> >::radix == 2), "The default implementation of ilogb requires a base 2 number type");
1621    typename B::exponent_type e;
1622    switch(eval_fpclassify(val))
1623    {
1624    case FP_NAN:
1625 #ifdef FP_ILOGBNAN
1626       return FP_ILOGBNAN > 0 ? (std::numeric_limits<typename B::exponent_type>::max)() : (std::numeric_limits<typename B::exponent_type>::min)();
1627 #else
1628       return (std::numeric_limits<typename B::exponent_type>::max)();
1629 #endif
1630    case FP_INFINITE:
1631       return (std::numeric_limits<typename B::exponent_type>::max)();
1632    case FP_ZERO:
1633       return (std::numeric_limits<typename B::exponent_type>::min)();
1634    }
1635    B result;
1636    eval_frexp(result, val, &e);
1637    return e - 1;
1638 }
1639 
1640 template <class T>
1641 int eval_signbit(const T& val);
1642 
1643 template <class B>
eval_logb(B & result,const B & val)1644 inline void eval_logb(B& result, const B& val)
1645 {
1646    switch(eval_fpclassify(val))
1647    {
1648    case FP_NAN:
1649       result = val;
1650       errno = EDOM;
1651       return;
1652    case FP_ZERO:
1653       result = std::numeric_limits<number<B> >::infinity().backend();
1654       result.negate();
1655       errno = ERANGE;
1656       return;
1657    case FP_INFINITE:
1658       result = val;
1659       if(eval_signbit(val))
1660          result.negate();
1661       return;
1662    }
1663    typedef typename boost::mpl::if_c<boost::is_same<boost::intmax_t, long>::value, boost::long_long_type, boost::intmax_t>::type max_t;
1664    result = static_cast<max_t>(eval_ilogb(val));
1665 }
1666 template <class B, class A>
eval_scalbn(B & result,const B & val,A e)1667 inline void eval_scalbn(B& result, const B& val, A e)
1668 {
1669    BOOST_STATIC_ASSERT_MSG(!std::numeric_limits<number<B> >::is_specialized || (std::numeric_limits<number<B> >::radix == 2), "The default implementation of scalbn requires a base 2 number type");
1670    eval_ldexp(result, val, static_cast<typename B::exponent_type>(e));
1671 }
1672 template <class B, class A>
eval_scalbln(B & result,const B & val,A e)1673 inline void eval_scalbln(B& result, const B& val, A e)
1674 {
1675    eval_scalbn(result, val, e);
1676 }
1677 
1678 template <class T>
is_arg_nan(const T & val,mpl::true_ const &,const mpl::false_ &)1679 inline bool is_arg_nan(const T& val, mpl::true_ const&, const mpl::false_&)
1680 {
1681    return eval_fpclassify(val) == FP_NAN;
1682 }
1683 template <class T>
is_arg_nan(const T & val,mpl::false_ const &,const mpl::true_ &)1684 inline bool is_arg_nan(const T& val, mpl::false_ const&, const mpl::true_&)
1685 {
1686    return (boost::math::isnan)(val);
1687 }
1688 template <class T>
is_arg_nan(const T &,mpl::false_ const &,const mpl::false_ &)1689 inline bool is_arg_nan(const T&, mpl::false_ const&, const mpl::false_&)
1690 {
1691    return false;
1692 }
1693 
1694 template <class T>
is_arg_nan(const T & val)1695 inline bool is_arg_nan(const T& val)
1696 {
1697    return is_arg_nan(val, mpl::bool_<boost::multiprecision::detail::is_backend<T>::value>(), is_floating_point<T>());
1698 }
1699 
1700 template <class T, class U, class V>
eval_fmax(T & result,const U & a,const V & b)1701 inline void eval_fmax(T& result, const U& a, const V& b)
1702 {
1703    if(is_arg_nan(a))
1704       result = number<T>::canonical_value(b);
1705    else if(is_arg_nan(b))
1706       result = number<T>::canonical_value(a);
1707    else if(eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1708       result = number<T>::canonical_value(b);
1709    else
1710       result = number<T>::canonical_value(a);
1711 }
1712 template <class T, class U, class V>
eval_fmin(T & result,const U & a,const V & b)1713 inline void eval_fmin(T& result, const U& a, const V& b)
1714 {
1715    if(is_arg_nan(a))
1716       result = number<T>::canonical_value(b);
1717    else if(is_arg_nan(b))
1718       result = number<T>::canonical_value(a);
1719    else if(eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1720       result = number<T>::canonical_value(a);
1721    else
1722       result = number<T>::canonical_value(b);
1723 }
1724 
1725 template <class R, class T, class U>
eval_hypot(R & result,const T & a,const U & b)1726 inline void eval_hypot(R& result, const T& a, const U& b)
1727 {
1728    //
1729    // Normalize x and y, so that both are positive and x >= y:
1730    //
1731    R x, y;
1732    x = number<R>::canonical_value(a);
1733    y = number<R>::canonical_value(b);
1734    if(eval_get_sign(x) < 0)
1735       x.negate();
1736    if(eval_get_sign(y) < 0)
1737       y.negate();
1738 
1739    // Special case, see C99 Annex F.
1740    // The order of the if's is important: do not change!
1741    int c1 = eval_fpclassify(x);
1742    int c2 = eval_fpclassify(y);
1743 
1744    if(c1 == FP_ZERO)
1745    {
1746       result = y;
1747       return;
1748    }
1749    if(c2 == FP_ZERO)
1750    {
1751       result = x;
1752       return;
1753    }
1754    if(c1 == FP_INFINITE)
1755    {
1756       result = x;
1757       return;
1758    }
1759    if((c2 == FP_INFINITE) || (c2 == FP_NAN))
1760    {
1761       result = y;
1762       return;
1763    }
1764    if(c1 == FP_NAN)
1765    {
1766       result = x;
1767       return;
1768    }
1769 
1770    if(eval_gt(y, x))
1771       x.swap(y);
1772 
1773    eval_multiply(result, x, std::numeric_limits<number<R> >::epsilon().backend());
1774 
1775    if(eval_gt(result, y))
1776    {
1777       result = x;
1778       return;
1779    }
1780 
1781    R rat;
1782    eval_divide(rat, y, x);
1783    eval_multiply(result, rat, rat);
1784    eval_increment(result);
1785    eval_sqrt(rat, result);
1786    eval_multiply(result, rat, x);
1787 }
1788 
1789 template <class R, class T>
eval_nearbyint(R & result,const T & a)1790 inline void eval_nearbyint(R& result, const T& a)
1791 {
1792    eval_round(result, a);
1793 }
1794 template <class R, class T>
eval_rint(R & result,const T & a)1795 inline void eval_rint(R& result, const T& a)
1796 {
1797    eval_nearbyint(result, a);
1798 }
1799 
1800 template <class T>
eval_signbit(const T & val)1801 inline int eval_signbit(const T& val)
1802 {
1803    return eval_get_sign(val) < 0 ? 1 : 0;
1804 }
1805 
1806 //
1807 // Real and imaginary parts:
1808 //
1809 template <class To, class From>
eval_real(To & to,const From & from)1810 inline void eval_real(To& to, const From& from)
1811 {
1812    to = from;
1813 }
1814 template <class To, class From>
eval_imag(To & to,const From &)1815 inline void eval_imag(To& to, const From& )
1816 {
1817    typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
1818    to = ui_type(0);
1819 }
1820 
1821 } namespace default_ops_adl {
1822 
1823 template <class To, class From>
eval_set_real_imp(To & to,const From & from)1824 inline void eval_set_real_imp(To& to, const From& from)
1825 {
1826    typedef typename component_type<number<To> >::type to_component_type;
1827    typename to_component_type::backend_type to_component;
1828    to_component = from;
1829    eval_set_real(to, to_component);
1830 }
1831 template <class To, class From>
eval_set_imag_imp(To & to,const From & from)1832 inline void eval_set_imag_imp(To& to, const From& from)
1833 {
1834    typedef typename component_type<number<To> >::type to_component_type;
1835    typename to_component_type::backend_type to_component;
1836    to_component = from;
1837    eval_set_imag(to, to_component);
1838 }
1839 
1840 } namespace default_ops{
1841 
1842 template <class To, class From>
eval_set_real(To & to,const From & from)1843 inline typename enable_if_c<number_category<To>::value == number_kind_complex>::type eval_set_real(To& to, const From& from)
1844 {
1845    default_ops_adl::eval_set_real_imp(to, from);
1846 }
1847 template <class To, class From>
eval_set_real(To & to,const From & from)1848 inline typename disable_if_c<number_category<To>::value == number_kind_complex>::type eval_set_real(To& to, const From& from)
1849 {
1850    to = from;
1851 }
1852 
1853 template <class To, class From>
eval_set_imag(To & to,const From & from)1854 inline void eval_set_imag(To& to, const From& from)
1855 {
1856    default_ops_adl::eval_set_imag_imp(to, from);
1857 }
1858 
1859 template <class T>
eval_set_real(T & to,const T & from)1860 inline void eval_set_real(T& to, const T& from)
1861 {
1862    to = from;
1863 }
1864 template <class T>
eval_set_imag(T &,const T &)1865 void eval_set_imag(T&, const T&)
1866 {
1867    BOOST_STATIC_ASSERT_MSG(sizeof(T) == INT_MAX, "eval_set_imag needs to be specialised for each specific backend");
1868 }
1869 
1870 //
1871 // These functions are implemented in separate files, but expanded inline here,
1872 // DO NOT CHANGE THE ORDER OF THESE INCLUDES:
1873 //
1874 #include <boost/multiprecision/detail/functions/constants.hpp>
1875 #include <boost/multiprecision/detail/functions/pow.hpp>
1876 #include <boost/multiprecision/detail/functions/trig.hpp>
1877 
1878 }
1879 
1880 //
1881 // Default versions of floating point classification routines:
1882 //
1883 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1884 inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1885 {
1886    using multiprecision::default_ops::eval_fpclassify;
1887    return eval_fpclassify(arg.backend());
1888 }
1889 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1890 inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1891 {
1892    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1893    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1894 }
1895 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1896 inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1897 {
1898    int v = fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg);
1899    return (v != (int)FP_INFINITE) && (v != (int)FP_NAN);
1900 }
1901 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1902 inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1903 {
1904    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1905    return isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1906 }
1907 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1908 inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1909 {
1910    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_NAN;
1911 }
1912 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1913 inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1914 {
1915    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1916    return isnan BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1917 }
1918 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1919 inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1920 {
1921    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_INFINITE;
1922 }
1923 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1924 inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1925 {
1926    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1927    return isinf BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1928 }
1929 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1930 inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1931 {
1932    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_NORMAL;
1933 }
1934 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1935 inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1936 {
1937    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1938    return isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1939 }
1940 
1941 // Default versions of sign manipulation functions, if individual backends can do better than this
1942 // (for example with signed zero), then they should overload these functions further:
1943 
1944 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1945 inline int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1946 {
1947    return arg.sign();
1948 }
1949 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1950 inline int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1951 {
1952    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1953    return sign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1954 }
1955 
1956 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1957 inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1958 {
1959    using default_ops::eval_signbit;
1960    return eval_signbit(arg.backend());
1961 }
1962 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1963 inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1964 {
1965    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1966    return signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1967 }
1968 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1969 inline multiprecision::number<Backend, ExpressionTemplates> changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1970 {
1971    return -arg;
1972 }
1973 template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)1974 inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1975 {
1976    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1977    return changesign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
1978 }
1979 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & a,const multiprecision::number<Backend,ExpressionTemplates> & b)1980 inline multiprecision::number<Backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
1981 {
1982    return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? (boost::multiprecision::changesign)(a) : a;
1983 }
1984 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & a,const multiprecision::detail::expression<tag,A1,A2,A3,A4> & b)1985 inline multiprecision::number<Backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& b)
1986 {
1987    return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
1988 }
1989 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & a,const multiprecision::number<Backend,ExpressionTemplates> & b)1990 inline multiprecision::number<Backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
1991 {
1992    return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
1993 }
1994 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & a,const multiprecision::detail::expression<tagb,A1b,A2b,A3b,A4b> & b)1995 inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
1996 {
1997    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1998    return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
1999 }
2000 //
2001 // real and imag:
2002 //
2003 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2004 inline typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
real(const multiprecision::number<Backend,ExpressionTemplates> & a)2005    real(const multiprecision::number<Backend, ExpressionTemplates>& a)
2006 {
2007    using default_ops::eval_real;
2008    typedef typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result_type;
2009    boost::multiprecision::detail::scoped_default_precision<result_type> precision_guard(a);
2010    result_type result;
2011    eval_real(result.backend(), a.backend());
2012    return result;
2013 }
2014 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2015 inline typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
imag(const multiprecision::number<Backend,ExpressionTemplates> & a)2016    imag(const multiprecision::number<Backend, ExpressionTemplates>& a)
2017 {
2018    using default_ops::eval_imag;
2019    typedef typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result_type;
2020    boost::multiprecision::detail::scoped_default_precision<result_type> precision_guard(a);
2021    result_type result;
2022    eval_imag(result.backend(), a.backend());
2023    return result;
2024 }
2025 
2026 template <class tag, class A1, class A2, class A3, class A4>
2027 inline typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
real(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2028    real(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2029 {
2030    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2031    detail::scoped_default_precision<value_type> precision_guard(arg);
2032    return real(value_type(arg));
2033 }
2034 
2035 template <class tag, class A1, class A2, class A3, class A4>
2036 inline typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
imag(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2037    imag(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2038 {
2039    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2040    detail::scoped_default_precision<value_type> precision_guard(arg);
2041    return imag(value_type(arg));
2042 }
2043 
2044 //
2045 // Complex number functions, these are overloaded at the Backend level, we just provide the
2046 // expression template versions here, plus overloads for non-complex types:
2047 //
2048 template <class T, expression_template_option ExpressionTemplates>
2049 inline typename boost::lazy_enable_if_c<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates> > >::type
abs(const number<T,ExpressionTemplates> & v)2050    abs(const number<T, ExpressionTemplates>& v)
2051 {
2052    return BOOST_MP_MOVE(boost::math::hypot(real(v), imag(v)));
2053 }
2054 template <class tag, class A1, class A2, class A3, class A4>
2055 inline typename boost::lazy_enable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_complex, component_type<typename detail::expression<tag, A1, A2, A3, A4>::result_type> >::type
abs(const detail::expression<tag,A1,A2,A3,A4> & v)2056    abs(const detail::expression<tag, A1, A2, A3, A4>& v)
2057 {
2058    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2059    return BOOST_MP_MOVE(abs(static_cast<number_type>(v)));
2060 }
2061 
2062 template <class T, expression_template_option ExpressionTemplates>
2063 inline typename enable_if_c<number_category<T>::value == number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
arg(const number<T,ExpressionTemplates> & v)2064 arg(const number<T, ExpressionTemplates>& v)
2065 {
2066    return BOOST_MP_MOVE(atan2(imag(v), real(v)));
2067 }
2068 template <class T, expression_template_option ExpressionTemplates>
2069 inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
arg(const number<T,ExpressionTemplates> &)2070 arg(const number<T, ExpressionTemplates>&)
2071 {
2072    return 0;
2073 }
2074 template <class tag, class A1, class A2, class A3, class A4>
2075 inline typename enable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_complex || number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
arg(const detail::expression<tag,A1,A2,A3,A4> & v)2076 arg(const detail::expression<tag, A1, A2, A3, A4>& v)
2077 {
2078    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2079    return BOOST_MP_MOVE(arg(static_cast<number_type>(v)));
2080 }
2081 
2082 template <class T, expression_template_option ExpressionTemplates>
2083 inline typename boost::lazy_enable_if_c<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates> > >::type
norm(const number<T,ExpressionTemplates> & v)2084 norm(const number<T, ExpressionTemplates>& v)
2085 {
2086    typename component_type<number<T, ExpressionTemplates> >::type a(real(v)), b(imag(v));
2087    return BOOST_MP_MOVE(a * a + b * b);
2088 }
2089 template <class T, expression_template_option ExpressionTemplates>
2090 inline typename boost::enable_if_c<number_category<T>::value != number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type >::type
norm(const number<T,ExpressionTemplates> & v)2091 norm(const number<T, ExpressionTemplates>& v)
2092 {
2093    return v * v;
2094 }
2095 template <class tag, class A1, class A2, class A3, class A4>
2096 inline typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
norm(const detail::expression<tag,A1,A2,A3,A4> & v)2097 norm(const detail::expression<tag, A1, A2, A3, A4>& v)
2098 {
2099    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2100    return BOOST_MP_MOVE(norm(static_cast<number_type>(v)));
2101 }
2102 
2103 template <class Backend, expression_template_option ExpressionTemplates>
polar(number<Backend,ExpressionTemplates> const & r,number<Backend,ExpressionTemplates> const & theta)2104 typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r, number<Backend, ExpressionTemplates> const& theta)
2105 {
2106    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2107 }
2108 
2109 template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
2110 typename enable_if_c<boost::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2111    typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
polar(detail::expression<tag,A1,A2,A3,A4> const & r,number<Backend,ExpressionTemplates> const & theta)2112       polar(detail::expression<tag, A1, A2, A3, A4> const& r, number<Backend, ExpressionTemplates> const& theta)
2113 {
2114    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2115 }
2116 
2117 template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2118 typename enable_if_c<boost::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2119    typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
polar(number<Backend,ExpressionTemplates> const & r,detail::expression<tag,A1,A2,A3,A4> const & theta)2120       polar(number<Backend, ExpressionTemplates> const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2121 {
2122    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2123 }
2124 
2125 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2126 typename enable_if_c<boost::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, typename detail::expression<tagb, A1b, A2b, A3b, A4b>::result_type >::value,
2127    typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type >::type>::type
polar(detail::expression<tag,A1,A2,A3,A4> const & r,detail::expression<tagb,A1b,A2b,A3b,A4b> const & theta)2128       polar(detail::expression<tag, A1, A2, A3, A4> const& r, detail::expression<tagb, A1b, A2b, A3b, A4b> const& theta)
2129 {
2130    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type scalar_type;
2131    return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2132 }
2133 //
2134 // We also allow the first argument to polar to be an arithmetic type (probably a literal):
2135 //
2136 template <class Scalar, class Backend, expression_template_option ExpressionTemplates>
2137 typename boost::enable_if_c<boost::is_arithmetic<Scalar>::value, typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
polar(Scalar const & r,number<Backend,ExpressionTemplates> const & theta)2138    polar(Scalar const& r, number<Backend, ExpressionTemplates> const& theta)
2139 {
2140    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2141 }
2142 
2143 template <class tag, class A1, class A2, class A3, class A4, class Scalar>
2144 typename enable_if_c<boost::is_arithmetic<Scalar>::value,
2145    typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
polar(Scalar const & r,detail::expression<tag,A1,A2,A3,A4> const & theta)2146    polar(Scalar const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2147 {
2148    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type scalar_type;
2149    return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2150 }
2151 //
2152 // Single argument overloads:
2153 //
2154 template <class Backend, expression_template_option ExpressionTemplates>
polar(number<Backend,ExpressionTemplates> const & r)2155 typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r)
2156 {
2157    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(r);
2158 }
2159 
2160 template <class tag, class A1, class A2, class A3, class A4>
2161 typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
polar(detail::expression<tag,A1,A2,A3,A4> const & r)2162    polar(detail::expression<tag, A1, A2, A3, A4> const& r)
2163 {
2164    return typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type(r);
2165 }
2166 
2167 
2168 
2169 } // namespace multiprecision
2170 
2171 namespace math {
2172 
2173    //
2174    // Import Math functions here, so they can be found by Boost.Math:
2175    //
2176    using boost::multiprecision::signbit;
2177    using boost::multiprecision::sign;
2178    using boost::multiprecision::copysign;
2179    using boost::multiprecision::changesign;
2180    using boost::multiprecision::fpclassify;
2181    using boost::multiprecision::isinf;
2182    using boost::multiprecision::isnan;
2183    using boost::multiprecision::isnormal;
2184    using boost::multiprecision::isfinite;
2185 
2186 }
2187 
2188 namespace multiprecision{
2189 
2190    typedef ::boost::math::policies::policy<
2191       ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>,
2192       ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>,
2193       ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>,
2194       ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>,
2195       ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>
2196    > c99_error_policy;
2197 
2198    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2199    inline typename boost::enable_if_c<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2200       asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2201    {
2202       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2203       return boost::math::asinh(arg, c99_error_policy());
2204    }
2205    template <class tag, class A1, class A2, class A3, class A4>
2206    inline typename boost::enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2207          asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2208    {
2209       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2210       detail::scoped_default_precision<value_type > precision_guard(arg);
2211       return asinh(value_type(arg));
2212    }
2213    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2214    inline typename boost::enable_if_c<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2215       acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2216    {
2217       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2218       return boost::math::acosh(arg, c99_error_policy());
2219    }
2220    template <class tag, class A1, class A2, class A3, class A4>
2221    inline typename boost::enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2222       acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2223    {
2224       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2225       detail::scoped_default_precision<value_type > precision_guard(arg);
2226       return acosh(value_type(arg));
2227    }
2228    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2229    inline typename boost::enable_if_c<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2230       atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2231    {
2232       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2233       return boost::math::atanh(arg, c99_error_policy());
2234    }
2235    template <class tag, class A1, class A2, class A3, class A4>
2236    inline typename boost::enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2237       atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2238    {
2239       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2240       detail::scoped_default_precision<value_type > precision_guard(arg);
2241       return atanh(value_type(arg));
2242    }
2243    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2244    inline multiprecision::number<Backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2245    {
2246       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2247       return boost::math::cbrt(arg, c99_error_policy());
2248    }
2249    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2250    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2251    {
2252       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2253       detail::scoped_default_precision<value_type> precision_guard(arg);
2254       return cbrt(value_type(arg));
2255    }
2256    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2257    inline multiprecision::number<Backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2258    {
2259       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2260       return boost::math::erf(arg, c99_error_policy());
2261    }
2262    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2263    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2264    {
2265       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2266       detail::scoped_default_precision<value_type> precision_guard(arg);
2267       return erf(value_type(arg));
2268    }
2269    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2270    inline multiprecision::number<Backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2271    {
2272       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2273       return boost::math::erfc(arg, c99_error_policy());
2274    }
2275    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2276    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2277    {
2278       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2279       detail::scoped_default_precision<value_type> precision_guard(arg);
2280       return erfc(value_type(arg));
2281    }
2282    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2283    inline multiprecision::number<Backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2284    {
2285       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2286       return boost::math::expm1(arg, c99_error_policy());
2287    }
2288    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2289    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2290    {
2291       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2292       detail::scoped_default_precision<value_type> precision_guard(arg);
2293       return expm1(value_type(arg));
2294    }
2295    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2296    inline multiprecision::number<Backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2297    {
2298       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2299       multiprecision::number<Backend, ExpressionTemplates> result;
2300       result = boost::math::lgamma(arg, c99_error_policy());
2301       if((boost::multiprecision::isnan)(result) && !(boost::multiprecision::isnan)(arg))
2302       {
2303          result = std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::infinity();
2304          errno = ERANGE;
2305       }
2306       return result;
2307    }
2308    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2309    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2310    {
2311       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2312       detail::scoped_default_precision<value_type> precision_guard(arg);
2313       return lgamma(value_type(arg));
2314    }
2315    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2316    inline multiprecision::number<Backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2317    {
2318       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2319       if((arg == 0) && std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::has_infinity)
2320       {
2321          errno = ERANGE;
2322          return 1 / arg;
2323       }
2324       return boost::math::tgamma(arg, c99_error_policy());
2325    }
2326    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2327    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2328    {
2329       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2330       detail::scoped_default_precision<value_type> precision_guard(arg);
2331       return tgamma(value_type(arg));
2332    }
2333 
2334    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2335    inline long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2336    {
2337       return lround(arg);
2338    }
2339    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2340    inline long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2341    {
2342       return lround(arg);
2343    }
2344 #ifndef BOOST_NO_LONG_LONG
2345    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2346    inline boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2347    {
2348       return llround(arg);
2349    }
2350    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2351    inline boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2352    {
2353       return llround(arg);
2354    }
2355 #endif
2356    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)2357    inline multiprecision::number<Backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2358    {
2359       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2360       return boost::math::log1p(arg, c99_error_policy());
2361    }
2362    template <class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & arg)2363    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2364    {
2365       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2366       detail::scoped_default_precision<value_type> precision_guard(arg);
2367       return log1p(value_type(arg));
2368    }
2369 
2370    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & a,const multiprecision::number<Backend,ExpressionTemplates> & b)2371    inline multiprecision::number<Backend, ExpressionTemplates> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2372    {
2373       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2374       return boost::math::nextafter(a, b, c99_error_policy());
2375    }
2376    template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & a,const multiprecision::detail::expression<tag,A1,A2,A3,A4> & b)2377    inline multiprecision::number<Backend, ExpressionTemplates> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& b)
2378    {
2379       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2380       return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2381    }
2382    template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & a,const multiprecision::number<Backend,ExpressionTemplates> & b)2383    inline multiprecision::number<Backend, ExpressionTemplates> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2384    {
2385       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2386       return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2387    }
2388    template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & a,const multiprecision::detail::expression<tagb,A1b,A2b,A3b,A4b> & b)2389    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
2390    {
2391       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2392       detail::scoped_default_precision<value_type> precision_guard(a, b);
2393       return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2394    }
2395    template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & a,const multiprecision::number<Backend,ExpressionTemplates> & b)2396    inline multiprecision::number<Backend, ExpressionTemplates> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2397    {
2398       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2399       return boost::math::nextafter(a, b, c99_error_policy());
2400    }
2401    template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & a,const multiprecision::detail::expression<tag,A1,A2,A3,A4> & b)2402    inline multiprecision::number<Backend, ExpressionTemplates> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& b)
2403    {
2404       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2405       return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2406    }
2407    template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & a,const multiprecision::number<Backend,ExpressionTemplates> & b)2408    inline multiprecision::number<Backend, ExpressionTemplates> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2409    {
2410       detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2411       return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2412    }
2413    template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag,A1,A2,A3,A4> & a,const multiprecision::detail::expression<tagb,A1b,A2b,A3b,A4b> & b)2414    inline typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
2415    {
2416       typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2417       detail::scoped_default_precision<value_type> precision_guard(a, b);
2418       return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2419    }
2420 
2421 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
add(number<B1,ET1> & result,const number<B2,ET2> & a,const number<B3,ET3> & b)2422 inline number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2423 {
2424    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2425    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2426    using default_ops::eval_add;
2427    eval_add(result.backend(), a.backend(), b.backend());
2428    return result;
2429 }
2430 
2431 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
subtract(number<B1,ET1> & result,const number<B2,ET2> & a,const number<B3,ET3> & b)2432 inline number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2433 {
2434    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2435    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2436    using default_ops::eval_subtract;
2437    eval_subtract(result.backend(), a.backend(), b.backend());
2438    return result;
2439 }
2440 
2441 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
multiply(number<B1,ET1> & result,const number<B2,ET2> & a,const number<B3,ET3> & b)2442 inline number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2443 {
2444    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2445    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2446    using default_ops::eval_multiply;
2447    eval_multiply(result.backend(), a.backend(), b.backend());
2448    return result;
2449 }
2450 
2451 template <class B, expression_template_option ET, class I>
2452 inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
add(number<B,ET> & result,const I & a,const I & b)2453    add(number<B, ET>& result, const I& a, const I& b)
2454 {
2455    using default_ops::eval_add;
2456    typedef typename detail::canonical<I, B>::type canonical_type;
2457    eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2458    return result;
2459 }
2460 
2461 template <class B, expression_template_option ET, class I>
2462 inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
subtract(number<B,ET> & result,const I & a,const I & b)2463    subtract(number<B, ET>& result, const I& a, const I& b)
2464 {
2465    using default_ops::eval_subtract;
2466    typedef typename detail::canonical<I, B>::type canonical_type;
2467    eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2468    return result;
2469 }
2470 
2471 template <class B, expression_template_option ET, class I>
2472 inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
multiply(number<B,ET> & result,const I & a,const I & b)2473    multiply(number<B, ET>& result, const I& a, const I& b)
2474 {
2475    using default_ops::eval_multiply;
2476    typedef typename detail::canonical<I, B>::type canonical_type;
2477    eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2478    return result;
2479 }
2480 
2481 template <class tag, class A1, class A2, class A3, class A4, class Policy>
trunc(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2482 inline typename detail::expression<tag, A1, A2, A3, A4>::result_type trunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2483 {
2484    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2485    return BOOST_MP_MOVE(trunc(number_type(v), pol));
2486 }
2487 
2488 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
trunc(const number<Backend,ExpressionTemplates> & v,const Policy &)2489 inline number<Backend, ExpressionTemplates> trunc(const number<Backend, ExpressionTemplates>& v, const Policy&)
2490 {
2491    using default_ops::eval_trunc;
2492    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(v);
2493    number<Backend, ExpressionTemplates> result;
2494    eval_trunc(result.backend(), v.backend());
2495    return BOOST_MP_MOVE(result);
2496 }
2497 
2498 template <class tag, class A1, class A2, class A3, class A4, class Policy>
itrunc(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2499 inline int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2500 {
2501    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2502    number_type r(trunc(v, pol));
2503    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2504       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, number_type(v), 0, pol);
2505    return r.template convert_to<int>();
2506 }
2507 template <class tag, class A1, class A2, class A3, class A4>
itrunc(const detail::expression<tag,A1,A2,A3,A4> & v)2508 inline int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2509 {
2510    return itrunc(v, boost::math::policies::policy<>());
2511 }
2512 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
itrunc(const number<Backend,ExpressionTemplates> & v,const Policy & pol)2513 inline int itrunc(const number<Backend, ExpressionTemplates>& v, const Policy& pol)
2514 {
2515    number<Backend, ExpressionTemplates> r(trunc(v, pol));
2516    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2517       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, v, 0, pol);
2518    return r.template convert_to<int>();
2519 }
2520 template <class Backend, expression_template_option ExpressionTemplates>
itrunc(const number<Backend,ExpressionTemplates> & v)2521 inline int itrunc(const number<Backend, ExpressionTemplates>& v)
2522 {
2523    return itrunc(v, boost::math::policies::policy<>());
2524 }
2525 template <class tag, class A1, class A2, class A3, class A4, class Policy>
ltrunc(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2526 inline long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2527 {
2528    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2529    number_type r(trunc(v, pol));
2530    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2531       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, number_type(v), 0L, pol);
2532    return r.template convert_to<long>();
2533 }
2534 template <class tag, class A1, class A2, class A3, class A4>
ltrunc(const detail::expression<tag,A1,A2,A3,A4> & v)2535 inline long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2536 {
2537    return ltrunc(v, boost::math::policies::policy<>());
2538 }
2539 template <class T, expression_template_option ExpressionTemplates, class Policy>
ltrunc(const number<T,ExpressionTemplates> & v,const Policy & pol)2540 inline long ltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2541 {
2542    number<T, ExpressionTemplates> r(trunc(v, pol));
2543    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2544       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, v, 0L, pol);
2545    return r.template convert_to<long>();
2546 }
2547 template <class T, expression_template_option ExpressionTemplates>
ltrunc(const number<T,ExpressionTemplates> & v)2548 inline long ltrunc(const number<T, ExpressionTemplates>& v)
2549 {
2550    return ltrunc(v, boost::math::policies::policy<>());
2551 }
2552 #ifndef BOOST_NO_LONG_LONG
2553 template <class tag, class A1, class A2, class A3, class A4, class Policy>
lltrunc(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2554 inline boost::long_long_type lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2555 {
2556    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2557    number_type r(trunc(v, pol));
2558    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2559       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, number_type(v), 0LL, pol);
2560    return r.template convert_to<boost::long_long_type>();
2561 }
2562 template <class tag, class A1, class A2, class A3, class A4>
lltrunc(const detail::expression<tag,A1,A2,A3,A4> & v)2563 inline boost::long_long_type lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2564 {
2565    return lltrunc(v, boost::math::policies::policy<>());
2566 }
2567 template <class T, expression_template_option ExpressionTemplates, class Policy>
lltrunc(const number<T,ExpressionTemplates> & v,const Policy & pol)2568 inline boost::long_long_type lltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2569 {
2570    number<T, ExpressionTemplates> r(trunc(v, pol));
2571    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2572       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, v, 0LL, pol);
2573    return r.template convert_to<boost::long_long_type>();
2574 }
2575 template <class T, expression_template_option ExpressionTemplates>
lltrunc(const number<T,ExpressionTemplates> & v)2576 inline boost::long_long_type lltrunc(const number<T, ExpressionTemplates>& v)
2577 {
2578    return lltrunc(v, boost::math::policies::policy<>());
2579 }
2580 #endif
2581 template <class tag, class A1, class A2, class A3, class A4, class Policy>
round(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2582 inline typename detail::expression<tag, A1, A2, A3, A4>::result_type round(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2583 {
2584    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2585    return BOOST_MP_MOVE(round(static_cast<number_type>(v), pol));
2586 }
2587 template <class T, expression_template_option ExpressionTemplates, class Policy>
round(const number<T,ExpressionTemplates> & v,const Policy &)2588 inline number<T, ExpressionTemplates> round(const number<T, ExpressionTemplates>& v, const Policy&)
2589 {
2590    using default_ops::eval_round;
2591    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2592    number<T, ExpressionTemplates> result;
2593    eval_round(result.backend(), v.backend());
2594    return BOOST_MP_MOVE(result);
2595 }
2596 
2597 template <class tag, class A1, class A2, class A3, class A4, class Policy>
iround(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2598 inline int iround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2599 {
2600    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2601    number_type r(round(v, pol));
2602    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2603       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0, pol);
2604    return r.template convert_to<int>();
2605 }
2606 template <class tag, class A1, class A2, class A3, class A4>
iround(const detail::expression<tag,A1,A2,A3,A4> & v)2607 inline int iround(const detail::expression<tag, A1, A2, A3, A4>& v)
2608 {
2609    return iround(v, boost::math::policies::policy<>());
2610 }
2611 template <class T, expression_template_option ExpressionTemplates, class Policy>
iround(const number<T,ExpressionTemplates> & v,const Policy & pol)2612 inline int iround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2613 {
2614    number<T, ExpressionTemplates> r(round(v, pol));
2615    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2616       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0, pol);
2617    return r.template convert_to<int>();
2618 }
2619 template <class T, expression_template_option ExpressionTemplates>
iround(const number<T,ExpressionTemplates> & v)2620 inline int iround(const number<T, ExpressionTemplates>& v)
2621 {
2622    return iround(v, boost::math::policies::policy<>());
2623 }
2624 template <class tag, class A1, class A2, class A3, class A4, class Policy>
lround(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2625 inline long lround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2626 {
2627    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2628    number_type r(round(v, pol));
2629    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2630       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, number_type(v), 0L, pol);
2631    return r.template convert_to<long>();
2632 }
2633 template <class tag, class A1, class A2, class A3, class A4>
lround(const detail::expression<tag,A1,A2,A3,A4> & v)2634 inline long lround(const detail::expression<tag, A1, A2, A3, A4>& v)
2635 {
2636    return lround(v, boost::math::policies::policy<>());
2637 }
2638 template <class T, expression_template_option ExpressionTemplates, class Policy>
lround(const number<T,ExpressionTemplates> & v,const Policy & pol)2639 inline long lround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2640 {
2641    number<T, ExpressionTemplates> r(round(v, pol));
2642    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2643       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, v, 0L, pol);
2644    return r.template convert_to<long>();
2645 }
2646 template <class T, expression_template_option ExpressionTemplates>
lround(const number<T,ExpressionTemplates> & v)2647 inline long lround(const number<T, ExpressionTemplates>& v)
2648 {
2649    return lround(v, boost::math::policies::policy<>());
2650 }
2651 #ifndef BOOST_NO_LONG_LONG
2652 template <class tag, class A1, class A2, class A3, class A4, class Policy>
llround(const detail::expression<tag,A1,A2,A3,A4> & v,const Policy & pol)2653 inline boost::long_long_type llround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2654 {
2655    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2656    number_type r(round(v, pol));
2657    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2658       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0LL, pol);
2659    return r.template convert_to<boost::long_long_type>();
2660 }
2661 template <class tag, class A1, class A2, class A3, class A4>
llround(const detail::expression<tag,A1,A2,A3,A4> & v)2662 inline boost::long_long_type llround(const detail::expression<tag, A1, A2, A3, A4>& v)
2663 {
2664    return llround(v, boost::math::policies::policy<>());
2665 }
2666 template <class T, expression_template_option ExpressionTemplates, class Policy>
llround(const number<T,ExpressionTemplates> & v,const Policy & pol)2667 inline boost::long_long_type llround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2668 {
2669    number<T, ExpressionTemplates> r(round(v, pol));
2670    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2671       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0LL, pol);
2672    return r.template convert_to<boost::long_long_type>();
2673 }
2674 template <class T, expression_template_option ExpressionTemplates>
llround(const number<T,ExpressionTemplates> & v)2675 inline boost::long_long_type llround(const number<T, ExpressionTemplates>& v)
2676 {
2677    return llround(v, boost::math::policies::policy<>());
2678 }
2679 #endif
2680 //
2681 // frexp does not return an expression template since we require the
2682 // integer argument to be evaluated even if the returned value is
2683 // not assigned to anything...
2684 //
2685 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,short * pint)2686 inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, short* pint)
2687 {
2688    using default_ops::eval_frexp;
2689    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2690    number<T, ExpressionTemplates> result;
2691    eval_frexp(result.backend(), v.backend(), pint);
2692    return BOOST_MP_MOVE(result);
2693 }
2694 template <class tag, class A1, class A2, class A3, class A4>
2695 inline typename enable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
frexp(const detail::expression<tag,A1,A2,A3,A4> & v,short * pint)2696    frexp(const detail::expression<tag, A1, A2, A3, A4>& v, short* pint)
2697 {
2698    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2699    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2700 }
2701 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,int * pint)2702 inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, int* pint)
2703 {
2704    using default_ops::eval_frexp;
2705    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2706    number<T, ExpressionTemplates> result;
2707    eval_frexp(result.backend(), v.backend(), pint);
2708    return BOOST_MP_MOVE(result);
2709 }
2710 template <class tag, class A1, class A2, class A3, class A4>
2711 inline typename enable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
frexp(const detail::expression<tag,A1,A2,A3,A4> & v,int * pint)2712 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, int* pint)
2713 {
2714    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2715    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2716 }
2717 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,long * pint)2718 inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, long* pint)
2719 {
2720    using default_ops::eval_frexp;
2721    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2722    number<T, ExpressionTemplates> result;
2723    eval_frexp(result.backend(), v.backend(), pint);
2724    return BOOST_MP_MOVE(result);
2725 }
2726 template <class tag, class A1, class A2, class A3, class A4>
2727 inline typename enable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
frexp(const detail::expression<tag,A1,A2,A3,A4> & v,long * pint)2728 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long* pint)
2729 {
2730    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2731    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2732 }
2733 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,boost::long_long_type * pint)2734 inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, boost::long_long_type* pint)
2735 {
2736    using default_ops::eval_frexp;
2737    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2738    number<T, ExpressionTemplates> result;
2739    eval_frexp(result.backend(), v.backend(), pint);
2740    return BOOST_MP_MOVE(result);
2741 }
2742 template <class tag, class A1, class A2, class A3, class A4>
2743 inline typename enable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
frexp(const detail::expression<tag,A1,A2,A3,A4> & v,boost::long_long_type * pint)2744 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, boost::long_long_type* pint)
2745 {
2746    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2747    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2748 }
2749 //
2750 // modf does not return an expression template since we require the
2751 // second argument to be evaluated even if the returned value is
2752 // not assigned to anything...
2753 //
2754 template <class T, expression_template_option ExpressionTemplates>
modf(const number<T,ExpressionTemplates> & v,number<T,ExpressionTemplates> * pipart)2755 inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type modf(const number<T, ExpressionTemplates>& v, number<T, ExpressionTemplates>* pipart)
2756 {
2757    using default_ops::eval_modf;
2758    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2759    number<T, ExpressionTemplates> result;
2760    eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : 0);
2761    return BOOST_MP_MOVE(result);
2762 }
2763 template <class T, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
modf(const detail::expression<tag,A1,A2,A3,A4> & v,number<T,ExpressionTemplates> * pipart)2764 inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type modf(const detail::expression<tag, A1, A2, A3, A4>& v, number<T, ExpressionTemplates>* pipart)
2765 {
2766    using default_ops::eval_modf;
2767    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2768    number<T, ExpressionTemplates> result, arg(v);
2769    eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : 0);
2770    return BOOST_MP_MOVE(result);
2771 }
2772 
2773 //
2774 // Integer square root:
2775 //
2776 template <class B, expression_template_option ExpressionTemplates>
2777 inline typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
sqrt(const number<B,ExpressionTemplates> & x)2778    sqrt(const number<B, ExpressionTemplates>& x)
2779 {
2780    using default_ops::eval_integer_sqrt;
2781    number<B, ExpressionTemplates> s, r;
2782    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
2783    return s;
2784 }
2785 //
2786 // fma:
2787 //
2788 
2789 namespace default_ops {
2790 
2791    struct fma_func
2792    {
2793       template <class B, class T, class U, class V>
operator ()boost::multiprecision::default_ops::fma_func2794       void operator()(B& result, const T& a, const U& b, const V& c)const
2795       {
2796          eval_multiply_add(result, a, b, c);
2797       }
2798    };
2799 
2800 
2801 }
2802 
2803 template <class Backend, class U, class V>
2804 inline typename enable_if<
2805    mpl::and_<
2806       mpl::bool_<number_category<number<Backend, et_on> >::value == number_kind_floating_point>,
2807       mpl::or_<
2808          is_number<U>,
2809          is_number_expression<U>,
2810          is_arithmetic<U>
2811       >,
2812       mpl::or_<
2813          is_number<V>,
2814          is_number_expression<V>,
2815          is_arithmetic<V>
2816       >
2817    >,
2818    detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V>
2819 >::type
fma(const number<Backend,et_on> & a,const U & b,const V & c)2820 fma(const number<Backend, et_on>& a, const U& b, const V& c)
2821 {
2822    return detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V>(
2823       default_ops::fma_func(), a, b, c);
2824 }
2825 
2826 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U, class V>
2827 inline typename enable_if<
2828    mpl::and_<
2829    mpl::bool_<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type >::value == number_kind_floating_point>,
2830    mpl::or_<
2831    is_number<U>,
2832    is_number_expression<U>,
2833    is_arithmetic<U>
2834    >,
2835    mpl::or_<
2836    is_number<V>,
2837    is_number_expression<V>,
2838    is_arithmetic<V>
2839    >
2840    >,
2841    detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V>
2842 >::type
fma(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & a,const U & b,const V & c)2843 fma(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, const V& c)
2844 {
2845    return detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V>(
2846       default_ops::fma_func(), a, b, c);
2847 }
2848 
2849 template <class Backend, class U, class V>
2850 inline typename enable_if<
2851    mpl::and_<
2852    mpl::bool_<number_category<number<Backend, et_off> >::value == number_kind_floating_point>,
2853    mpl::or_<
2854    is_number<U>,
2855    is_number_expression<U>,
2856    is_arithmetic<U>
2857    >,
2858    mpl::or_<
2859    is_number<V>,
2860    is_number_expression<V>,
2861    is_arithmetic<V>
2862    >
2863    >,
2864    number<Backend, et_off>
2865 >::type
fma(const number<Backend,et_off> & a,const U & b,const V & c)2866 fma(const number<Backend, et_off>& a, const U& b, const V& c)
2867 {
2868    using default_ops::eval_multiply_add;
2869    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
2870    number<Backend, et_off> result;
2871    eval_multiply_add(result.backend(), number<Backend, et_off>::canonical_value(a), number<Backend, et_off>::canonical_value(b), number<Backend, et_off>::canonical_value(c));
2872    return BOOST_MP_MOVE(result);
2873 }
2874 
2875 template <class U, class Backend, class V>
2876 inline typename enable_if<
2877    mpl::and_<
2878       mpl::bool_<number_category<number<Backend, et_on> >::value == number_kind_floating_point>,
2879       is_arithmetic<U>,
2880       mpl::or_<
2881          is_number<V>,
2882          is_number_expression<V>,
2883          is_arithmetic<V>
2884       >
2885    >,
2886    detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V>
2887 >::type
fma(const U & a,const number<Backend,et_on> & b,const V & c)2888 fma(const U& a, const number<Backend, et_on>& b, const V& c)
2889 {
2890    return detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V>(
2891       default_ops::fma_func(), a, b, c);
2892 }
2893 
2894 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
2895 inline typename enable_if<
2896    mpl::and_<
2897       mpl::bool_<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type >::value == number_kind_floating_point>,
2898       is_arithmetic<U>,
2899       mpl::or_<
2900          is_number<V>,
2901          is_number_expression<V>,
2902          is_arithmetic<V>
2903       >
2904    >,
2905    detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V>
2906 >::type
fma(const U & a,const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & b,const V & c)2907 fma(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, const V& c)
2908 {
2909    return detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V>(
2910       default_ops::fma_func(), a, b, c);
2911 }
2912 
2913 template <class U, class Backend, class V>
2914 inline typename enable_if<
2915    mpl::and_<
2916       mpl::bool_<number_category<number<Backend, et_off> >::value == number_kind_floating_point>,
2917       is_arithmetic<U>,
2918       mpl::or_<
2919          is_number<V>,
2920          is_number_expression<V>,
2921          is_arithmetic<V>
2922       >
2923    >,
2924    number<Backend, et_off>
2925 >::type
fma(const U & a,const number<Backend,et_off> & b,const V & c)2926 fma(const U& a, const number<Backend, et_off>& b, const V& c)
2927 {
2928    using default_ops::eval_multiply_add;
2929    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
2930    number<Backend, et_off> result;
2931    eval_multiply_add(result.backend(), number<Backend, et_off>::canonical_value(a), number<Backend, et_off>::canonical_value(b), number<Backend, et_off>::canonical_value(c));
2932    return BOOST_MP_MOVE(result);
2933 }
2934 
2935 template <class U, class V, class Backend>
2936 inline typename enable_if<
2937    mpl::and_<
2938    mpl::bool_<number_category<number<Backend, et_on> >::value == number_kind_floating_point>,
2939       is_arithmetic<U>,
2940       is_arithmetic<V>
2941    >,
2942    detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> >
2943 >::type
fma(const U & a,const V & b,const number<Backend,et_on> & c)2944 fma(const U& a, const V& b, const number<Backend, et_on>& c)
2945 {
2946    return detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> >(
2947       default_ops::fma_func(), a, b, c);
2948 }
2949 
2950 template <class U, class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
2951 inline typename enable_if<
2952    mpl::and_<
2953    mpl::bool_<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type >::value == number_kind_floating_point>,
2954       is_arithmetic<U>,
2955       is_arithmetic<V>
2956    >,
2957    detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
2958 >::type
fma(const U & a,const V & b,const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & c)2959 fma(const U& a, const V& b, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& c)
2960 {
2961    return detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(
2962       default_ops::fma_func(), a, b, c);
2963 }
2964 
2965 template <class U, class V, class Backend>
2966 inline typename enable_if<
2967    mpl::and_<
2968    mpl::bool_<number_category<number<Backend, et_off> >::value == number_kind_floating_point>,
2969       is_arithmetic<U>,
2970       is_arithmetic<V>
2971    >,
2972    number<Backend, et_off>
2973 >::type
fma(const U & a,const V & b,const number<Backend,et_off> & c)2974 fma(const U& a, const V& b, const number<Backend, et_off>& c)
2975 {
2976    using default_ops::eval_multiply_add;
2977    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
2978    number<Backend, et_off> result;
2979    eval_multiply_add(result.backend(), number<Backend, et_off>::canonical_value(a), number<Backend, et_off>::canonical_value(b), number<Backend, et_off>::canonical_value(c));
2980    return BOOST_MP_MOVE(result);
2981 }
2982 
2983 namespace default_ops {
2984 
2985    struct remquo_func
2986    {
2987       template <class B, class T, class U>
operator ()boost::multiprecision::default_ops::remquo_func2988       void operator()(B& result, const T& a, const U& b, int* pi)const
2989       {
2990          eval_remquo(result, a, b, pi);
2991       }
2992    };
2993 
2994 }
2995 
2996 template <class Backend, class U>
2997 inline typename enable_if_c<
2998    number_category<number<Backend, et_on> >::value == number_kind_floating_point,
2999    detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*>
3000 >::type
remquo(const number<Backend,et_on> & a,const U & b,int * pi)3001 remquo(const number<Backend, et_on>& a, const U& b, int* pi)
3002 {
3003    return detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*>(
3004       default_ops::remquo_func(), a, b, pi);
3005 }
3006 
3007 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U>
3008 inline typename enable_if_c<
3009    number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type >::value == number_kind_floating_point,
3010    detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*>
3011 >::type
remquo(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & a,const U & b,int * pi)3012 remquo(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, int* pi)
3013 {
3014    return detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*>(
3015       default_ops::remquo_func(), a, b, pi);
3016 }
3017 
3018 template <class U, class Backend>
3019 inline typename enable_if_c<
3020    (number_category<number<Backend, et_on> >::value == number_kind_floating_point)
3021    && !is_number<U>::value && !is_number_expression<U>::value,
3022    detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*>
3023 >::type
remquo(const U & a,const number<Backend,et_on> & b,int * pi)3024 remquo(const U& a, const number<Backend, et_on>& b, int* pi)
3025 {
3026    return detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*>(
3027       default_ops::remquo_func(), a, b, pi);
3028 }
3029 
3030 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3031 inline typename enable_if_c<
3032    (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type >::value == number_kind_floating_point)
3033    && !is_number<U>::value && !is_number_expression<U>::value,
3034    detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*>
3035 >::type
remquo(const U & a,const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & b,int * pi)3036 remquo(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, int* pi)
3037 {
3038    return detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*>(
3039       default_ops::remquo_func(), a, b, pi);
3040 }
3041 
3042 template <class Backend, class U>
3043 inline typename enable_if_c<
3044    number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3045    number<Backend, et_off>
3046 >::type
remquo(const number<Backend,et_off> & a,const U & b,int * pi)3047 remquo(const number<Backend, et_off>& a, const U& b, int* pi)
3048 {
3049    using default_ops::eval_remquo;
3050    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3051    number<Backend, et_off> result;
3052    eval_remquo(result.backend(), a.backend(), number<Backend, et_off>::canonical_value(b), pi);
3053    return BOOST_MP_MOVE(result);
3054 }
3055 template <class U, class Backend>
3056 inline typename enable_if_c<
3057 (number_category<number<Backend, et_on> >::value == number_kind_floating_point)
3058 && !is_number<U>::value && !is_number_expression<U>::value,
3059 number<Backend, et_off>
3060 >::type
remquo(const U & a,const number<Backend,et_off> & b,int * pi)3061 remquo(const U& a, const number<Backend, et_off>& b, int* pi)
3062 {
3063    using default_ops::eval_remquo;
3064    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3065    number<Backend, et_off> result;
3066    eval_remquo(result.backend(), number<Backend, et_off>::canonical_value(a), b.backend(), pi);
3067    return BOOST_MP_MOVE(result);
3068 }
3069 
3070 
3071 template <class B, expression_template_option ExpressionTemplates>
3072 inline typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
sqrt(const number<B,ExpressionTemplates> & x,number<B,ExpressionTemplates> & r)3073    sqrt(const number<B, ExpressionTemplates>& x, number<B, ExpressionTemplates>& r)
3074 {
3075    using default_ops::eval_integer_sqrt;
3076    detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(x, r);
3077    number<B, ExpressionTemplates> s;
3078    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3079    return s;
3080 }
3081 
3082 #define UNARY_OP_FUNCTOR(func, category)\
3083 namespace detail{\
3084 template <class Backend> \
3085 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))\
3086 {\
3087    void operator()(Backend& result, const Backend& arg)const\
3088    {\
3089       using default_ops::BOOST_JOIN(eval_,func);\
3090       BOOST_JOIN(eval_,func)(result, arg);\
3091    }\
3092    template <class U>\
3093    void operator()(U& result, const Backend& arg)const\
3094    {\
3095       using default_ops::BOOST_JOIN(eval_,func);\
3096       Backend temp;\
3097       BOOST_JOIN(eval_,func)(temp, arg);\
3098       result = temp;\
3099    }\
3100 };\
3101 \
3102 }\
3103 \
3104 template <class tag, class A1, class A2, class A3, class A4> \
3105 inline typename enable_if_c<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category,\
3106    detail::expression<\
3107     detail::function\
3108   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3109   , detail::expression<tag, A1, A2, A3, A4> > \
3110 >::type \
3111 func(const detail::expression<tag, A1, A2, A3, A4>& arg)\
3112 {\
3113     return detail::expression<\
3114     detail::function\
3115   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3116   , detail::expression<tag, A1, A2, A3, A4> \
3117 > (\
3118         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
3119       , arg   \
3120     );\
3121 }\
3122 template <class Backend> \
3123 inline typename enable_if_c<number_category<Backend>::value == category,\
3124    detail::expression<\
3125     detail::function\
3126   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3127   , number<Backend, et_on> > \
3128 >::type \
3129 func(const number<Backend, et_on>& arg)\
3130 {\
3131     return detail::expression<\
3132     detail::function\
3133   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3134   , number<Backend, et_on> \
3135   >(\
3136         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>() \
3137       , arg   \
3138     );\
3139 }\
3140 template <class Backend> \
3141 inline typename boost::enable_if_c<\
3142    boost::multiprecision::number_category<Backend>::value == category,\
3143    number<Backend, et_off> >::type \
3144 func(const number<Backend, et_off>& arg)\
3145 {\
3146    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);\
3147    number<Backend, et_off> result;\
3148    using default_ops::BOOST_JOIN(eval_,func);\
3149    BOOST_JOIN(eval_,func)(result.backend(), arg.backend());\
3150    return BOOST_MP_MOVE(result);\
3151 }
3152 
3153 #define BINARY_OP_FUNCTOR(func, category)\
3154 namespace detail{\
3155 template <class Backend> \
3156 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))\
3157 {\
3158    void operator()(Backend& result, const Backend& arg, const Backend& a)const\
3159    {\
3160       using default_ops:: BOOST_JOIN(eval_,func);\
3161       BOOST_JOIN(eval_,func)(result, arg, a);\
3162    }\
3163    template <class Arithmetic> \
3164    void operator()(Backend& result, const Backend& arg, const Arithmetic& a)const\
3165    {\
3166       using default_ops:: BOOST_JOIN(eval_,func);\
3167       BOOST_JOIN(eval_,func)(result, arg, number<Backend>::canonical_value(a));\
3168    }\
3169    template <class Arithmetic> \
3170    void operator()(Backend& result, const Arithmetic& arg, const Backend& a)const\
3171    {\
3172       using default_ops:: BOOST_JOIN(eval_,func);\
3173       BOOST_JOIN(eval_,func)(result, number<Backend>::canonical_value(arg), a);\
3174    }\
3175    template <class U>\
3176    void operator()(U& result, const Backend& arg, const Backend& a)const\
3177    {\
3178       using default_ops:: BOOST_JOIN(eval_,func);\
3179       Backend r;\
3180       BOOST_JOIN(eval_,func)(r, arg, a);\
3181       result = r;\
3182    }\
3183    template <class U, class Arithmetic> \
3184    void operator()(U& result, const Backend& arg, const Arithmetic& a)const\
3185    {\
3186       using default_ops:: BOOST_JOIN(eval_,func);\
3187       Backend r;\
3188       BOOST_JOIN(eval_,func)(r, arg, number<Backend>::canonical_value(a));\
3189       result = r;\
3190    }\
3191    template <class U, class Arithmetic> \
3192    void operator()(U& result, const Arithmetic& arg, const Backend& a)const\
3193    {\
3194       using default_ops:: BOOST_JOIN(eval_,func);\
3195       Backend r;\
3196       BOOST_JOIN(eval_,func)(r, number<Backend>::canonical_value(arg), a);\
3197       result = r;\
3198    }\
3199 };\
3200 \
3201 }\
3202 template <class Backend> \
3203 inline typename enable_if_c<number_category<Backend>::value == category,\
3204    detail::expression<\
3205     detail::function\
3206   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3207   , number<Backend, et_on> \
3208   , number<Backend, et_on> > \
3209 >::type \
3210 func(const number<Backend, et_on>& arg, const number<Backend, et_on>& a)\
3211 {\
3212     return detail::expression<\
3213     detail::function\
3214   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3215   , number<Backend, et_on> \
3216   , number<Backend, et_on> \
3217   >(\
3218         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>() \
3219       , arg,\
3220       a\
3221     );\
3222 }\
3223 template <class Backend, class tag, class A1, class A2, class A3, class A4> \
3224 inline typename enable_if_c<\
3225    (number_category<Backend>::value == category) && (boost::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),\
3226    detail::expression<\
3227     detail::function\
3228   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3229   , number<Backend, et_on> \
3230   , detail::expression<tag, A1, A2, A3, A4> > \
3231 >::type \
3232 func(const number<Backend, et_on>& arg, const detail::expression<tag, A1, A2, A3, A4>& a)\
3233 {\
3234     return detail::expression<\
3235     detail::function\
3236   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3237   , number<Backend, et_on> \
3238   , detail::expression<tag, A1, A2, A3, A4> \
3239   >(\
3240         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>() \
3241       , arg,\
3242       a\
3243     );\
3244 }\
3245 template <class tag, class A1, class A2, class A3, class A4, class Backend> \
3246 inline typename enable_if_c<\
3247    (number_category<Backend>::value == category) && (boost::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),\
3248    detail::expression<\
3249     detail::function\
3250   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3251   , detail::expression<tag, A1, A2, A3, A4> \
3252   , number<Backend, et_on> > \
3253 >::type \
3254 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const number<Backend, et_on>& a)\
3255 {\
3256     return detail::expression<\
3257     detail::function\
3258   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3259   , detail::expression<tag, A1, A2, A3, A4> \
3260   , number<Backend, et_on> \
3261   >(\
3262         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>() \
3263       , arg,\
3264       a\
3265     );\
3266 }\
3267 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b> \
3268 inline typename enable_if_c<\
3269       (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category) && (number_category<detail::expression<tagb, A1b, A2b, A3b, A4b> >::value == category),\
3270    detail::expression<\
3271     detail::function\
3272   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3273   , detail::expression<tag, A1, A2, A3, A4> \
3274   , detail::expression<tagb, A1b, A2b, A3b, A4b> > \
3275 >::type \
3276 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const detail::expression<tagb, A1b, A2b, A3b, A4b>& a)\
3277 {\
3278     return detail::expression<\
3279     detail::function\
3280   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3281   , detail::expression<tag, A1, A2, A3, A4> \
3282   , detail::expression<tagb, A1b, A2b, A3b, A4b> \
3283   >(\
3284         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
3285       , arg,\
3286       a\
3287     );\
3288 }\
3289 template <class Backend, class Arithmetic> \
3290 inline typename enable_if_c<\
3291    is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),\
3292    detail::expression<\
3293     detail::function\
3294   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3295   , number<Backend, et_on> \
3296   , Arithmetic\
3297   > \
3298 >::type \
3299 func(const number<Backend, et_on>& arg, const Arithmetic& a)\
3300 {\
3301     return detail::expression<\
3302     detail::function\
3303   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3304   , number<Backend, et_on> \
3305   , Arithmetic\
3306   >(\
3307         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>() \
3308       , arg,\
3309       a\
3310     );\
3311 }\
3312 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
3313 inline typename enable_if_c<\
3314    is_compatible_arithmetic_type<Arithmetic, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
3315    detail::expression<\
3316     detail::function\
3317   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3318   , detail::expression<tag, A1, A2, A3, A4> \
3319   , Arithmetic\
3320   > \
3321 >::type \
3322 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const Arithmetic& a)\
3323 {\
3324     return detail::expression<\
3325     detail::function\
3326   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3327   , detail::expression<tag, A1, A2, A3, A4> \
3328   , Arithmetic\
3329    >(\
3330         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
3331       , arg,\
3332       a\
3333     );\
3334 }\
3335 template <class Backend, class Arithmetic> \
3336 inline typename enable_if_c<\
3337    is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),\
3338    detail::expression<\
3339     detail::function\
3340   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3341   , Arithmetic \
3342   , number<Backend, et_on> \
3343   > \
3344 >::type \
3345 func(const Arithmetic& arg, const number<Backend, et_on>& a)\
3346 {\
3347     return detail::expression<\
3348     detail::function\
3349   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3350   , Arithmetic \
3351   , number<Backend, et_on> \
3352   >(\
3353         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>() \
3354       , arg,\
3355       a\
3356     );\
3357 }\
3358 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
3359 inline typename enable_if_c<\
3360    is_compatible_arithmetic_type<Arithmetic, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
3361    detail::expression<\
3362     detail::function\
3363   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3364   , Arithmetic \
3365   , detail::expression<tag, A1, A2, A3, A4> \
3366   > \
3367 >::type \
3368 func(const Arithmetic& arg, const detail::expression<tag, A1, A2, A3, A4>& a)\
3369 {\
3370     return detail::expression<\
3371     detail::function\
3372   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3373   , Arithmetic \
3374   , detail::expression<tag, A1, A2, A3, A4> \
3375    >(\
3376         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
3377       , arg,\
3378       a\
3379     );\
3380 }\
3381 template <class Backend> \
3382 inline typename enable_if_c<(number_category<Backend>::value == category),\
3383    number<Backend, et_off> >::type \
3384 func(const number<Backend, et_off>& arg, const number<Backend, et_off>& a)\
3385 {\
3386    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);\
3387    number<Backend, et_off> result;\
3388    using default_ops:: BOOST_JOIN(eval_,func);\
3389    BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a.backend());\
3390    return BOOST_MP_MOVE(result);\
3391 }\
3392 template <class Backend, class Arithmetic> \
3393 inline typename enable_if_c<\
3394    is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),\
3395    number<Backend, et_off> \
3396 >::type \
3397 func(const number<Backend, et_off>& arg, const Arithmetic& a)\
3398 {\
3399    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);\
3400    number<Backend, et_off> result;\
3401    using default_ops:: BOOST_JOIN(eval_,func);\
3402    BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), number<Backend, et_off>::canonical_value(a));\
3403    return BOOST_MP_MOVE(result);\
3404 }\
3405 template <class Backend, class Arithmetic> \
3406 inline typename enable_if_c<\
3407    is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),\
3408    number<Backend, et_off> \
3409 >::type \
3410 func(const Arithmetic& a, const number<Backend, et_off>& arg)\
3411 {\
3412    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);\
3413    number<Backend, et_off> result;\
3414    using default_ops:: BOOST_JOIN(eval_,func);\
3415    BOOST_JOIN(eval_,func)(result.backend(), number<Backend, et_off>::canonical_value(a), arg.backend());\
3416    return BOOST_MP_MOVE(result);\
3417 }\
3418 
3419 
3420 #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)\
3421 template <class tag, class A1, class A2, class A3, class A4> \
3422 inline typename enable_if_c<\
3423    (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
3424    detail::expression<\
3425     detail::function\
3426   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3427   , detail::expression<tag, A1, A2, A3, A4> \
3428   , Arg2> \
3429 >::type \
3430 func(const detail::expression<tag, A1, A2, A3, A4>& arg, Arg2 const& a)\
3431 {\
3432     return detail::expression<\
3433     detail::function\
3434   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
3435   , detail::expression<tag, A1, A2, A3, A4> \
3436   , Arg2\
3437    >(\
3438         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
3439       , arg, a   \
3440     );\
3441 }\
3442 template <class Backend> \
3443 inline typename enable_if_c<\
3444    (number_category<Backend>::value == category),\
3445   detail::expression<\
3446     detail::function\
3447   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3448   , number<Backend, et_on> \
3449   , Arg2> \
3450 >::type \
3451 func(const number<Backend, et_on>& arg, Arg2 const& a)\
3452 {\
3453     return detail::expression<\
3454     detail::function\
3455   , detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend> \
3456   , number<Backend, et_on> \
3457   , Arg2\
3458   >(\
3459         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>() \
3460       , arg,\
3461       a\
3462     );\
3463 }\
3464 template <class Backend> \
3465 inline typename enable_if_c<\
3466   (number_category<Backend>::value == category),\
3467   number<Backend, et_off> >::type \
3468 func(const number<Backend, et_off>& arg, Arg2 const& a)\
3469 {\
3470    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);\
3471    number<Backend, et_off> result;\
3472    using default_ops:: BOOST_JOIN(eval_,func);\
3473    BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a);\
3474    return BOOST_MP_MOVE(result);\
3475 }\
3476 
3477 #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)\
3478 namespace detail{\
3479 template <class Backend> \
3480 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))\
3481 {\
3482    template <class Arg>\
3483    void operator()(Backend& result, Backend const& arg, Arg a)const\
3484    {\
3485       using default_ops:: BOOST_JOIN(eval_,func);\
3486       BOOST_JOIN(eval_,func)(result, arg, a);\
3487    }\
3488 };\
3489 \
3490 }\
3491 \
3492 HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)
3493 
3494 namespace detail{
3495 template <class Backend>
3496 struct abs_funct
3497 {
operator ()boost::multiprecision::detail::abs_funct3498    void operator()(Backend& result, const Backend& arg)const
3499    {
3500       using default_ops::eval_abs;
3501       eval_abs(result, arg);
3502    }
3503 };
3504 template <class Backend>
3505 struct conj_funct
3506 {
operator ()boost::multiprecision::detail::conj_funct3507    void operator()(Backend& result, const Backend& arg)const
3508    {
3509       using default_ops::eval_conj;
3510       eval_conj(result, arg);
3511    }
3512 };
3513 template <class Backend>
3514 struct proj_funct
3515 {
operator ()boost::multiprecision::detail::proj_funct3516    void operator()(Backend& result, const Backend& arg)const
3517    {
3518       using default_ops::eval_proj;
3519       eval_proj(result, arg);
3520    }
3521 };
3522 
3523 }
3524 
3525 template <class tag, class A1, class A2, class A3, class A4>
3526 inline typename boost::disable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_complex,
3527    detail::expression<
3528     detail::function
3529   , detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
3530   , detail::expression<tag, A1, A2, A3, A4> > >::type
abs(const detail::expression<tag,A1,A2,A3,A4> & arg)3531 abs(const detail::expression<tag, A1, A2, A3, A4>& arg)
3532 {
3533     return detail::expression<
3534     detail::function
3535   , detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
3536   , detail::expression<tag, A1, A2, A3, A4>
3537 > (
3538         detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>()
3539       , arg
3540     );
3541 }
3542 template <class Backend>
3543 inline typename disable_if_c<number_category<Backend>::value == number_kind_complex,
3544    detail::expression<
3545     detail::function
3546   , detail::abs_funct<Backend>
3547   , number<Backend, et_on> > >::type
abs(const number<Backend,et_on> & arg)3548 abs(const number<Backend, et_on>& arg)
3549 {
3550     return detail::expression<
3551     detail::function
3552   , detail::abs_funct<Backend>
3553   , number<Backend, et_on>
3554   >(
3555         detail::abs_funct<Backend>()
3556       , arg
3557     );
3558 }
3559 template <class Backend>
3560 inline typename disable_if_c<number_category<Backend>::value == number_kind_complex, number<Backend, et_off> >::type
abs(const number<Backend,et_off> & arg)3561 abs(const number<Backend, et_off>& arg)
3562 {
3563    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3564    number<Backend, et_off> result;
3565    using default_ops::eval_abs;
3566    eval_abs(result.backend(), arg.backend());
3567    return BOOST_MP_MOVE(result);
3568 }
3569 
3570 template <class tag, class A1, class A2, class A3, class A4>
3571 inline detail::expression<
3572     detail::function
3573   , detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
3574   , detail::expression<tag, A1, A2, A3, A4> >
conj(const detail::expression<tag,A1,A2,A3,A4> & arg)3575 conj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3576 {
3577     return detail::expression<
3578     detail::function
3579   , detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
3580   , detail::expression<tag, A1, A2, A3, A4>
3581 > (
3582         detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>()
3583       , arg
3584     );
3585 }
3586 template <class Backend>
3587 inline detail::expression<
3588     detail::function
3589   , detail::conj_funct<Backend>
3590   , number<Backend, et_on> >
conj(const number<Backend,et_on> & arg)3591 conj(const number<Backend, et_on>& arg)
3592 {
3593     return detail::expression<
3594     detail::function
3595   , detail::conj_funct<Backend>
3596   , number<Backend, et_on>
3597   >(
3598         detail::conj_funct<Backend>()
3599       , arg
3600     );
3601 }
3602 template <class Backend>
3603 inline number<Backend, et_off>
conj(const number<Backend,et_off> & arg)3604 conj(const number<Backend, et_off>& arg)
3605 {
3606    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3607    number<Backend, et_off> result;
3608    using default_ops::eval_conj;
3609    eval_conj(result.backend(), arg.backend());
3610    return BOOST_MP_MOVE(result);
3611 }
3612 
3613 template <class tag, class A1, class A2, class A3, class A4>
3614 inline detail::expression<
3615     detail::function
3616   , detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
3617   , detail::expression<tag, A1, A2, A3, A4> >
proj(const detail::expression<tag,A1,A2,A3,A4> & arg)3618 proj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3619 {
3620     return detail::expression<
3621     detail::function
3622   , detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
3623   , detail::expression<tag, A1, A2, A3, A4>
3624 > (
3625         detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>()
3626       , arg
3627     );
3628 }
3629 template <class Backend>
3630 inline detail::expression<
3631     detail::function
3632   , detail::proj_funct<Backend>
3633   , number<Backend, et_on> >
proj(const number<Backend,et_on> & arg)3634 proj(const number<Backend, et_on>& arg)
3635 {
3636     return detail::expression<
3637     detail::function
3638   , detail::proj_funct<Backend>
3639   , number<Backend, et_on>
3640   >(
3641         detail::proj_funct<Backend>()
3642       , arg
3643     );
3644 }
3645 template <class Backend>
3646 inline number<Backend, et_off>
proj(const number<Backend,et_off> & arg)3647 proj(const number<Backend, et_off>& arg)
3648 {
3649    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3650    number<Backend, et_off> result;
3651    using default_ops::eval_proj;
3652    eval_proj(result.backend(), arg.backend());
3653    return BOOST_MP_MOVE(result);
3654 }
3655 
UNARY_OP_FUNCTOR(fabs,number_kind_floating_point)3656 UNARY_OP_FUNCTOR(fabs, number_kind_floating_point)
3657 UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point)
3658 UNARY_OP_FUNCTOR(floor, number_kind_floating_point)
3659 UNARY_OP_FUNCTOR(ceil, number_kind_floating_point)
3660 UNARY_OP_FUNCTOR(trunc, number_kind_floating_point)
3661 UNARY_OP_FUNCTOR(round, number_kind_floating_point)
3662 UNARY_OP_FUNCTOR(exp, number_kind_floating_point)
3663 UNARY_OP_FUNCTOR(exp2, number_kind_floating_point)
3664 UNARY_OP_FUNCTOR(log, number_kind_floating_point)
3665 UNARY_OP_FUNCTOR(log10, number_kind_floating_point)
3666 UNARY_OP_FUNCTOR(cos, number_kind_floating_point)
3667 UNARY_OP_FUNCTOR(sin, number_kind_floating_point)
3668 UNARY_OP_FUNCTOR(tan, number_kind_floating_point)
3669 UNARY_OP_FUNCTOR(asin, number_kind_floating_point)
3670 UNARY_OP_FUNCTOR(acos, number_kind_floating_point)
3671 UNARY_OP_FUNCTOR(atan, number_kind_floating_point)
3672 UNARY_OP_FUNCTOR(cosh, number_kind_floating_point)
3673 UNARY_OP_FUNCTOR(sinh, number_kind_floating_point)
3674 UNARY_OP_FUNCTOR(tanh, number_kind_floating_point)
3675 UNARY_OP_FUNCTOR(log2, number_kind_floating_point)
3676 UNARY_OP_FUNCTOR(nearbyint, number_kind_floating_point)
3677 UNARY_OP_FUNCTOR(rint, number_kind_floating_point)
3678 
3679 HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point)
3680 //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point)
3681 HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point)
3682 //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point)
3683 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point)
3684 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point)
3685 HETERO_BINARY_OP_FUNCTOR_B(ldexp, boost::long_long_type, number_kind_floating_point)
3686 //HETERO_BINARY_OP_FUNCTOR_B(frexp, boost::long_long_type*, number_kind_floating_point)
3687 BINARY_OP_FUNCTOR(pow, number_kind_floating_point)
3688 BINARY_OP_FUNCTOR(fmod, number_kind_floating_point)
3689 BINARY_OP_FUNCTOR(fmax, number_kind_floating_point)
3690 BINARY_OP_FUNCTOR(fmin, number_kind_floating_point)
3691 BINARY_OP_FUNCTOR(atan2, number_kind_floating_point)
3692 BINARY_OP_FUNCTOR(fdim, number_kind_floating_point)
3693 BINARY_OP_FUNCTOR(hypot, number_kind_floating_point)
3694 BINARY_OP_FUNCTOR(remainder, number_kind_floating_point)
3695 
3696 UNARY_OP_FUNCTOR(logb, number_kind_floating_point)
3697 HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point)
3698 HETERO_BINARY_OP_FUNCTOR(scalbln, short, number_kind_floating_point)
3699 HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point)
3700 HETERO_BINARY_OP_FUNCTOR_B(scalbln, int, number_kind_floating_point)
3701 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point)
3702 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long, number_kind_floating_point)
3703 HETERO_BINARY_OP_FUNCTOR_B(scalbn, boost::long_long_type, number_kind_floating_point)
3704 HETERO_BINARY_OP_FUNCTOR_B(scalbln, boost::long_long_type, number_kind_floating_point)
3705 
3706 //
3707 // Complex functions:
3708 //
3709 UNARY_OP_FUNCTOR(exp, number_kind_complex)
3710 UNARY_OP_FUNCTOR(log, number_kind_complex)
3711 UNARY_OP_FUNCTOR(log10, number_kind_complex)
3712 BINARY_OP_FUNCTOR(pow, number_kind_complex)
3713 UNARY_OP_FUNCTOR(sqrt, number_kind_complex)
3714 UNARY_OP_FUNCTOR(sin, number_kind_complex)
3715 UNARY_OP_FUNCTOR(cos, number_kind_complex)
3716 UNARY_OP_FUNCTOR(tan, number_kind_complex)
3717 UNARY_OP_FUNCTOR(asin, number_kind_complex)
3718 UNARY_OP_FUNCTOR(acos, number_kind_complex)
3719 UNARY_OP_FUNCTOR(atan, number_kind_complex)
3720 UNARY_OP_FUNCTOR(sinh, number_kind_complex)
3721 UNARY_OP_FUNCTOR(cosh, number_kind_complex)
3722 UNARY_OP_FUNCTOR(tanh, number_kind_complex)
3723 UNARY_OP_FUNCTOR(asinh, number_kind_complex)
3724 UNARY_OP_FUNCTOR(acosh, number_kind_complex)
3725 UNARY_OP_FUNCTOR(atanh, number_kind_complex)
3726 
3727 //
3728 // Integer functions:
3729 //
3730 BINARY_OP_FUNCTOR(gcd, number_kind_integer)
3731 BINARY_OP_FUNCTOR(lcm, number_kind_integer)
3732 HETERO_BINARY_OP_FUNCTOR(pow, unsigned, number_kind_integer)
3733 
3734 #undef BINARY_OP_FUNCTOR
3735 #undef UNARY_OP_FUNCTOR
3736 
3737 //
3738 // ilogb:
3739 //
3740 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3741 inline typename enable_if_c<number_category<Backend>::value == number_kind_floating_point, typename Backend::exponent_type>::type
3742    ilogb(const multiprecision::number<Backend, ExpressionTemplates>& val)
3743 {
3744    using default_ops::eval_ilogb;
3745    return eval_ilogb(val.backend());
3746 }
3747 
3748 template <class tag, class A1, class A2, class A3, class A4>
3749 inline typename enable_if_c<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == number_kind_floating_point, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type::backend_type::exponent_type>::type
ilogb(const detail::expression<tag,A1,A2,A3,A4> & val)3750 ilogb(const detail::expression<tag, A1, A2, A3, A4>& val)
3751 {
3752    using default_ops::eval_ilogb;
3753    typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type arg(val);
3754    return eval_ilogb(arg.backend());
3755 }
3756 
3757 } //namespace multiprecision
3758 
3759 namespace math{
3760 //
3761 // Overload of Boost.Math functions that find the wrong overload when used with number:
3762 //
3763 namespace detail{
3764    template <class T> T sinc_pi_imp(T);
3765    template <class T> T sinhc_pi_imp(T);
3766 }
3767 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
sinc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x)3768 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3769 {
3770    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3771    return BOOST_MP_MOVE(detail::sinc_pi_imp(x));
3772 }
3773 
3774 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
sinc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x,const Policy &)3775 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3776 {
3777    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3778    return BOOST_MP_MOVE(detail::sinc_pi_imp(x));
3779 }
3780 
3781 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
sinhc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x)3782 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3783 {
3784    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3785    return BOOST_MP_MOVE(detail::sinhc_pi_imp(x));
3786 }
3787 
3788 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
sinhc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x,const Policy &)3789 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3790 {
3791    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3792    return BOOST_MP_MOVE(boost::math::sinhc_pi(x));
3793 }
3794 
3795 using boost::multiprecision::gcd;
3796 using boost::multiprecision::lcm;
3797 
3798 #ifdef BOOST_MSVC
3799 #pragma warning(pop)
3800 #endif
3801 } // namespace math
3802 
3803 namespace integer {
3804 
3805 using boost::multiprecision::gcd;
3806 using boost::multiprecision::lcm;
3807 
3808 }
3809 
3810 } // namespace boost
3811 
3812 //
3813 // This has to come last of all:
3814 //
3815 #include <boost/multiprecision/detail/no_et_ops.hpp>
3816 #include <boost/multiprecision/detail/et_ops.hpp>
3817 //
3818 // min/max overloads:
3819 //
3820 #include <boost/multiprecision/detail/min_max.hpp>
3821 
3822 #endif
3823 
3824