Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / multiprecision / detail / default_ops.hpp
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 namespace boost {
33 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 } // namespace detail
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 BOOST_MP_CXX14_CONSTEXPR typename disable_if_c<is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename disable_if_c<is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename disable_if_c<is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v);
120
121 template <class T, class U, class V>
122 inline BOOST_MP_CXX14_CONSTEXPR 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>
129 inline BOOST_MP_CXX14_CONSTEXPR 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>
134 inline BOOST_MP_CXX14_CONSTEXPR 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>
141 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
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 BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v);
242
243 template <class T>
244 inline BOOST_MP_CXX14_CONSTEXPR 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>
261 inline BOOST_MP_CXX14_CONSTEXPR 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>
268 inline BOOST_MP_CXX14_CONSTEXPR 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>
274 inline BOOST_MP_CXX14_CONSTEXPR 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>
279 inline BOOST_MP_CXX14_CONSTEXPR 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>
292 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR eval_subtract(T& t, const U& u, const V& v);
299
300 template <class T>
301 inline BOOST_MP_CXX14_CONSTEXPR 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>
319 inline BOOST_MP_CXX14_CONSTEXPR 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>
326 inline BOOST_MP_CXX14_CONSTEXPR 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>
332 inline BOOST_MP_CXX14_CONSTEXPR 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>
338 inline BOOST_MP_CXX14_CONSTEXPR 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>
345 inline BOOST_MP_CXX14_CONSTEXPR 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>
351 inline BOOST_MP_CXX14_CONSTEXPR 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>
365 inline BOOST_MP_CXX14_CONSTEXPR 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>
371 inline BOOST_MP_CXX14_CONSTEXPR 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>
389 inline BOOST_MP_CXX14_CONSTEXPR 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>
396 inline BOOST_MP_CXX14_CONSTEXPR 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>
402 inline BOOST_MP_CXX14_CONSTEXPR 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>
408 inline BOOST_MP_CXX14_CONSTEXPR 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>
421 inline BOOST_MP_CXX14_CONSTEXPR 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>
427 inline BOOST_MP_CXX14_CONSTEXPR 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>
443 inline BOOST_MP_CXX14_CONSTEXPR 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 t;
448 }
449 template <class T>
450 inline BOOST_MP_CXX14_CONSTEXPR const T& make_T(const T& t)
451 {
452    return t;
453 }
454
455 template <class T, class U, class V, class X>
456 inline BOOST_MP_CXX14_CONSTEXPR 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>
461 inline BOOST_MP_CXX14_CONSTEXPR 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>
466 inline BOOST_MP_CXX14_CONSTEXPR 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>
481 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v);
488
489 template <class T>
490 inline BOOST_MP_CXX14_CONSTEXPR 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>
508 inline BOOST_MP_CXX14_CONSTEXPR 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>
515 inline BOOST_MP_CXX14_CONSTEXPR 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>
521 inline BOOST_MP_CXX14_CONSTEXPR 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>
528 inline BOOST_MP_CXX14_CONSTEXPR 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>
535 inline BOOST_MP_CXX14_CONSTEXPR 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>
551 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v);
558
559 template <class T>
560 inline BOOST_MP_CXX14_CONSTEXPR 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>
577 inline BOOST_MP_CXX14_CONSTEXPR 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>
584 inline BOOST_MP_CXX14_CONSTEXPR 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>
590 inline BOOST_MP_CXX14_CONSTEXPR 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>
597 inline BOOST_MP_CXX14_CONSTEXPR 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>
603 inline BOOST_MP_CXX14_CONSTEXPR 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>
618 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v);
625
626 template <class T>
627 inline BOOST_MP_CXX14_CONSTEXPR 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>
644 inline BOOST_MP_CXX14_CONSTEXPR 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>
651 inline BOOST_MP_CXX14_CONSTEXPR 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>
657 inline BOOST_MP_CXX14_CONSTEXPR 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>
662 inline BOOST_MP_CXX14_CONSTEXPR 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>
668 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v);
675
676 template <class T>
677 inline BOOST_MP_CXX14_CONSTEXPR 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>
694 inline BOOST_MP_CXX14_CONSTEXPR 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>
701 inline BOOST_MP_CXX14_CONSTEXPR 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>
707 inline BOOST_MP_CXX14_CONSTEXPR 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>
712 inline BOOST_MP_CXX14_CONSTEXPR 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>
725 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v);
732
733 template <class T>
734 inline BOOST_MP_CXX14_CONSTEXPR 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>
751 inline BOOST_MP_CXX14_CONSTEXPR 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>
758 inline BOOST_MP_CXX14_CONSTEXPR 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>
764 inline BOOST_MP_CXX14_CONSTEXPR 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>
769 inline BOOST_MP_CXX14_CONSTEXPR 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>
782 inline BOOST_MP_CXX14_CONSTEXPR 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>
788 inline BOOST_MP_CXX14_CONSTEXPR 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>
794 inline BOOST_MP_CXX14_CONSTEXPR 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>
801 inline BOOST_MP_CXX14_CONSTEXPR 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>
808 inline BOOST_MP_CXX14_CONSTEXPR 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>
815 inline BOOST_MP_CXX14_CONSTEXPR 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>
821 inline BOOST_MP_CXX14_CONSTEXPR 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>
828 inline BOOST_MP_CXX14_CONSTEXPR 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>
837 inline BOOST_MP_CXX14_CONSTEXPR 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>
846 inline BOOST_MP_CXX14_CONSTEXPR 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>
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>
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
876 template <class R>
877 struct terminal
878 {
879    BOOST_MP_CXX14_CONSTEXPR terminal(const R& v) : value(v) {}
880    BOOST_MP_CXX14_CONSTEXPR terminal() {}
881    BOOST_MP_CXX14_CONSTEXPR terminal& operator=(R val)
882    {
883       value = val;
884       return *this;
885    }
886    R value;
887    BOOST_MP_CXX14_CONSTEXPR operator R() const { return value; }
888 };
889
890 template <class R, class B>
891 struct calculate_next_larger_type
892 {
893    // Find which list we're looking through:
894    typedef typename mpl::if_<
895        is_signed<R>,
896        typename B::signed_types,
897        typename mpl::if_<
898            is_unsigned<R>,
899            typename B::unsigned_types,
900            typename B::float_types>::type>::type list_type;
901    // A predicate to find a type with enough bits:
902    typedef typename has_enough_bits<R, std::numeric_limits<R>::digits>::template type<mpl::_> pred_type;
903    // See if the last type is in the list, if so we have to start after this:
904    typedef typename mpl::find_if<
905        list_type,
906        is_same<R, mpl::_> >::type start_last;
907    // Where we're starting from, either the start of the sequence or the last type found:
908    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;
909    // The range we're searching:
910    typedef mpl::iterator_range<start_seq, typename mpl::end<list_type>::type> range;
911    // Find the next type:
912    typedef typename mpl::find_if<
913        range,
914        pred_type>::type iter_type;
915    // Either the next type, or a "terminal" to indicate we've run out of types to search:
916    typedef typename mpl::eval_if<
917        is_same<typename mpl::end<list_type>::type, iter_type>,
918        mpl::identity<terminal<R> >,
919        mpl::deref<iter_type> >::type type;
920 };
921
922 template <class R, class T>
923 inline BOOST_MP_CXX14_CONSTEXPR 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>
933 inline BOOST_MP_CXX14_CONSTEXPR 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 = next_type();
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>
951 inline BOOST_MP_CXX14_CONSTEXPR 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 = next_type();
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>
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>
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>
1016 inline BOOST_MP_CXX14_CONSTEXPR 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>
1023 inline BOOST_MP_CXX14_CONSTEXPR 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>
1033 inline BOOST_MP_CXX14_CONSTEXPR 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>
1039 inline BOOST_MP_CXX14_CONSTEXPR 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>
1050 inline BOOST_MP_CXX14_CONSTEXPR 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>
1061 inline BOOST_MP_CXX14_CONSTEXPR 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>
1075 inline BOOST_MP_CXX14_CONSTEXPR 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>
1084 inline BOOST_MP_CXX14_CONSTEXPR 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>
1095 inline BOOST_MP_CXX14_CONSTEXPR 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>
1102 inline BOOST_MP_CXX14_CONSTEXPR 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>
1141 inline BOOST_MP_CXX14_CONSTEXPR 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>
1151 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a);
1162
1163 template <class T>
1164 inline BOOST_MP_CXX14_CONSTEXPR 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>
1182 inline BOOST_MP_CXX14_CONSTEXPR 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 = cast_type();
1187    c = a;
1188    eval_remquo(result, x, c, pi);
1189 }
1190 template <class T, class A>
1191 inline BOOST_MP_CXX14_CONSTEXPR 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 = cast_type();
1196    c = x;
1197    eval_remquo(result, c, a, pi);
1198 }
1199 template <class T, class U, class V>
1200 inline BOOST_MP_CXX14_CONSTEXPR void eval_remainder(T& result, const U& a, const V& b)
1201 {
1202    int i(0);
1203    eval_remquo(result, a, b, &i);
1204 }
1205
1206 template <class B>
1207 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const B& a, const B& b);
1208 template <class T, class U>
1209 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const T& a, const U& b);
1210 template <class B>
1211 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const B& a, const B& b);
1212 template <class T, class U>
1213 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const T& a, const U& b);
1214
1215 template <class T>
1216 inline BOOST_MP_CXX14_CONSTEXPR 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    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>
1245 inline BOOST_MP_CXX14_CONSTEXPR 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    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>
1276 inline BOOST_MP_CXX14_CONSTEXPR 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    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>
1307 inline BOOST_MP_CXX14_CONSTEXPR 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>
1327 inline BOOST_MP_CXX14_CONSTEXPR 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>
1359 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR void eval_lcm(B& result, const B& a, const B& b);
1388 template <class B>
1389 BOOST_MP_CXX14_CONSTEXPR void eval_gcd(B& result, const B& a, const B& b);
1390
1391 template <class T, class Arithmetic>
1392 inline BOOST_MP_CXX14_CONSTEXPR 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>
1401 inline BOOST_MP_CXX14_CONSTEXPR 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>
1406 inline BOOST_MP_CXX14_CONSTEXPR 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>
1415 inline BOOST_MP_CXX14_CONSTEXPR 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>
1421 inline BOOST_MP_CXX14_CONSTEXPR 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    } while (eval_is_zero(t));
1442
1443    return --result;
1444 }
1445
1446 template <class T>
1447 inline BOOST_MP_CXX14_CONSTEXPR int eval_msb(const T& val)
1448 {
1449    int c = eval_get_sign(val);
1450    if (c == 0)
1451    {
1452       BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
1453    }
1454    if (c < 0)
1455    {
1456       BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
1457    }
1458    //
1459    // This implementation is really really rubbish - it does
1460    // a linear scan for the most-significant-bit.  We should really
1461    // do a binary search, but as none of our backends actually needs
1462    // this implementation, we'll leave it for now.  In fact for most
1463    // backends it's likely that there will always be a more efficient
1464    // native implementation possible.
1465    //
1466    unsigned result = 0;
1467    T        t(val);
1468    while (!eval_is_zero(t))
1469    {
1470       eval_right_shift(t, 1);
1471       ++result;
1472    }
1473    return --result;
1474 }
1475
1476 template <class T>
1477 inline BOOST_MP_CXX14_CONSTEXPR bool eval_bit_test(const T& val, unsigned index)
1478 {
1479    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1480    T                                                                            mask, t;
1481    mask = ui_type(1);
1482    eval_left_shift(mask, index);
1483    eval_bitwise_and(t, mask, val);
1484    return !eval_is_zero(t);
1485 }
1486
1487 template <class T>
1488 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_set(T& val, unsigned index)
1489 {
1490    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1491    T                                                                            mask;
1492    mask = ui_type(1);
1493    eval_left_shift(mask, index);
1494    eval_bitwise_or(val, mask);
1495 }
1496
1497 template <class T>
1498 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_flip(T& val, unsigned index)
1499 {
1500    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1501    T                                                                            mask;
1502    mask = ui_type(1);
1503    eval_left_shift(mask, index);
1504    eval_bitwise_xor(val, mask);
1505 }
1506
1507 template <class T>
1508 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_unset(T& val, unsigned index)
1509 {
1510    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1511    T                                                                            mask, t;
1512    mask = ui_type(1);
1513    eval_left_shift(mask, index);
1514    eval_bitwise_and(t, mask, val);
1515    if (!eval_is_zero(t))
1516       eval_bitwise_xor(val, mask);
1517 }
1518
1519 template <class B>
1520 void BOOST_MP_CXX14_CONSTEXPR eval_integer_sqrt(B& s, B& r, const B& x)
1521 {
1522    //
1523    // This is slow bit-by-bit integer square root, see for example
1524    // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
1525    // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
1526    // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
1527    // at some point.
1528    //
1529    typedef typename boost::multiprecision::detail::canonical<unsigned char, B>::type ui_type;
1530
1531    s = ui_type(0u);
1532    if (eval_get_sign(x) == 0)
1533    {
1534       r = ui_type(0u);
1535       return;
1536    }
1537    int g = eval_msb(x);
1538    if (g <= 1)
1539    {
1540       s = ui_type(1);
1541       eval_subtract(r, x, s);
1542       return;
1543    }
1544
1545    B t;
1546    r = x;
1547    g /= 2;
1548    int org_g = g;
1549    eval_bit_set(s, g);
1550    eval_bit_set(t, 2 * g);
1551    eval_subtract(r, x, t);
1552    --g;
1553    if (eval_get_sign(r) == 0)
1554       return;
1555    int msbr = eval_msb(r);
1556    do
1557    {
1558       if (msbr >= org_g + g + 1)
1559       {
1560          t = s;
1561          eval_left_shift(t, g + 1);
1562          eval_bit_set(t, 2 * g);
1563          if (t.compare(r) <= 0)
1564          {
1565             BOOST_ASSERT(g >= 0);
1566             eval_bit_set(s, g);
1567             eval_subtract(r, t);
1568             if (eval_get_sign(r) == 0)
1569                return;
1570             msbr = eval_msb(r);
1571          }
1572       }
1573       --g;
1574    } while (g >= 0);
1575 }
1576
1577 template <class B>
1578 inline BOOST_MP_CXX14_CONSTEXPR void eval_conj(B& result, const B& val)
1579 {
1580    result = val; // assume non-complex result.
1581 }
1582 template <class B>
1583 inline BOOST_MP_CXX14_CONSTEXPR void eval_proj(B& result, const B& val)
1584 {
1585    result = val; // assume non-complex result.
1586 }
1587
1588 //
1589 // These have to implemented by the backend, declared here so that our macro generated code compiles OK.
1590 //
1591 template <class T>
1592 typename enable_if_c<sizeof(T) == 0>::type eval_floor();
1593 template <class T>
1594 typename enable_if_c<sizeof(T) == 0>::type eval_ceil();
1595 template <class T>
1596 typename enable_if_c<sizeof(T) == 0>::type eval_trunc();
1597 template <class T>
1598 typename enable_if_c<sizeof(T) == 0>::type eval_sqrt();
1599 template <class T>
1600 typename enable_if_c<sizeof(T) == 0>::type eval_ldexp();
1601 template <class T>
1602 typename enable_if_c<sizeof(T) == 0>::type eval_frexp();
1603 // TODO implement default versions of these:
1604 template <class T>
1605 typename enable_if_c<sizeof(T) == 0>::type eval_asinh();
1606 template <class T>
1607 typename enable_if_c<sizeof(T) == 0>::type eval_acosh();
1608 template <class T>
1609 typename enable_if_c<sizeof(T) == 0>::type eval_atanh();
1610
1611 //
1612 // eval_logb and eval_scalbn simply assume base 2 and forward to
1613 // eval_ldexp and eval_frexp:
1614 //
1615 template <class B>
1616 inline BOOST_MP_CXX14_CONSTEXPR typename B::exponent_type eval_ilogb(const B& val)
1617 {
1618    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");
1619    typename B::exponent_type e(0);
1620    switch (eval_fpclassify(val))
1621    {
1622    case FP_NAN:
1623 #ifdef FP_ILOGBNAN
1624       return FP_ILOGBNAN > 0 ? (std::numeric_limits<typename B::exponent_type>::max)() : (std::numeric_limits<typename B::exponent_type>::min)();
1625 #else
1626       return (std::numeric_limits<typename B::exponent_type>::max)();
1627 #endif
1628    case FP_INFINITE:
1629       return (std::numeric_limits<typename B::exponent_type>::max)();
1630    case FP_ZERO:
1631       return (std::numeric_limits<typename B::exponent_type>::min)();
1632    }
1633    B result;
1634    eval_frexp(result, val, &e);
1635    return e - 1;
1636 }
1637
1638 template <class T>
1639 BOOST_MP_CXX14_CONSTEXPR int eval_signbit(const T& val);
1640
1641 template <class B>
1642 inline BOOST_MP_CXX14_CONSTEXPR void eval_logb(B& result, const B& val)
1643 {
1644    switch (eval_fpclassify(val))
1645    {
1646    case FP_NAN:
1647       result = val;
1648       errno  = EDOM;
1649       return;
1650    case FP_ZERO:
1651       result = std::numeric_limits<number<B> >::infinity().backend();
1652       result.negate();
1653       errno = ERANGE;
1654       return;
1655    case FP_INFINITE:
1656       result = val;
1657       if (eval_signbit(val))
1658          result.negate();
1659       return;
1660    }
1661    typedef typename boost::mpl::if_c<boost::is_same<boost::intmax_t, long>::value, boost::long_long_type, boost::intmax_t>::type max_t;
1662    result = static_cast<max_t>(eval_ilogb(val));
1663 }
1664 template <class B, class A>
1665 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbn(B& result, const B& val, A e)
1666 {
1667    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");
1668    eval_ldexp(result, val, static_cast<typename B::exponent_type>(e));
1669 }
1670 template <class B, class A>
1671 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbln(B& result, const B& val, A e)
1672 {
1673    eval_scalbn(result, val, e);
1674 }
1675
1676 template <class T>
1677 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, mpl::true_ const&, const mpl::false_&)
1678 {
1679    return eval_fpclassify(val) == FP_NAN;
1680 }
1681 template <class T>
1682 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, mpl::false_ const&, const mpl::true_&)
1683 {
1684    return (boost::math::isnan)(val);
1685 }
1686 template <class T>
1687 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T&, mpl::false_ const&, const mpl::false_&)
1688 {
1689    return false;
1690 }
1691
1692 template <class T>
1693 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val)
1694 {
1695    return is_arg_nan(val, mpl::bool_<boost::multiprecision::detail::is_backend<T>::value>(), is_floating_point<T>());
1696 }
1697
1698 template <class T, class U, class V>
1699 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmax(T& result, const U& a, const V& b)
1700 {
1701    if (is_arg_nan(a))
1702       result = number<T>::canonical_value(b);
1703    else if (is_arg_nan(b))
1704       result = number<T>::canonical_value(a);
1705    else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1706       result = number<T>::canonical_value(b);
1707    else
1708       result = number<T>::canonical_value(a);
1709 }
1710 template <class T, class U, class V>
1711 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmin(T& result, const U& a, const V& b)
1712 {
1713    if (is_arg_nan(a))
1714       result = number<T>::canonical_value(b);
1715    else if (is_arg_nan(b))
1716       result = number<T>::canonical_value(a);
1717    else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1718       result = number<T>::canonical_value(a);
1719    else
1720       result = number<T>::canonical_value(b);
1721 }
1722
1723 template <class R, class T, class U>
1724 inline BOOST_MP_CXX14_CONSTEXPR void eval_hypot(R& result, const T& a, const U& b)
1725 {
1726    //
1727    // Normalize x and y, so that both are positive and x >= y:
1728    //
1729    R x, y;
1730    x = number<R>::canonical_value(a);
1731    y = number<R>::canonical_value(b);
1732    if (eval_get_sign(x) < 0)
1733       x.negate();
1734    if (eval_get_sign(y) < 0)
1735       y.negate();
1736
1737    // Special case, see C99 Annex F.
1738    // The order of the if's is important: do not change!
1739    int c1 = eval_fpclassify(x);
1740    int c2 = eval_fpclassify(y);
1741
1742    if (c1 == FP_ZERO)
1743    {
1744       result = y;
1745       return;
1746    }
1747    if (c2 == FP_ZERO)
1748    {
1749       result = x;
1750       return;
1751    }
1752    if (c1 == FP_INFINITE)
1753    {
1754       result = x;
1755       return;
1756    }
1757    if ((c2 == FP_INFINITE) || (c2 == FP_NAN))
1758    {
1759       result = y;
1760       return;
1761    }
1762    if (c1 == FP_NAN)
1763    {
1764       result = x;
1765       return;
1766    }
1767
1768    if (eval_gt(y, x))
1769       x.swap(y);
1770
1771    eval_multiply(result, x, std::numeric_limits<number<R> >::epsilon().backend());
1772
1773    if (eval_gt(result, y))
1774    {
1775       result = x;
1776       return;
1777    }
1778
1779    R rat;
1780    eval_divide(rat, y, x);
1781    eval_multiply(result, rat, rat);
1782    eval_increment(result);
1783    eval_sqrt(rat, result);
1784    eval_multiply(result, rat, x);
1785 }
1786
1787 template <class R, class T>
1788 inline BOOST_MP_CXX14_CONSTEXPR void eval_nearbyint(R& result, const T& a)
1789 {
1790    eval_round(result, a);
1791 }
1792 template <class R, class T>
1793 inline BOOST_MP_CXX14_CONSTEXPR void eval_rint(R& result, const T& a)
1794 {
1795    eval_nearbyint(result, a);
1796 }
1797
1798 template <class T>
1799 inline BOOST_MP_CXX14_CONSTEXPR int eval_signbit(const T& val)
1800 {
1801    return eval_get_sign(val) < 0 ? 1 : 0;
1802 }
1803
1804 //
1805 // Real and imaginary parts:
1806 //
1807 template <class To, class From>
1808 inline BOOST_MP_CXX14_CONSTEXPR void eval_real(To& to, const From& from)
1809 {
1810    to = from;
1811 }
1812 template <class To, class From>
1813 inline BOOST_MP_CXX14_CONSTEXPR void eval_imag(To& to, const From&)
1814 {
1815    typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
1816    to = ui_type(0);
1817 }
1818
1819 } // namespace default_ops
1820 namespace default_ops_adl {
1821
1822 template <class To, class From>
1823 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real_imp(To& to, const From& from)
1824 {
1825    typedef typename component_type<number<To> >::type to_component_type;
1826    typename to_component_type::backend_type           to_component;
1827    to_component = from;
1828    eval_set_real(to, to_component);
1829 }
1830 template <class To, class From>
1831 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag_imp(To& to, const From& from)
1832 {
1833    typedef typename component_type<number<To> >::type to_component_type;
1834    typename to_component_type::backend_type           to_component;
1835    to_component = from;
1836    eval_set_imag(to, to_component);
1837 }
1838
1839 } // namespace default_ops_adl
1840 namespace default_ops {
1841
1842 template <class To, class From>
1843 inline BOOST_MP_CXX14_CONSTEXPR 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>
1848 inline BOOST_MP_CXX14_CONSTEXPR 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>
1854 inline BOOST_MP_CXX14_CONSTEXPR 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>
1860 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real(T& to, const T& from)
1861 {
1862    to = from;
1863 }
1864 template <class T>
1865 void BOOST_MP_CXX14_CONSTEXPR 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 } // namespace default_ops
1879
1880 //
1881 // Default versions of floating point classification routines:
1882 //
1883 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
1884 inline BOOST_MP_CXX14_CONSTEXPR 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>
1890 inline BOOST_MP_CXX14_CONSTEXPR 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>
1896 inline BOOST_MP_CXX14_CONSTEXPR 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>
1902 inline BOOST_MP_CXX14_CONSTEXPR 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>
1908 inline BOOST_MP_CXX14_CONSTEXPR 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>
1913 inline BOOST_MP_CXX14_CONSTEXPR 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>
1919 inline BOOST_MP_CXX14_CONSTEXPR 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>
1924 inline BOOST_MP_CXX14_CONSTEXPR 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>
1930 inline BOOST_MP_CXX14_CONSTEXPR 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>
1935 inline BOOST_MP_CXX14_CONSTEXPR 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>
1945 inline BOOST_MP_CXX14_CONSTEXPR 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>
1950 inline BOOST_MP_CXX14_CONSTEXPR 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>
1957 inline BOOST_MP_CXX14_CONSTEXPR 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>
1963 inline BOOST_MP_CXX14_CONSTEXPR 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>
1969 inline BOOST_MP_CXX14_CONSTEXPR 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>
1974 inline BOOST_MP_CXX14_CONSTEXPR 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>
1980 inline BOOST_MP_CXX14_CONSTEXPR 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>
1985 inline BOOST_MP_CXX14_CONSTEXPR 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>
1990 inline BOOST_MP_CXX14_CONSTEXPR 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>
1995 inline BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
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 BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
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 BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
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 BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
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 BOOST_MP_CXX14_CONSTEXPR typename boost::lazy_enable_if_c<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates> > >::type
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 BOOST_MP_CXX14_CONSTEXPR 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
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<T>::value == number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
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 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<T>::value == number_kind_floating_point, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
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 BOOST_MP_CXX14_CONSTEXPR 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
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 BOOST_MP_CXX14_CONSTEXPR typename boost::lazy_enable_if_c<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates> > >::type
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 BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<number_category<T>::value != number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
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 BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
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>
2104 BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR 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
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 BOOST_MP_CXX14_CONSTEXPR 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
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 BOOST_MP_CXX14_CONSTEXPR 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
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 BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_arithmetic<Scalar>::value, typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
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 BOOST_MP_CXX14_CONSTEXPR 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
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>
2155 BOOST_MP_CXX14_CONSTEXPR 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 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
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 } // namespace multiprecision
2168
2169 namespace math {
2170
2171 //
2172 // Import Math functions here, so they can be found by Boost.Math:
2173 //
2174 using boost::multiprecision::changesign;
2175 using boost::multiprecision::copysign;
2176 using boost::multiprecision::fpclassify;
2177 using boost::multiprecision::isfinite;
2178 using boost::multiprecision::isinf;
2179 using boost::multiprecision::isnan;
2180 using boost::multiprecision::isnormal;
2181 using boost::multiprecision::sign;
2182 using boost::multiprecision::signbit;
2183
2184 } // namespace math
2185
2186 namespace multiprecision {
2187
2188 typedef ::boost::math::policies::policy<
2189     ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>,
2190     ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>,
2191     ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>,
2192     ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>,
2193     ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error> >
2194     c99_error_policy;
2195
2196 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2197 inline BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2198     asinh
2199     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2200 {
2201    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2202    return boost::math::asinh(arg, c99_error_policy());
2203 }
2204 template <class tag, class A1, class A2, class A3, class A4>
2205 inline BOOST_MP_CXX14_CONSTEXPR 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
2206     asinh
2207     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 BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2215     acosh
2216     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2217 {
2218    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2219    return boost::math::acosh(arg, c99_error_policy());
2220 }
2221 template <class tag, class A1, class A2, class A3, class A4>
2222 inline BOOST_MP_CXX14_CONSTEXPR 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
2223     acosh
2224     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2225 {
2226    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2227    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2228    return acosh(value_type(arg));
2229 }
2230 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2231 inline BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2232     atanh
2233     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2234 {
2235    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2236    return boost::math::atanh(arg, c99_error_policy());
2237 }
2238 template <class tag, class A1, class A2, class A3, class A4>
2239 inline BOOST_MP_CXX14_CONSTEXPR 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
2240     atanh
2241     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2242 {
2243    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2244    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2245    return atanh(value_type(arg));
2246 }
2247 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2248 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2249 {
2250    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2251    return boost::math::cbrt(arg, c99_error_policy());
2252 }
2253 template <class tag, class A1, class A2, class A3, class A4>
2254 inline BOOST_MP_CXX14_CONSTEXPR 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)
2255 {
2256    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2257    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2258    return cbrt(value_type(arg));
2259 }
2260 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2261 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2262 {
2263    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2264    return boost::math::erf(arg, c99_error_policy());
2265 }
2266 template <class tag, class A1, class A2, class A3, class A4>
2267 inline BOOST_MP_CXX14_CONSTEXPR 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)
2268 {
2269    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2270    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2271    return erf(value_type(arg));
2272 }
2273 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2274 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2275 {
2276    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2277    return boost::math::erfc(arg, c99_error_policy());
2278 }
2279 template <class tag, class A1, class A2, class A3, class A4>
2280 inline BOOST_MP_CXX14_CONSTEXPR 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)
2281 {
2282    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2283    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2284    return erfc(value_type(arg));
2285 }
2286 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2287 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2288 {
2289    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2290    return boost::math::expm1(arg, c99_error_policy());
2291 }
2292 template <class tag, class A1, class A2, class A3, class A4>
2293 inline BOOST_MP_CXX14_CONSTEXPR 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)
2294 {
2295    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2296    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2297    return expm1(value_type(arg));
2298 }
2299 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2300 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2301 {
2302    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2303    multiprecision::number<Backend, ExpressionTemplates>                                    result;
2304    result = boost::math::lgamma(arg, c99_error_policy());
2305    if ((boost::multiprecision::isnan)(result) && !(boost::multiprecision::isnan)(arg))
2306    {
2307       result = std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::infinity();
2308       errno  = ERANGE;
2309    }
2310    return result;
2311 }
2312 template <class tag, class A1, class A2, class A3, class A4>
2313 inline BOOST_MP_CXX14_CONSTEXPR 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)
2314 {
2315    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2316    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2317    return lgamma(value_type(arg));
2318 }
2319 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2320 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2321 {
2322    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2323    if ((arg == 0) && std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::has_infinity)
2324    {
2325       errno = ERANGE;
2326       return 1 / arg;
2327    }
2328    return boost::math::tgamma(arg, c99_error_policy());
2329 }
2330 template <class tag, class A1, class A2, class A3, class A4>
2331 inline BOOST_MP_CXX14_CONSTEXPR 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)
2332 {
2333    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2334    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2335    return tgamma(value_type(arg));
2336 }
2337
2338 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2339 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2340 {
2341    return lround(arg);
2342 }
2343 template <class tag, class A1, class A2, class A3, class A4>
2344 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2345 {
2346    return lround(arg);
2347 }
2348 #ifndef BOOST_NO_LONG_LONG
2349 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2350 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2351 {
2352    return llround(arg);
2353 }
2354 template <class tag, class A1, class A2, class A3, class A4>
2355 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2356 {
2357    return llround(arg);
2358 }
2359 #endif
2360 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2361 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2362 {
2363    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2364    return boost::math::log1p(arg, c99_error_policy());
2365 }
2366 template <class tag, class A1, class A2, class A3, class A4>
2367 inline BOOST_MP_CXX14_CONSTEXPR 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)
2368 {
2369    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2370    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2371    return log1p(value_type(arg));
2372 }
2373
2374 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2375 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2376 {
2377    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2378    return boost::math::nextafter(a, b, c99_error_policy());
2379 }
2380 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2381 inline BOOST_MP_CXX14_CONSTEXPR 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)
2382 {
2383    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2384    return nextafter                                                                        BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2385 }
2386 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2387 inline BOOST_MP_CXX14_CONSTEXPR 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)
2388 {
2389    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2390    return nextafter                                                                        BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2391 }
2392 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2393 inline BOOST_MP_CXX14_CONSTEXPR 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)
2394 {
2395    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2396    detail::scoped_default_precision<value_type>                                          precision_guard(a, b);
2397    return nextafter                                                                      BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2398 }
2399 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2400 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2401 {
2402    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2403    return boost::math::nextafter(a, b, c99_error_policy());
2404 }
2405 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2406 inline BOOST_MP_CXX14_CONSTEXPR 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)
2407 {
2408    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2409    return nexttoward                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2410 }
2411 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2412 inline BOOST_MP_CXX14_CONSTEXPR 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)
2413 {
2414    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2415    return nexttoward                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2416 }
2417 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2418 inline BOOST_MP_CXX14_CONSTEXPR 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)
2419 {
2420    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
2421    detail::scoped_default_precision<value_type>                                          precision_guard(a, b);
2422    return nexttoward                                                                     BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2423 }
2424
2425 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2426 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2427 {
2428    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2429    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2430    using default_ops::eval_add;
2431    eval_add(result.backend(), a.backend(), b.backend());
2432    return result;
2433 }
2434
2435 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2436 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2437 {
2438    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2439    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2440    using default_ops::eval_subtract;
2441    eval_subtract(result.backend(), a.backend(), b.backend());
2442    return result;
2443 }
2444
2445 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2446 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2447 {
2448    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2449    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2450    using default_ops::eval_multiply;
2451    eval_multiply(result.backend(), a.backend(), b.backend());
2452    return result;
2453 }
2454
2455 template <class B, expression_template_option ET, class I>
2456 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
2457 add(number<B, ET>& result, const I& a, const I& b)
2458 {
2459    using default_ops::eval_add;
2460    typedef typename detail::canonical<I, B>::type canonical_type;
2461    eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2462    return result;
2463 }
2464
2465 template <class B, expression_template_option ET, class I>
2466 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
2467 subtract(number<B, ET>& result, const I& a, const I& b)
2468 {
2469    using default_ops::eval_subtract;
2470    typedef typename detail::canonical<I, B>::type canonical_type;
2471    eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2472    return result;
2473 }
2474
2475 template <class B, expression_template_option ET, class I>
2476 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
2477 multiply(number<B, ET>& result, const I& a, const I& b)
2478 {
2479    using default_ops::eval_multiply;
2480    typedef typename detail::canonical<I, B>::type canonical_type;
2481    eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2482    return result;
2483 }
2484
2485 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2486 inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression<tag, A1, A2, A3, A4>::result_type trunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2487 {
2488    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2489    return BOOST_MP_MOVE(trunc(number_type(v), pol));
2490 }
2491
2492 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2493 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates> trunc(const number<Backend, ExpressionTemplates>& v, const Policy&)
2494 {
2495    using default_ops::eval_trunc;
2496    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(v);
2497    number<Backend, ExpressionTemplates>                                                    result;
2498    eval_trunc(result.backend(), v.backend());
2499    return result;
2500 }
2501
2502 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2503 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2504 {
2505    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2506    number_type                                                           r(trunc(v, pol));
2507    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2508       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, number_type(v), 0, pol);
2509    return r.template convert_to<int>();
2510 }
2511 template <class tag, class A1, class A2, class A3, class A4>
2512 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2513 {
2514    return itrunc(v, boost::math::policies::policy<>());
2515 }
2516 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2517 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v, const Policy& pol)
2518 {
2519    number<Backend, ExpressionTemplates> r(trunc(v, pol));
2520    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2521       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, v, 0, pol);
2522    return r.template convert_to<int>();
2523 }
2524 template <class Backend, expression_template_option ExpressionTemplates>
2525 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v)
2526 {
2527    return itrunc(v, boost::math::policies::policy<>());
2528 }
2529 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2530 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2531 {
2532    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2533    number_type                                                           r(trunc(v, pol));
2534    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2535       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, number_type(v), 0L, pol);
2536    return r.template convert_to<long>();
2537 }
2538 template <class tag, class A1, class A2, class A3, class A4>
2539 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2540 {
2541    return ltrunc(v, boost::math::policies::policy<>());
2542 }
2543 template <class T, expression_template_option ExpressionTemplates, class Policy>
2544 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2545 {
2546    number<T, ExpressionTemplates> r(trunc(v, pol));
2547    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2548       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, v, 0L, pol);
2549    return r.template convert_to<long>();
2550 }
2551 template <class T, expression_template_option ExpressionTemplates>
2552 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v)
2553 {
2554    return ltrunc(v, boost::math::policies::policy<>());
2555 }
2556 #ifndef BOOST_NO_LONG_LONG
2557 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2558 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2559 {
2560    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2561    number_type                                                           r(trunc(v, pol));
2562    if ((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2563       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, number_type(v), 0LL, pol);
2564    return r.template convert_to<boost::long_long_type>();
2565 }
2566 template <class tag, class A1, class A2, class A3, class A4>
2567 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2568 {
2569    return lltrunc(v, boost::math::policies::policy<>());
2570 }
2571 template <class T, expression_template_option ExpressionTemplates, class Policy>
2572 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2573 {
2574    number<T, ExpressionTemplates> r(trunc(v, pol));
2575    if ((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2576       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, v, 0LL, pol);
2577    return r.template convert_to<boost::long_long_type>();
2578 }
2579 template <class T, expression_template_option ExpressionTemplates>
2580 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const number<T, ExpressionTemplates>& v)
2581 {
2582    return lltrunc(v, boost::math::policies::policy<>());
2583 }
2584 #endif
2585 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2586 inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression<tag, A1, A2, A3, A4>::result_type round(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2587 {
2588    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2589    return BOOST_MP_MOVE(round(static_cast<number_type>(v), pol));
2590 }
2591 template <class T, expression_template_option ExpressionTemplates, class Policy>
2592 inline BOOST_MP_CXX14_CONSTEXPR number<T, ExpressionTemplates> round(const number<T, ExpressionTemplates>& v, const Policy&)
2593 {
2594    using default_ops::eval_round;
2595    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2596    number<T, ExpressionTemplates>                                                    result;
2597    eval_round(result.backend(), v.backend());
2598    return result;
2599 }
2600
2601 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2602 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2603 {
2604    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2605    number_type                                                           r(round(v, pol));
2606    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2607       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0, pol);
2608    return r.template convert_to<int>();
2609 }
2610 template <class tag, class A1, class A2, class A3, class A4>
2611 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v)
2612 {
2613    return iround(v, boost::math::policies::policy<>());
2614 }
2615 template <class T, expression_template_option ExpressionTemplates, class Policy>
2616 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2617 {
2618    number<T, ExpressionTemplates> r(round(v, pol));
2619    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
2620       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0, pol);
2621    return r.template convert_to<int>();
2622 }
2623 template <class T, expression_template_option ExpressionTemplates>
2624 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v)
2625 {
2626    return iround(v, boost::math::policies::policy<>());
2627 }
2628 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2629 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2630 {
2631    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2632    number_type                                                           r(round(v, pol));
2633    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2634       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, number_type(v), 0L, pol);
2635    return r.template convert_to<long>();
2636 }
2637 template <class tag, class A1, class A2, class A3, class A4>
2638 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v)
2639 {
2640    return lround(v, boost::math::policies::policy<>());
2641 }
2642 template <class T, expression_template_option ExpressionTemplates, class Policy>
2643 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2644 {
2645    number<T, ExpressionTemplates> r(round(v, pol));
2646    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
2647       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, v, 0L, pol);
2648    return r.template convert_to<long>();
2649 }
2650 template <class T, expression_template_option ExpressionTemplates>
2651 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v)
2652 {
2653    return lround(v, boost::math::policies::policy<>());
2654 }
2655 #ifndef BOOST_NO_LONG_LONG
2656 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2657 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2658 {
2659    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2660    number_type                                                           r(round(v, pol));
2661    if ((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2662       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0LL, pol);
2663    return r.template convert_to<boost::long_long_type>();
2664 }
2665 template <class tag, class A1, class A2, class A3, class A4>
2666 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const detail::expression<tag, A1, A2, A3, A4>& v)
2667 {
2668    return llround(v, boost::math::policies::policy<>());
2669 }
2670 template <class T, expression_template_option ExpressionTemplates, class Policy>
2671 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2672 {
2673    number<T, ExpressionTemplates> r(round(v, pol));
2674    if ((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
2675       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0LL, pol);
2676    return r.template convert_to<boost::long_long_type>();
2677 }
2678 template <class T, expression_template_option ExpressionTemplates>
2679 inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const number<T, ExpressionTemplates>& v)
2680 {
2681    return llround(v, boost::math::policies::policy<>());
2682 }
2683 #endif
2684 //
2685 // frexp does not return an expression template since we require the
2686 // integer argument to be evaluated even if the returned value is
2687 // not assigned to anything...
2688 //
2689 template <class T, expression_template_option ExpressionTemplates>
2690 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, short* pint)
2691 {
2692    using default_ops::eval_frexp;
2693    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2694    number<T, ExpressionTemplates>                                                    result;
2695    eval_frexp(result.backend(), v.backend(), pint);
2696    return result;
2697 }
2698 template <class tag, class A1, class A2, class A3, class A4>
2699 inline BOOST_MP_CXX14_CONSTEXPR 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
2700 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, short* pint)
2701 {
2702    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2703    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2704 }
2705 template <class T, expression_template_option ExpressionTemplates>
2706 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, int* pint)
2707 {
2708    using default_ops::eval_frexp;
2709    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2710    number<T, ExpressionTemplates>                                                    result;
2711    eval_frexp(result.backend(), v.backend(), pint);
2712    return result;
2713 }
2714 template <class tag, class A1, class A2, class A3, class A4>
2715 inline BOOST_MP_CXX14_CONSTEXPR 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
2716 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, int* pint)
2717 {
2718    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2719    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2720 }
2721 template <class T, expression_template_option ExpressionTemplates>
2722 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, long* pint)
2723 {
2724    using default_ops::eval_frexp;
2725    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2726    number<T, ExpressionTemplates>                                                    result;
2727    eval_frexp(result.backend(), v.backend(), pint);
2728    return result;
2729 }
2730 template <class tag, class A1, class A2, class A3, class A4>
2731 inline BOOST_MP_CXX14_CONSTEXPR 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
2732 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long* pint)
2733 {
2734    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2735    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2736 }
2737 template <class T, expression_template_option ExpressionTemplates>
2738 inline BOOST_MP_CXX14_CONSTEXPR 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)
2739 {
2740    using default_ops::eval_frexp;
2741    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2742    number<T, ExpressionTemplates>                                                    result;
2743    eval_frexp(result.backend(), v.backend(), pint);
2744    return result;
2745 }
2746 template <class tag, class A1, class A2, class A3, class A4>
2747 inline BOOST_MP_CXX14_CONSTEXPR 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
2748 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, boost::long_long_type* pint)
2749 {
2750    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
2751    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
2752 }
2753 //
2754 // modf does not return an expression template since we require the
2755 // second argument to be evaluated even if the returned value is
2756 // not assigned to anything...
2757 //
2758 template <class T, expression_template_option ExpressionTemplates>
2759 inline BOOST_MP_CXX14_CONSTEXPR 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)
2760 {
2761    using default_ops::eval_modf;
2762    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2763    number<T, ExpressionTemplates>                                                    result;
2764    eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : 0);
2765    return result;
2766 }
2767 template <class T, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2768 inline BOOST_MP_CXX14_CONSTEXPR 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)
2769 {
2770    using default_ops::eval_modf;
2771    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2772    number<T, ExpressionTemplates>                                                    result, arg(v);
2773    eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : 0);
2774    return result;
2775 }
2776
2777 //
2778 // Integer square root:
2779 //
2780 template <class B, expression_template_option ExpressionTemplates>
2781 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
2782 sqrt(const number<B, ExpressionTemplates>& x)
2783 {
2784    using default_ops::eval_integer_sqrt;
2785    number<B, ExpressionTemplates> s, r;
2786    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
2787    return s;
2788 }
2789 //
2790 // fma:
2791 //
2792
2793 namespace default_ops {
2794
2795 struct fma_func
2796 {
2797    template <class B, class T, class U, class V>
2798    BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, const V& c) const
2799    {
2800       eval_multiply_add(result, a, b, c);
2801    }
2802 };
2803
2804 } // namespace default_ops
2805
2806 template <class Backend, class U, class V>
2807 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2808     mpl::and_<
2809         mpl::bool_<number_category<number<Backend, et_on> >::value == number_kind_floating_point>,
2810         mpl::or_<
2811             is_number<U>,
2812             is_number_expression<U>,
2813             is_arithmetic<U> >,
2814         mpl::or_<
2815             is_number<V>,
2816             is_number_expression<V>,
2817             is_arithmetic<V> > >,
2818     detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V> >::type
2819 fma(const number<Backend, et_on>& a, const U& b, const V& c)
2820 {
2821    return detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V>(
2822        default_ops::fma_func(), a, b, c);
2823 }
2824
2825 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U, class V>
2826 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2827     mpl::and_<
2828         mpl::bool_<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point>,
2829         mpl::or_<
2830             is_number<U>,
2831             is_number_expression<U>,
2832             is_arithmetic<U> >,
2833         mpl::or_<
2834             is_number<V>,
2835             is_number_expression<V>,
2836             is_arithmetic<V> > >,
2837     detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V> >::type
2838 fma(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, const V& c)
2839 {
2840    return detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V>(
2841        default_ops::fma_func(), a, b, c);
2842 }
2843
2844 template <class Backend, class U, class V>
2845 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2846     mpl::and_<
2847         mpl::bool_<number_category<number<Backend, et_off> >::value == number_kind_floating_point>,
2848         mpl::or_<
2849             is_number<U>,
2850             is_number_expression<U>,
2851             is_arithmetic<U> >,
2852         mpl::or_<
2853             is_number<V>,
2854             is_number_expression<V>,
2855             is_arithmetic<V> > >,
2856     number<Backend, et_off> >::type
2857 fma(const number<Backend, et_off>& a, const U& b, const V& c)
2858 {
2859    using default_ops::eval_multiply_add;
2860    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
2861    number<Backend, et_off>                                                    result;
2862    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));
2863    return result;
2864 }
2865
2866 template <class U, class Backend, class V>
2867 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2868     mpl::and_<
2869         mpl::bool_<number_category<number<Backend, et_on> >::value == number_kind_floating_point>,
2870         is_arithmetic<U>,
2871         mpl::or_<
2872             is_number<V>,
2873             is_number_expression<V>,
2874             is_arithmetic<V> > >,
2875     detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V> >::type
2876 fma(const U& a, const number<Backend, et_on>& b, const V& c)
2877 {
2878    return detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V>(
2879        default_ops::fma_func(), a, b, c);
2880 }
2881
2882 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
2883 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2884     mpl::and_<
2885         mpl::bool_<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point>,
2886         is_arithmetic<U>,
2887         mpl::or_<
2888             is_number<V>,
2889             is_number_expression<V>,
2890             is_arithmetic<V> > >,
2891     detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V> >::type
2892 fma(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, const V& c)
2893 {
2894    return detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V>(
2895        default_ops::fma_func(), a, b, c);
2896 }
2897
2898 template <class U, class Backend, class V>
2899 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2900     mpl::and_<
2901         mpl::bool_<number_category<number<Backend, et_off> >::value == number_kind_floating_point>,
2902         is_arithmetic<U>,
2903         mpl::or_<
2904             is_number<V>,
2905             is_number_expression<V>,
2906             is_arithmetic<V> > >,
2907     number<Backend, et_off> >::type
2908 fma(const U& a, const number<Backend, et_off>& b, const V& c)
2909 {
2910    using default_ops::eval_multiply_add;
2911    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
2912    number<Backend, et_off>                                                    result;
2913    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));
2914    return result;
2915 }
2916
2917 template <class U, class V, class Backend>
2918 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2919     mpl::and_<
2920         mpl::bool_<number_category<number<Backend, et_on> >::value == number_kind_floating_point>,
2921         is_arithmetic<U>,
2922         is_arithmetic<V> >,
2923     detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> > >::type
2924 fma(const U& a, const V& b, const number<Backend, et_on>& c)
2925 {
2926    return detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> >(
2927        default_ops::fma_func(), a, b, c);
2928 }
2929
2930 template <class U, class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
2931 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2932     mpl::and_<
2933         mpl::bool_<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point>,
2934         is_arithmetic<U>,
2935         is_arithmetic<V> >,
2936     detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
2937 fma(const U& a, const V& b, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& c)
2938 {
2939    return detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(
2940        default_ops::fma_func(), a, b, c);
2941 }
2942
2943 template <class U, class V, class Backend>
2944 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
2945     mpl::and_<
2946         mpl::bool_<number_category<number<Backend, et_off> >::value == number_kind_floating_point>,
2947         is_arithmetic<U>,
2948         is_arithmetic<V> >,
2949     number<Backend, et_off> >::type
2950 fma(const U& a, const V& b, const number<Backend, et_off>& c)
2951 {
2952    using default_ops::eval_multiply_add;
2953    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
2954    number<Backend, et_off>                                                    result;
2955    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));
2956    return result;
2957 }
2958
2959 namespace default_ops {
2960
2961 struct remquo_func
2962 {
2963    template <class B, class T, class U>
2964    BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, int* pi) const
2965    {
2966       eval_remquo(result, a, b, pi);
2967    }
2968 };
2969
2970 } // namespace default_ops
2971
2972 template <class Backend, class U>
2973 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
2974     number_category<number<Backend, et_on> >::value == number_kind_floating_point,
2975     detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*> >::type
2976 remquo(const number<Backend, et_on>& a, const U& b, int* pi)
2977 {
2978    return detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*>(
2979        default_ops::remquo_func(), a, b, pi);
2980 }
2981
2982 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U>
2983 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
2984     number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point,
2985     detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*> >::type
2986 remquo(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, int* pi)
2987 {
2988    return detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*>(
2989        default_ops::remquo_func(), a, b, pi);
2990 }
2991
2992 template <class U, class Backend>
2993 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
2994     (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
2995     detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*> >::type
2996 remquo(const U& a, const number<Backend, et_on>& b, int* pi)
2997 {
2998    return detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*>(
2999        default_ops::remquo_func(), a, b, pi);
3000 }
3001
3002 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3003 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
3004     (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3005     detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*> >::type
3006 remquo(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, int* pi)
3007 {
3008    return detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*>(
3009        default_ops::remquo_func(), a, b, pi);
3010 }
3011
3012 template <class Backend, class U>
3013 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
3014     number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3015     number<Backend, et_off> >::type
3016 remquo(const number<Backend, et_off>& a, const U& b, int* pi)
3017 {
3018    using default_ops::eval_remquo;
3019    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3020    number<Backend, et_off>                                                    result;
3021    eval_remquo(result.backend(), a.backend(), number<Backend, et_off>::canonical_value(b), pi);
3022    return result;
3023 }
3024 template <class U, class Backend>
3025 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
3026     (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3027     number<Backend, et_off> >::type
3028 remquo(const U& a, const number<Backend, et_off>& b, int* pi)
3029 {
3030    using default_ops::eval_remquo;
3031    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3032    number<Backend, et_off>                                                    result;
3033    eval_remquo(result.backend(), number<Backend, et_off>::canonical_value(a), b.backend(), pi);
3034    return result;
3035 }
3036
3037 template <class B, expression_template_option ExpressionTemplates>
3038 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3039 sqrt(const number<B, ExpressionTemplates>& x, number<B, ExpressionTemplates>& r)
3040 {
3041    using default_ops::eval_integer_sqrt;
3042    detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(x, r);
3043    number<B, ExpressionTemplates>                                                    s;
3044    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3045    return s;
3046 }
3047
3048 // clang-format off
3049 #define UNARY_OP_FUNCTOR(func, category)                                                                                                                                                                  \
3050    namespace detail {                                                                                                                                                                                     \
3051    template <class Backend>                                                                                                                                                                               \
3052    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                                                                                                                                                  \
3053    {                                                                                                                                                                                                      \
3054       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const                                                                                                                                          \
3055       {                                                                                                                                                                                                   \
3056          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                      \
3057          BOOST_JOIN(eval_, func)                                                                                                                                                                          \
3058          (result, arg);                                                                                                                                                                                   \
3059       }                                                                                                                                                                                                   \
3060       template <class U>                                                                                                                                                                                  \
3061       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg) const                                                                                                                                                \
3062       {                                                                                                                                                                                                   \
3063          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                      \
3064          Backend temp;                                                                                                                                                                                    \
3065          BOOST_JOIN(eval_, func)                                                                                                                                                                          \
3066          (temp, arg);                                                                                                                                                                                     \
3067          result = temp;                                                                                                                                                                                   \
3068       }                                                                                                                                                                                                   \
3069    };                                                                                                                                                                                                     \
3070    }                                                                                                                                                                                                      \
3071                                                                                                                                                                                                           \
3072    template <class tag, class A1, class A2, class A3, class A4>                                                                                                                                           \
3073        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category,                                                                                          \
3074                                    detail::expression<                                                                                                                                                    \
3075                                        detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,         \
3076                                    detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                                      \
3077                                                                               func(const detail::expression<tag, A1, A2, A3, A4>& arg)                                                                    \
3078    {                                                                                                                                                                                                      \
3079       return detail::expression<                                                                                                                                                                          \
3080                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                               \
3081              detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg); \
3082    }                                                                                                                                                                                                      \
3083    template <class Backend>                                                                                                                                                                               \
3084        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == category,                                                                                                                           \
3085                                    detail::expression<                                                                                                                                                    \
3086                                        detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                               \
3087                                    number<Backend, et_on> > > ::type                                                                                                                                       \
3088                                                              func(const number<Backend, et_on>& arg)                                                                                                      \
3089    {                                                                                                                                                                                                      \
3090       return detail::expression<                                                                                                                                                                          \
3091                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                     \
3092              number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg);                                                                                        \
3093    }                                                                                                                                                                                                      \
3094    template <class Backend>                                                                                                                                                                               \
3095    inline BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<                                                                                                                                                                    \
3096        boost::multiprecision::number_category<Backend>::value == category,                                                                                                                                \
3097        number<Backend, et_off> >::type                                                                                                                                                                    \
3098    func(const number<Backend, et_off>& arg)                                                                                                                                                               \
3099    {                                                                                                                                                                                                      \
3100       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                    \
3101       number<Backend, et_off>                                                    result;                                                                                                                  \
3102       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                         \
3103       BOOST_JOIN(eval_, func)                                                                                                                                                                             \
3104       (result.backend(), arg.backend());                                                                                                                                                                  \
3105       return result;                                                                                                                                                                       \
3106    }
3107
3108 #define BINARY_OP_FUNCTOR(func, category)                                                                                                                                                                                                                  \
3109    namespace detail {                                                                                                                                                                                                                                      \
3110    template <class Backend>                                                                                                                                                                                                                                \
3111    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                                                                                                                                                                                                   \
3112    {                                                                                                                                                                                                                                                       \
3113       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Backend& a) const                                                                                                                                                                         \
3114       {                                                                                                                                                                                                                                                    \
3115          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3116          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3117          (result, arg, a);                                                                                                                                                                                                                                 \
3118       }                                                                                                                                                                                                                                                    \
3119       template <class Arithmetic>                                                                                                                                                                                                                          \
3120       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Arithmetic& a) const                                                                                                                                                                      \
3121       {                                                                                                                                                                                                                                                    \
3122          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3123          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3124          (result, arg, number<Backend>::canonical_value(a));                                                                                                                                                                                               \
3125       }                                                                                                                                                                                                                                                    \
3126       template <class Arithmetic>                                                                                                                                                                                                                          \
3127       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Arithmetic& arg, const Backend& a) const                                                                                                                                                                      \
3128       {                                                                                                                                                                                                                                                    \
3129          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3130          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3131          (result, number<Backend>::canonical_value(arg), a);                                                                                                                                                                                               \
3132       }                                                                                                                                                                                                                                                    \
3133       template <class U>                                                                                                                                                                                                                                   \
3134       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Backend& a) const                                                                                                                                                                               \
3135       {                                                                                                                                                                                                                                                    \
3136          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3137          Backend r;                                                                                                                                                                                                                                        \
3138          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3139          (r, arg, a);                                                                                                                                                                                                                                      \
3140          result = r;                                                                                                                                                                                                                                       \
3141       }                                                                                                                                                                                                                                                    \
3142       template <class U, class Arithmetic>                                                                                                                                                                                                                 \
3143       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Arithmetic& a) const                                                                                                                                                                            \
3144       {                                                                                                                                                                                                                                                    \
3145          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3146          Backend r;                                                                                                                                                                                                                                        \
3147          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3148          (r, arg, number<Backend>::canonical_value(a));                                                                                                                                                                                                    \
3149          result = r;                                                                                                                                                                                                                                       \
3150       }                                                                                                                                                                                                                                                    \
3151       template <class U, class Arithmetic>                                                                                                                                                                                                                 \
3152       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Arithmetic& arg, const Backend& a) const                                                                                                                                                                            \
3153       {                                                                                                                                                                                                                                                    \
3154          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3155          Backend r;                                                                                                                                                                                                                                        \
3156          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3157          (r, number<Backend>::canonical_value(arg), a);                                                                                                                                                                                                    \
3158          result = r;                                                                                                                                                                                                                                       \
3159       }                                                                                                                                                                                                                                                    \
3160    };                                                                                                                                                                                                                                                      \
3161    }                                                                                                                                                                                                                                                       \
3162    template <class Backend>                                                                                                                                                                                                                                \
3163        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == category,                                                                                                                                                                            \
3164                                    detail::expression<                                                                                                                                                                                                     \
3165                                        detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                \
3166                                    number<Backend, et_on>, number<Backend, et_on> > > ::type                                                                                                                                                                \
3167                                                                                      func(const number<Backend, et_on>& arg, const number<Backend, et_on>& a)                                                                                              \
3168    {                                                                                                                                                                                                                                                       \
3169       return detail::expression<                                                                                                                                                                                                                           \
3170                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3171              number<Backend, et_on>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                                              \
3172    }                                                                                                                                                                                                                                                       \
3173    template <class Backend, class tag, class A1, class A2, class A3, class A4>                                                                                                                                                                             \
3174        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                        \
3175            (number_category<Backend>::value == category) && (boost::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),                                                                        \
3176            detail::expression<                                                                                                                                                                                                                             \
3177                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3178            number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                                                                                       \
3179                                                                               func(const number<Backend, et_on>& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                    \
3180    {                                                                                                                                                                                                                                                       \
3181       return detail::expression<                                                                                                                                                                                                                           \
3182                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3183              number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                             \
3184    }                                                                                                                                                                                                                                                       \
3185    template <class tag, class A1, class A2, class A3, class A4, class Backend>                                                                                                                                                                             \
3186        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                        \
3187            (number_category<Backend>::value == category) && (boost::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),                                                                        \
3188            detail::expression<                                                                                                                                                                                                                             \
3189                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3190            detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > > ::type                                                                                                                                                                       \
3191                                                                               func(const detail::expression<tag, A1, A2, A3, A4>& arg, const number<Backend, et_on>& a)                                                                                    \
3192    {                                                                                                                                                                                                                                                       \
3193       return detail::expression<                                                                                                                                                                                                                           \
3194                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3195              detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                             \
3196    }                                                                                                                                                                                                                                                       \
3197    template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>                                                                                                                                    \
3198        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                        \
3199            (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category) && (number_category<detail::expression<tagb, A1b, A2b, A3b, A4b> >::value == category),                                                                          \
3200            detail::expression<                                                                                                                                                                                                                             \
3201                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3202            detail::expression<tag, A1, A2, A3, A4>, detail::expression<tagb, A1b, A2b, A3b, A4b> > > ::type                                                                                                                                                 \
3203                                                                                                     func(const detail::expression<tag, A1, A2, A3, A4>& arg, const detail::expression<tagb, A1b, A2b, A3b, A4b>& a)                                        \
3204    {                                                                                                                                                                                                                                                       \
3205       return detail::expression<                                                                                                                                                                                                                           \
3206                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3207              detail::expression<tag, A1, A2, A3, A4>, detail::expression<tagb, A1b, A2b, A3b, A4b> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg, a); \
3208    }                                                                                                                                                                                                                                                       \
3209    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3210        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                        \
3211            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3212            detail::expression<                                                                                                                                                                                                                             \
3213                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3214            number<Backend, et_on>, Arithmetic> > ::type                                                                                                                                                                                                     \
3215                                                 func(const number<Backend, et_on>& arg, const Arithmetic& a)                                                                                                                                               \
3216    {                                                                                                                                                                                                                                                       \
3217       return detail::expression<                                                                                                                                                                                                                           \
3218                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3219              number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                                                         \
3220    }                                                                                                                                                                                                                                                       \
3221    template <class tag, class A1, class A2, class A3, class A4, class Arithmetic>                                                                                                                                                                          \
3222        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                        \
3223            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),                                              \
3224            detail::expression<                                                                                                                                                                                                                             \
3225                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3226            detail::expression<tag, A1, A2, A3, A4>, Arithmetic> > ::type                                                                                                                                                                                    \
3227                                                                  func(const detail::expression<tag, A1, A2, A3, A4>& arg, const Arithmetic& a)                                                                                                             \
3228    {                                                                                                                                                                                                                                                       \
3229       return detail::expression<                                                                                                                                                                                                                           \
3230                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3231              detail::expression<tag, A1, A2, A3, A4>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg, a);                                  \
3232    }                                                                                                                                                                                                                                                       \
3233    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3234        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                        \
3235            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3236            detail::expression<                                                                                                                                                                                                                             \
3237                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3238            Arithmetic, number<Backend, et_on> > > ::type                                                                                                                                                                                                    \
3239                                                  func(const Arithmetic& arg, const number<Backend, et_on>& a)                                                                                                                                              \
3240    {                                                                                                                                                                                                                                                       \
3241       return detail::expression<                                                                                                                                                                                                                           \
3242                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3243              Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                                                          \
3244    }                                                                                                                                                                                                                                                       \
3245    template <class tag, class A1, class A2, class A3, class A4, class Arithmetic>                                                                                                                                                                          \
3246        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                        \
3247            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),                                              \
3248            detail::expression<                                                                                                                                                                                                                             \
3249                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3250            Arithmetic, detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                                                                                                   \
3251                                                                   func(const Arithmetic& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                                            \
3252    {                                                                                                                                                                                                                                                       \
3253       return detail::expression<                                                                                                                                                                                                                           \
3254                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3255              Arithmetic, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg, a);                                   \
3256    }                                                                                                                                                                                                                                                       \
3257    template <class Backend>                                                                                                                                                                                                                                \
3258    inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<(number_category<Backend>::value == category),                                                                                                                                                                              \
3259                                number<Backend, et_off> >::type                                                                                                                                                                                             \
3260    func(const number<Backend, et_off>& arg, const number<Backend, et_off>& a)                                                                                                                                                                              \
3261    {                                                                                                                                                                                                                                                       \
3262       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);                                                                                                                                                  \
3263       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3264       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3265       BOOST_JOIN(eval_, func)                                                                                                                                                                                                                              \
3266       (result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3267       return result;                                                                                                                                                                                                                        \
3268    }                                                                                                                                                                                                                                                       \
3269    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3270    inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                            \
3271        is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),                                                                                                                        \
3272        number<Backend, et_off> >::type                                                                                                                                                                                                                     \
3273    func(const number<Backend, et_off>& arg, const Arithmetic& a)                                                                                                                                                                                           \
3274    {                                                                                                                                                                                                                                                       \
3275       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                                                                     \
3276       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3277       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3278       BOOST_JOIN(eval_, func)                                                                                                                                                                                                                              \
3279       (result.backend(), arg.backend(), number<Backend, et_off>::canonical_value(a));                                                                                                                                                                      \
3280       return result;                                                                                                                                                                                                                        \
3281    }                                                                                                                                                                                                                                                       \
3282    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3283    inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                                                            \
3284        is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),                                                                                                                        \
3285        number<Backend, et_off> >::type                                                                                                                                                                                                                     \
3286    func(const Arithmetic& a, const number<Backend, et_off>& arg)                                                                                                                                                                                           \
3287    {                                                                                                                                                                                                                                                       \
3288       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                                                                     \
3289       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3290       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3291       BOOST_JOIN(eval_, func)                                                                                                                                                                                                                              \
3292       (result.backend(), number<Backend, et_off>::canonical_value(a), arg.backend());                                                                                                                                                                      \
3293       return result;                                                                                                                                                                                                                        \
3294    }
3295
3296 #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)                                                                                                                                                            \
3297    template <class tag, class A1, class A2, class A3, class A4>                                                                                                                                                     \
3298        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                 \
3299            (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),                                                                                                                          \
3300            detail::expression<                                                                                                                                                                                      \
3301                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                           \
3302            detail::expression<tag, A1, A2, A3, A4>, Arg2> > ::type                                                                                                                                                   \
3303                                                            func(const detail::expression<tag, A1, A2, A3, A4>& arg, Arg2 const& a)                                                                                  \
3304    {                                                                                                                                                                                                                \
3305       return detail::expression<                                                                                                                                                                                    \
3306                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                         \
3307              detail::expression<tag, A1, A2, A3, A4>, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg, a); \
3308    }                                                                                                                                                                                                                \
3309    template <class Backend>                                                                                                                                                                                         \
3310        inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                 \
3311            (number_category<Backend>::value == category),                                                                                                                                                           \
3312            detail::expression<                                                                                                                                                                                      \
3313                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                 \
3314            number<Backend, et_on>, Arg2> > ::type                                                                                                                                                                    \
3315                                           func(const number<Backend, et_on>& arg, Arg2 const& a)                                                                                                                    \
3316    {                                                                                                                                                                                                                \
3317       return detail::expression<                                                                                                                                                                                    \
3318                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                               \
3319              number<Backend, et_on>, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                        \
3320    }                                                                                                                                                                                                                \
3321    template <class Backend>                                                                                                                                                                                         \
3322    inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<                                                                                                                                                                                     \
3323        (number_category<Backend>::value == category),                                                                                                                                                               \
3324        number<Backend, et_off> >::type                                                                                                                                                                              \
3325    func(const number<Backend, et_off>& arg, Arg2 const& a)                                                                                                                                                          \
3326    {                                                                                                                                                                                                                \
3327       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);                                                                                                           \
3328       number<Backend, et_off>                                                    result;                                                                                                                            \
3329       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                   \
3330       BOOST_JOIN(eval_, func)                                                                                                                                                                                       \
3331       (result.backend(), arg.backend(), a);                                                                                                                                                                         \
3332       return result;                                                                                                                                                                                 \
3333    }
3334
3335 #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)                  \
3336    namespace detail {                                                   \
3337    template <class Backend>                                             \
3338    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                \
3339    {                                                                    \
3340       template <class Arg>                                              \
3341       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, Backend const& arg, Arg a) const \
3342       {                                                                 \
3343          using default_ops::BOOST_JOIN(eval_, func);                    \
3344          BOOST_JOIN(eval_, func)                                        \
3345          (result, arg, a);                                              \
3346       }                                                                 \
3347    };                                                                   \
3348    }                                                                    \
3349                                                                         \
3350    HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)
3351
3352 // clang-format on
3353
3354 namespace detail {
3355 template <class Backend>
3356 struct abs_funct
3357 {
3358    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3359    {
3360       using default_ops::eval_abs;
3361       eval_abs(result, arg);
3362    }
3363 };
3364 template <class Backend>
3365 struct conj_funct
3366 {
3367    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3368    {
3369       using default_ops::eval_conj;
3370       eval_conj(result, arg);
3371    }
3372 };
3373 template <class Backend>
3374 struct proj_funct
3375 {
3376    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3377    {
3378       using default_ops::eval_proj;
3379       eval_proj(result, arg);
3380    }
3381 };
3382
3383 } // namespace detail
3384
3385 template <class tag, class A1, class A2, class A3, class A4>
3386 inline BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_complex,
3387                                     detail::expression<
3388                                         detail::function, detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> > >::type
3389 abs(const detail::expression<tag, A1, A2, A3, A4>& arg)
3390 {
3391    return detail::expression<
3392        detail::function, detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3393        detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3394 }
3395 template <class Backend>
3396 inline BOOST_MP_CXX14_CONSTEXPR typename disable_if_c<number_category<Backend>::value == number_kind_complex,
3397                              detail::expression<
3398                                  detail::function, detail::abs_funct<Backend>, number<Backend, et_on> > >::type
3399 abs(const number<Backend, et_on>& arg)
3400 {
3401    return detail::expression<
3402        detail::function, detail::abs_funct<Backend>, number<Backend, et_on> >(
3403        detail::abs_funct<Backend>(), arg);
3404 }
3405 template <class Backend>
3406 inline BOOST_MP_CXX14_CONSTEXPR typename disable_if_c<number_category<Backend>::value == number_kind_complex, number<Backend, et_off> >::type
3407 abs(const number<Backend, et_off>& arg)
3408 {
3409    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3410    number<Backend, et_off>                                                    result;
3411    using default_ops::eval_abs;
3412    eval_abs(result.backend(), arg.backend());
3413    return result;
3414 }
3415
3416 template <class tag, class A1, class A2, class A3, class A4>
3417 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3418     detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3419 conj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3420 {
3421    return detail::expression<
3422        detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3423        detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3424 }
3425 template <class Backend>
3426 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3427     detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >
3428 conj(const number<Backend, et_on>& arg)
3429 {
3430    return detail::expression<
3431        detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >(
3432        detail::conj_funct<Backend>(), arg);
3433 }
3434 template <class Backend>
3435 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3436 conj(const number<Backend, et_off>& arg)
3437 {
3438    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3439    number<Backend, et_off>                                                    result;
3440    using default_ops::eval_conj;
3441    eval_conj(result.backend(), arg.backend());
3442    return result;
3443 }
3444
3445 template <class tag, class A1, class A2, class A3, class A4>
3446 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3447     detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3448 proj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3449 {
3450    return detail::expression<
3451        detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3452        detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3453 }
3454 template <class Backend>
3455 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3456     detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >
3457 proj(const number<Backend, et_on>& arg)
3458 {
3459    return detail::expression<
3460        detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >(
3461        detail::proj_funct<Backend>(), arg);
3462 }
3463 template <class Backend>
3464 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3465 proj(const number<Backend, et_off>& arg)
3466 {
3467    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3468    number<Backend, et_off>                                                    result;
3469    using default_ops::eval_proj;
3470    eval_proj(result.backend(), arg.backend());
3471    return result;
3472 }
3473
3474 UNARY_OP_FUNCTOR(fabs, number_kind_floating_point)
3475 UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point)
3476 UNARY_OP_FUNCTOR(floor, number_kind_floating_point)
3477 UNARY_OP_FUNCTOR(ceil, number_kind_floating_point)
3478 UNARY_OP_FUNCTOR(trunc, number_kind_floating_point)
3479 UNARY_OP_FUNCTOR(round, number_kind_floating_point)
3480 UNARY_OP_FUNCTOR(exp, number_kind_floating_point)
3481 UNARY_OP_FUNCTOR(exp2, number_kind_floating_point)
3482 UNARY_OP_FUNCTOR(log, number_kind_floating_point)
3483 UNARY_OP_FUNCTOR(log10, number_kind_floating_point)
3484 UNARY_OP_FUNCTOR(cos, number_kind_floating_point)
3485 UNARY_OP_FUNCTOR(sin, number_kind_floating_point)
3486 UNARY_OP_FUNCTOR(tan, number_kind_floating_point)
3487 UNARY_OP_FUNCTOR(asin, number_kind_floating_point)
3488 UNARY_OP_FUNCTOR(acos, number_kind_floating_point)
3489 UNARY_OP_FUNCTOR(atan, number_kind_floating_point)
3490 UNARY_OP_FUNCTOR(cosh, number_kind_floating_point)
3491 UNARY_OP_FUNCTOR(sinh, number_kind_floating_point)
3492 UNARY_OP_FUNCTOR(tanh, number_kind_floating_point)
3493 UNARY_OP_FUNCTOR(log2, number_kind_floating_point)
3494 UNARY_OP_FUNCTOR(nearbyint, number_kind_floating_point)
3495 UNARY_OP_FUNCTOR(rint, number_kind_floating_point)
3496
3497 HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point)
3498 //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point)
3499 HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point)
3500 //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point)
3501 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point)
3502 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point)
3503 HETERO_BINARY_OP_FUNCTOR_B(ldexp, boost::long_long_type, number_kind_floating_point)
3504 //HETERO_BINARY_OP_FUNCTOR_B(frexp, boost::long_long_type*, number_kind_floating_point)
3505 BINARY_OP_FUNCTOR(pow, number_kind_floating_point)
3506 BINARY_OP_FUNCTOR(fmod, number_kind_floating_point)
3507 BINARY_OP_FUNCTOR(fmax, number_kind_floating_point)
3508 BINARY_OP_FUNCTOR(fmin, number_kind_floating_point)
3509 BINARY_OP_FUNCTOR(atan2, number_kind_floating_point)
3510 BINARY_OP_FUNCTOR(fdim, number_kind_floating_point)
3511 BINARY_OP_FUNCTOR(hypot, number_kind_floating_point)
3512 BINARY_OP_FUNCTOR(remainder, number_kind_floating_point)
3513
3514 UNARY_OP_FUNCTOR(logb, number_kind_floating_point)
3515 HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point)
3516 HETERO_BINARY_OP_FUNCTOR(scalbln, short, number_kind_floating_point)
3517 HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point)
3518 HETERO_BINARY_OP_FUNCTOR_B(scalbln, int, number_kind_floating_point)
3519 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point)
3520 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long, number_kind_floating_point)
3521 HETERO_BINARY_OP_FUNCTOR_B(scalbn, boost::long_long_type, number_kind_floating_point)
3522 HETERO_BINARY_OP_FUNCTOR_B(scalbln, boost::long_long_type, number_kind_floating_point)
3523
3524 //
3525 // Complex functions:
3526 //
3527 UNARY_OP_FUNCTOR(exp, number_kind_complex)
3528 UNARY_OP_FUNCTOR(log, number_kind_complex)
3529 UNARY_OP_FUNCTOR(log10, number_kind_complex)
3530 BINARY_OP_FUNCTOR(pow, number_kind_complex)
3531 UNARY_OP_FUNCTOR(sqrt, number_kind_complex)
3532 UNARY_OP_FUNCTOR(sin, number_kind_complex)
3533 UNARY_OP_FUNCTOR(cos, number_kind_complex)
3534 UNARY_OP_FUNCTOR(tan, number_kind_complex)
3535 UNARY_OP_FUNCTOR(asin, number_kind_complex)
3536 UNARY_OP_FUNCTOR(acos, number_kind_complex)
3537 UNARY_OP_FUNCTOR(atan, number_kind_complex)
3538 UNARY_OP_FUNCTOR(sinh, number_kind_complex)
3539 UNARY_OP_FUNCTOR(cosh, number_kind_complex)
3540 UNARY_OP_FUNCTOR(tanh, number_kind_complex)
3541 UNARY_OP_FUNCTOR(asinh, number_kind_complex)
3542 UNARY_OP_FUNCTOR(acosh, number_kind_complex)
3543 UNARY_OP_FUNCTOR(atanh, number_kind_complex)
3544
3545 //
3546 // Integer functions:
3547 //
3548 BINARY_OP_FUNCTOR(gcd, number_kind_integer)
3549 BINARY_OP_FUNCTOR(lcm, number_kind_integer)
3550 HETERO_BINARY_OP_FUNCTOR(pow, unsigned, number_kind_integer)
3551
3552 #undef BINARY_OP_FUNCTOR
3553 #undef UNARY_OP_FUNCTOR
3554
3555 //
3556 // ilogb:
3557 //
3558 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3559 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_floating_point, typename Backend::exponent_type>::type
3560 ilogb(const multiprecision::number<Backend, ExpressionTemplates>& val)
3561 {
3562    using default_ops::eval_ilogb;
3563    return eval_ilogb(val.backend());
3564 }
3565
3566 template <class tag, class A1, class A2, class A3, class A4>
3567 inline BOOST_MP_CXX14_CONSTEXPR 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
3568 ilogb(const detail::expression<tag, A1, A2, A3, A4>& val)
3569 {
3570    using default_ops::eval_ilogb;
3571    typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type arg(val);
3572    return eval_ilogb(arg.backend());
3573 }
3574
3575 } //namespace multiprecision
3576
3577 namespace math {
3578 //
3579 // Overload of Boost.Math functions that find the wrong overload when used with number:
3580 //
3581 namespace detail {
3582 template <class T>
3583 T sinc_pi_imp(T);
3584 template <class T>
3585 T sinhc_pi_imp(T);
3586 } // namespace detail
3587 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3588 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3589 {
3590    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3591    return BOOST_MP_MOVE(detail::sinc_pi_imp(x));
3592 }
3593
3594 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
3595 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3596 {
3597    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3598    return BOOST_MP_MOVE(detail::sinc_pi_imp(x));
3599 }
3600
3601 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3602 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3603 {
3604    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3605    return BOOST_MP_MOVE(detail::sinhc_pi_imp(x));
3606 }
3607
3608 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
3609 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3610 {
3611    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3612    return BOOST_MP_MOVE(boost::math::sinhc_pi(x));
3613 }
3614
3615 using boost::multiprecision::gcd;
3616 using boost::multiprecision::lcm;
3617
3618 #ifdef BOOST_MSVC
3619 #pragma warning(pop)
3620 #endif
3621 } // namespace math
3622
3623 namespace integer {
3624
3625 using boost::multiprecision::gcd;
3626 using boost::multiprecision::lcm;
3627
3628 } // namespace integer
3629
3630 } // namespace boost
3631
3632 //
3633 // This has to come last of all:
3634 //
3635 #include <boost/multiprecision/detail/no_et_ops.hpp>
3636 #include <boost/multiprecision/detail/et_ops.hpp>
3637 //
3638 // min/max overloads:
3639 //
3640 #include <boost/multiprecision/detail/min_max.hpp>
3641
3642 #endif