Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:52:10

0001 ///////////////////////////////////////////////////////////////////////////////
0002 //  Copyright 2011-21 John Maddock.
0003 //  Copyright 2021 Iskandarov Lev. Distributed under the Boost
0004 //  Software License, Version 1.0. (See accompanying file
0005 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_MP_DEFAULT_OPS
0008 #define BOOST_MP_DEFAULT_OPS
0009 
0010 #include <boost/multiprecision/detail/standalone_config.hpp>
0011 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0012 #include <boost/multiprecision/detail/number_base.hpp>
0013 #include <boost/multiprecision/detail/assert.hpp>
0014 #include <boost/multiprecision/traits/is_backend.hpp>
0015 #include <boost/multiprecision/detail/fpclassify.hpp>
0016 #include <cstdint>
0017 #include <complex>
0018 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
0019 #include <string_view>
0020 #endif
0021 
0022 #ifdef BOOST_MP_MATH_AVAILABLE
0023 #include <boost/math/special_functions/fpclassify.hpp>
0024 #include <boost/math/special_functions/next.hpp>
0025 #include <boost/math/special_functions/hypot.hpp>
0026 #include <boost/math/policies/error_handling.hpp>
0027 #endif
0028 
0029 #ifndef INSTRUMENT_BACKEND
0030 #ifndef BOOST_MP_INSTRUMENT
0031 #define INSTRUMENT_BACKEND(x)
0032 #else
0033 #define INSTRUMENT_BACKEND(x) \
0034    std::cout << BOOST_STRINGIZE(x) << " = " << x.str(0, std::ios_base::scientific) << std::endl;
0035 #endif
0036 #endif
0037 
0038 namespace boost {
0039 namespace multiprecision {
0040 
0041 namespace detail {
0042 
0043 template <class To, class From>
0044 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_floating_point>& /*to_type*/, const std::integral_constant<int, number_kind_integer>& /*from_type*/);
0045 template <class To, class From>
0046 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_integer>& /*to_type*/, const std::integral_constant<int, number_kind_integer>& /*from_type*/);
0047 template <class To, class From>
0048 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_floating_point>& /*to_type*/, const std::integral_constant<int, number_kind_floating_point>& /*from_type*/);
0049 template <class To, class From>
0050 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_rational>& /*to_type*/, const std::integral_constant<int, number_kind_rational>& /*from_type*/);
0051 template <class To, class From>
0052 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_rational>& /*to_type*/, const std::integral_constant<int, number_kind_integer>& /*from_type*/);
0053 
0054 template <class Integer>
0055 BOOST_MP_CXX14_CONSTEXPR Integer karatsuba_sqrt(const Integer& x, Integer& r, size_t bits);
0056 
0057 } // namespace detail
0058 
0059 namespace default_ops {
0060 
0061 template <class T>
0062 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val);
0063 
0064 template <class T>
0065 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val) { return val < 0; }
0066 
0067 inline int eval_signbit(float val) { return (std::signbit)(val); }
0068 inline int eval_signbit(double val) { return (std::signbit)(val); }
0069 inline int eval_signbit(long double val) { return (std::signbit)(val); }
0070 #ifdef BOOST_HAS_FLOAT128
0071 extern "C" int signbitq(float128_type) throw();
0072 inline int            eval_signbit(float128_type val) { return signbitq(val); }
0073 #endif
0074 
0075 template <class T>
0076 BOOST_MP_CXX14_CONSTEXPR bool eval_is_zero(const T& val);
0077 
0078 #ifdef BOOST_MSVC
0079 // warning C4127: conditional expression is constant
0080 // warning C4146: unary minus operator applied to unsigned type, result still unsigned
0081 #pragma warning(push)
0082 #pragma warning(disable : 4127 4146)
0083 #endif
0084 //
0085 // Default versions of mixed arithmetic, these just construct a temporary
0086 // from the arithmetic value and then do the arithmetic on that, two versions
0087 // of each depending on whether the backend can be directly constructed from type V.
0088 //
0089 // Note that we have to provide *all* the template parameters to class number when used in
0090 // enable_if as MSVC-10 won't compile the code if we rely on a computed-default parameter.
0091 // Since the result of the test doesn't depend on whether expression templates are on or off
0092 // we just use et_on everywhere.  We could use a BOOST_WORKAROUND but that just obfuscates the
0093 // code even more....
0094 //
0095 template <class T, class V>
0096 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
0097 eval_add(T& result, V const& v)
0098 {
0099    T t;
0100    t = v;
0101    eval_add(result, t);
0102 }
0103 template <class T, class V>
0104 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
0105 eval_add(T& result, V const& v)
0106 {
0107    T t(v);
0108    eval_add(result, t);
0109 }
0110 template <class T, class V>
0111 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
0112 eval_subtract(T& result, V const& v)
0113 {
0114    T t;
0115    t = v;
0116    eval_subtract(result, t);
0117 }
0118 template <class T, class V>
0119 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
0120 eval_subtract(T& result, V const& v)
0121 {
0122    T t(v);
0123    eval_subtract(result, t);
0124 }
0125 template <class T, class V>
0126 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
0127 eval_multiply(T& result, V const& v)
0128 {
0129    T t;
0130    t = v;
0131    eval_multiply(result, t);
0132 }
0133 template <class T, class V>
0134 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
0135 eval_multiply(T& result, V const& v)
0136 {
0137    T t(v);
0138    eval_multiply(result, t);
0139 }
0140 
0141 template <class T, class U, class V>
0142 BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v);
0143 
0144 template <class T, class U, class V>
0145 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_add(T& t, const U& u, const V& v)
0146 {
0147    T z;
0148    eval_multiply(z, u, v);
0149    eval_add(t, z);
0150 }
0151 template <class T, class U, class V>
0152 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v)
0153 {
0154    eval_multiply_add(t, v, u);
0155 }
0156 template <class T, class U, class V>
0157 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_subtract(T& t, const U& u, const V& v)
0158 {
0159    T z;
0160    eval_multiply(z, u, v);
0161    eval_subtract(t, z);
0162 }
0163 template <class T, class U, class V>
0164 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v)
0165 {
0166    eval_multiply_subtract(t, v, u);
0167 }
0168 template <class T, class V>
0169 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
0170 eval_divide(T& result, V const& v)
0171 {
0172    T t;
0173    t = v;
0174    eval_divide(result, t);
0175 }
0176 template <class T, class V>
0177 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
0178 eval_divide(T& result, V const& v)
0179 {
0180    T t(v);
0181    eval_divide(result, t);
0182 }
0183 template <class T, class V>
0184 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
0185 eval_modulus(T& result, V const& v)
0186 {
0187    T t;
0188    t = v;
0189    eval_modulus(result, t);
0190 }
0191 template <class T, class V>
0192 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
0193 eval_modulus(T& result, V const& v)
0194 {
0195    T t(v);
0196    eval_modulus(result, t);
0197 }
0198 template <class T, class V>
0199 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
0200 eval_bitwise_and(T& result, V const& v)
0201 {
0202    T t;
0203    t = v;
0204    eval_bitwise_and(result, t);
0205 }
0206 template <class T, class V>
0207 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
0208 eval_bitwise_and(T& result, V const& v)
0209 {
0210    T t(v);
0211    eval_bitwise_and(result, t);
0212 }
0213 template <class T, class V>
0214 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
0215 eval_bitwise_or(T& result, V const& v)
0216 {
0217    T t;
0218    t = v;
0219    eval_bitwise_or(result, t);
0220 }
0221 template <class T, class V>
0222 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
0223 eval_bitwise_or(T& result, V const& v)
0224 {
0225    T t(v);
0226    eval_bitwise_or(result, t);
0227 }
0228 template <class T, class V>
0229 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
0230 eval_bitwise_xor(T& result, V const& v)
0231 {
0232    T t;
0233    t = v;
0234    eval_bitwise_xor(result, t);
0235 }
0236 template <class T, class V>
0237 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
0238 eval_bitwise_xor(T& result, V const& v)
0239 {
0240    T t(v);
0241    eval_bitwise_xor(result, t);
0242 }
0243 
0244 template <class T, class V>
0245 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
0246 eval_complement(T& result, V const& v)
0247 {
0248    T t;
0249    t = v;
0250    eval_complement(result, t);
0251 }
0252 template <class T, class V>
0253 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
0254 eval_complement(T& result, V const& v)
0255 {
0256    T t(v);
0257    eval_complement(result, t);
0258 }
0259 
0260 //
0261 // Default versions of 3-arg arithmetic functions, these mostly just forward to the 2 arg versions:
0262 //
0263 template <class T, class U, class V>
0264 BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v);
0265 
0266 template <class T>
0267 inline BOOST_MP_CXX14_CONSTEXPR void eval_add_default(T& t, const T& u, const T& v)
0268 {
0269    if (&t == &v)
0270    {
0271       eval_add(t, u);
0272    }
0273    else if (&t == &u)
0274    {
0275       eval_add(t, v);
0276    }
0277    else
0278    {
0279       t = u;
0280       eval_add(t, v);
0281    }
0282 }
0283 template <class T, class U>
0284 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_add_default(T& t, const T& u, const U& v)
0285 {
0286    T vv;
0287    vv = v;
0288    eval_add(t, u, vv);
0289 }
0290 template <class T, class U>
0291 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_add_default(T& t, const T& u, const U& v)
0292 {
0293    T vv(v);
0294    eval_add(t, u, vv);
0295 }
0296 template <class T, class U>
0297 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_add_default(T& t, const U& u, const T& v)
0298 {
0299    eval_add(t, v, u);
0300 }
0301 template <class T, class U, class V>
0302 inline BOOST_MP_CXX14_CONSTEXPR void eval_add_default(T& t, const U& u, const V& v)
0303 {
0304    BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
0305    {
0306       if ((void*)&t == (void*)&v)
0307       {
0308          eval_add(t, u);
0309       }
0310       else
0311       {
0312          t = u;
0313          eval_add(t, v);
0314       }
0315    }
0316    else
0317    {
0318       t = u;
0319       eval_add(t, v);
0320    }
0321 }
0322 template <class T, class U, class V>
0323 inline BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v)
0324 {
0325    eval_add_default(t, u, v);
0326 }
0327 
0328 template <class T, class U, class V>
0329 void BOOST_MP_CXX14_CONSTEXPR eval_subtract(T& t, const U& u, const V& v);
0330 
0331 template <class T>
0332 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract_default(T& t, const T& u, const T& v)
0333 {
0334    if ((&t == &v) && is_signed_number<T>::value)
0335    {
0336       eval_subtract(t, u);
0337       t.negate();
0338    }
0339    else if (&t == &u)
0340    {
0341       eval_subtract(t, v);
0342    }
0343    else
0344    {
0345       t = u;
0346       eval_subtract(t, v);
0347    }
0348 }
0349 template <class T, class U>
0350 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_subtract_default(T& t, const T& u, const U& v)
0351 {
0352    T vv;
0353    vv = v;
0354    eval_subtract(t, u, vv);
0355 }
0356 template <class T, class U>
0357 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_subtract_default(T& t, const T& u, const U& v)
0358 {
0359    T vv(v);
0360    eval_subtract(t, u, vv);
0361 }
0362 template <class T, class U>
0363 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && is_signed_number<T>::value && (number_category<T>::value != number_kind_complex)>::type eval_subtract_default(T& t, const U& u, const T& v)
0364 {
0365    eval_subtract(t, v, u);
0366    if(!eval_is_zero(t) || (eval_signbit(u) != eval_signbit(v)))
0367       t.negate();
0368 }
0369 template <class T, class U>
0370 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && is_signed_number<T>::value && (number_category<T>::value == number_kind_complex)>::type eval_subtract_default(T& t, const U& u, const T& v)
0371 {
0372    eval_subtract(t, v, u);
0373    t.negate();
0374 }
0375 template <class T, class U>
0376 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
0377 {
0378    T temp;
0379    temp = u;
0380    eval_subtract(t, temp, v);
0381 }
0382 template <class T, class U>
0383 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
0384 {
0385    T temp(u);
0386    eval_subtract(t, temp, v);
0387 }
0388 template <class T, class U, class V>
0389 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract_default(T& t, const U& u, const V& v)
0390 {
0391    BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
0392    {
0393       if ((void*)&t == (void*)&v)
0394       {
0395          eval_subtract(t, u);
0396          t.negate();
0397       }
0398       else
0399       {
0400          t = u;
0401          eval_subtract(t, v);
0402       }
0403    }
0404    else
0405    {
0406       t = u;
0407       eval_subtract(t, v);
0408    }
0409 }
0410 template <class T, class U, class V>
0411 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(T& t, const U& u, const V& v)
0412 {
0413    eval_subtract_default(t, u, v);
0414 }
0415 
0416 template <class T>
0417 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_default(T& t, const T& u, const T& v)
0418 {
0419    if (&t == &v)
0420    {
0421       eval_multiply(t, u);
0422    }
0423    else if (&t == &u)
0424    {
0425       eval_multiply(t, v);
0426    }
0427    else
0428    {
0429       t = u;
0430       eval_multiply(t, v);
0431    }
0432 }
0433 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
0434 template <class T, class U>
0435 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_multiply_default(T& t, const T& u, const U& v)
0436 {
0437    T vv;
0438    vv = v;
0439    eval_multiply(t, u, vv);
0440 }
0441 template <class T, class U>
0442 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_multiply_default(T& t, const T& u, const U& v)
0443 {
0444    T vv(v);
0445    eval_multiply(t, u, vv);
0446 }
0447 template <class T, class U>
0448 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_multiply_default(T& t, const U& u, const T& v)
0449 {
0450    eval_multiply(t, v, u);
0451 }
0452 #endif
0453 template <class T, class U, class V>
0454 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_default(T& t, const U& u, const V& v)
0455 {
0456    BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
0457    {
0458       if ((void*)&t == (void*)&v)
0459       {
0460          eval_multiply(t, u);
0461       }
0462       else
0463       {
0464          t = number<T>::canonical_value(u);
0465          eval_multiply(t, v);
0466       }
0467    }
0468    else
0469    {
0470       t = number<T>::canonical_value(u);
0471       eval_multiply(t, v);
0472    }
0473 }
0474 template <class T, class U, class V>
0475 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v)
0476 {
0477    eval_multiply_default(t, u, v);
0478 }
0479 
0480 template <class T>
0481 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_add(T& t, const T& u, const T& v, const T& x)
0482 {
0483    if ((void*)&x == (void*)&t)
0484    {
0485       T z;
0486       z = number<T>::canonical_value(x);
0487       eval_multiply_add(t, u, v, z);
0488    }
0489    else
0490    {
0491       eval_multiply(t, u, v);
0492       eval_add(t, x);
0493    }
0494 }
0495 
0496 template <class T, class U>
0497 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_same<T, U>::value, T>::type make_T(const U& u)
0498 {
0499    T t;
0500    t = number<T>::canonical_value(u);
0501    return t;
0502 }
0503 template <class T>
0504 inline BOOST_MP_CXX14_CONSTEXPR const T& make_T(const T& t)
0505 {
0506    return t;
0507 }
0508 
0509 template <class T, class U, class V, class X>
0510 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x)
0511 {
0512    eval_multiply_add(t, make_T<T>(u), make_T<T>(v), make_T<T>(x));
0513 }
0514 template <class T, class U, class V, class X>
0515 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x)
0516 {
0517    eval_multiply_add(t, v, u, x);
0518 }
0519 template <class T, class U, class V, class X>
0520 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x)
0521 {
0522    if ((void*)&x == (void*)&t)
0523    {
0524       T z;
0525       z = x;
0526       eval_multiply_subtract(t, u, v, z);
0527    }
0528    else
0529    {
0530       eval_multiply(t, u, v);
0531       eval_subtract(t, x);
0532    }
0533 }
0534 template <class T, class U, class V, class X>
0535 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x)
0536 {
0537    eval_multiply_subtract(t, v, u, x);
0538 }
0539 
0540 template <class T, class U, class V>
0541 BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v);
0542 
0543 template <class T>
0544 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide_default(T& t, const T& u, const T& v)
0545 {
0546    if (&t == &u)
0547       eval_divide(t, v);
0548    else if (&t == &v)
0549    {
0550       T temp;
0551       eval_divide(temp, u, v);
0552       temp.swap(t);
0553    }
0554    else
0555    {
0556       t = u;
0557       eval_divide(t, v);
0558    }
0559 }
0560 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
0561 template <class T, class U>
0562 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const T& u, const U& v)
0563 {
0564    T vv;
0565    vv = v;
0566    eval_divide(t, u, vv);
0567 }
0568 template <class T, class U>
0569 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const T& u, const U& v)
0570 {
0571    T vv(v);
0572    eval_divide(t, u, vv);
0573 }
0574 template <class T, class U>
0575 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const U& u, const T& v)
0576 {
0577    T uu;
0578    uu = u;
0579    eval_divide(t, uu, v);
0580 }
0581 template <class T, class U>
0582 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const U& u, const T& v)
0583 {
0584    T uu(u);
0585    eval_divide(t, uu, v);
0586 }
0587 #endif
0588 template <class T, class U, class V>
0589 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide_default(T& t, const U& u, const V& v)
0590 {
0591    BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
0592    {
0593       if ((void*)&t == (void*)&v)
0594       {
0595          T temp;
0596          temp = u;
0597          eval_divide(temp, v);
0598          t = temp;
0599       }
0600       else
0601       {
0602          t = u;
0603          eval_divide(t, v);
0604       }
0605    }
0606    else
0607    {
0608       t = u;
0609       eval_divide(t, v);
0610    }
0611 }
0612 template <class T, class U, class V>
0613 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v)
0614 {
0615    eval_divide_default(t, u, v);
0616 }
0617 
0618 template <class T, class U, class V>
0619 BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v);
0620 
0621 template <class T>
0622 inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus_default(T& t, const T& u, const T& v)
0623 {
0624    if (&t == &u)
0625       eval_modulus(t, v);
0626    else if (&t == &v)
0627    {
0628       T temp;
0629       eval_modulus(temp, u, v);
0630       temp.swap(t);
0631    }
0632    else
0633    {
0634       t = u;
0635       eval_modulus(t, v);
0636    }
0637 }
0638 template <class T, class U>
0639 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const T& u, const U& v)
0640 {
0641    T vv;
0642    vv = v;
0643    eval_modulus(t, u, vv);
0644 }
0645 template <class T, class U>
0646 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const T& u, const U& v)
0647 {
0648    T vv(v);
0649    eval_modulus(t, u, vv);
0650 }
0651 template <class T, class U>
0652 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const U& u, const T& v)
0653 {
0654    T uu;
0655    uu = u;
0656    eval_modulus(t, uu, v);
0657 }
0658 template <class T, class U>
0659 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const U& u, const T& v)
0660 {
0661    T uu(u);
0662    eval_modulus(t, uu, v);
0663 }
0664 template <class T, class U, class V>
0665 inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus_default(T& t, const U& u, const V& v)
0666 {
0667    BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
0668    {
0669       if ((void*)&t == (void*)&v)
0670       {
0671          T temp(u);
0672          eval_modulus(temp, v);
0673          t = temp;
0674       }
0675       else
0676       {
0677          t = u;
0678          eval_modulus(t, v);
0679       }
0680    }
0681    else
0682    {
0683       t = u;
0684       eval_modulus(t, v);
0685    }
0686 }
0687 template <class T, class U, class V>
0688 inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v)
0689 {
0690    eval_modulus_default(t, u, v);
0691 }
0692 
0693 template <class T, class U, class V>
0694 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v);
0695 
0696 template <class T>
0697 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and_default(T& t, const T& u, const T& v)
0698 {
0699    if (&t == &v)
0700    {
0701       eval_bitwise_and(t, u);
0702    }
0703    else if (&t == &u)
0704    {
0705       eval_bitwise_and(t, v);
0706    }
0707    else
0708    {
0709       t = u;
0710       eval_bitwise_and(t, v);
0711    }
0712 }
0713 template <class T, class U>
0714 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
0715 {
0716    T vv;
0717    vv = v;
0718    eval_bitwise_and(t, u, vv);
0719 }
0720 template <class T, class U>
0721 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
0722 {
0723    T vv(v);
0724    eval_bitwise_and(t, u, vv);
0725 }
0726 template <class T, class U>
0727 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v)
0728 {
0729    eval_bitwise_and(t, v, u);
0730 }
0731 template <class T, class U, class V>
0732 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value || std::is_same<T, V>::value>::type eval_bitwise_and_default(T& t, const U& u, const V& v)
0733 {
0734    t = u;
0735    eval_bitwise_and(t, v);
0736 }
0737 template <class T, class U, class V>
0738 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v)
0739 {
0740    eval_bitwise_and_default(t, u, v);
0741 }
0742 
0743 template <class T, class U, class V>
0744 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v);
0745 
0746 template <class T>
0747 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or_default(T& t, const T& u, const T& v)
0748 {
0749    if (&t == &v)
0750    {
0751       eval_bitwise_or(t, u);
0752    }
0753    else if (&t == &u)
0754    {
0755       eval_bitwise_or(t, v);
0756    }
0757    else
0758    {
0759       t = u;
0760       eval_bitwise_or(t, v);
0761    }
0762 }
0763 template <class T, class U>
0764 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v)
0765 {
0766    T vv;
0767    vv = v;
0768    eval_bitwise_or(t, u, vv);
0769 }
0770 template <class T, class U>
0771 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v)
0772 {
0773    T vv(v);
0774    eval_bitwise_or(t, u, vv);
0775 }
0776 template <class T, class U>
0777 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v)
0778 {
0779    eval_bitwise_or(t, v, u);
0780 }
0781 template <class T, class U, class V>
0782 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or_default(T& t, const U& u, const V& v)
0783 {
0784    BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
0785    {
0786       if ((void*)&t == (void*)&v)
0787       {
0788          eval_bitwise_or(t, u);
0789       }
0790       else
0791       {
0792          t = u;
0793          eval_bitwise_or(t, v);
0794       }
0795    }
0796    else
0797    {
0798       t = u;
0799       eval_bitwise_or(t, v);
0800    }
0801 }
0802 template <class T, class U, class V>
0803 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v)
0804 {
0805    eval_bitwise_or_default(t, u, v);
0806 }
0807 
0808 template <class T, class U, class V>
0809 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v);
0810 
0811 template <class T>
0812 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor_default(T& t, const T& u, const T& v)
0813 {
0814    if (&t == &v)
0815    {
0816       eval_bitwise_xor(t, u);
0817    }
0818    else if (&t == &u)
0819    {
0820       eval_bitwise_xor(t, v);
0821    }
0822    else
0823    {
0824       t = u;
0825       eval_bitwise_xor(t, v);
0826    }
0827 }
0828 template <class T, class U>
0829 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v)
0830 {
0831    T vv;
0832    vv = v;
0833    eval_bitwise_xor(t, u, vv);
0834 }
0835 template <class T, class U>
0836 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v)
0837 {
0838    T vv(v);
0839    eval_bitwise_xor(t, u, vv);
0840 }
0841 template <class T, class U>
0842 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v)
0843 {
0844    eval_bitwise_xor(t, v, u);
0845 }
0846 template <class T, class U, class V>
0847 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor_default(T& t, const U& u, const V& v)
0848 {
0849    BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
0850    {
0851       if ((void*)&t == (void*)&v)
0852       {
0853          eval_bitwise_xor(t, u);
0854       }
0855       else
0856       {
0857          t = u;
0858          eval_bitwise_xor(t, v);
0859       }
0860    }
0861    else
0862    {
0863       t = u;
0864       eval_bitwise_xor(t, v);
0865    }
0866 }
0867 template <class T, class U, class V>
0868 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v)
0869 {
0870    eval_bitwise_xor_default(t, u, v);
0871 }
0872 
0873 template <class T>
0874 inline BOOST_MP_CXX14_CONSTEXPR void eval_increment(T& val)
0875 {
0876    using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
0877    eval_add(val, static_cast<ui_type>(1u));
0878 }
0879 template <class T>
0880 inline BOOST_MP_CXX14_CONSTEXPR void eval_decrement(T& val)
0881 {
0882    using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
0883    eval_subtract(val, static_cast<ui_type>(1u));
0884 }
0885 
0886 template <class T, class U, class V>
0887 inline BOOST_MP_CXX14_CONSTEXPR void eval_left_shift(T& result, const U& arg, const V val)
0888 {
0889    result = arg;
0890    eval_left_shift(result, val);
0891 }
0892 
0893 template <class T, class U, class V>
0894 inline BOOST_MP_CXX14_CONSTEXPR void eval_right_shift(T& result, const U& arg, const V val)
0895 {
0896    result = arg;
0897    eval_right_shift(result, val);
0898 }
0899 
0900 template <class T>
0901 inline BOOST_MP_CXX14_CONSTEXPR bool eval_is_zero(const T& val)
0902 {
0903    using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
0904    return val.compare(static_cast<ui_type>(0)) == 0;
0905 }
0906 template <class T>
0907 inline BOOST_MP_CXX14_CONSTEXPR int eval_get_sign(const T& val)
0908 {
0909    using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
0910    return val.compare(static_cast<ui_type>(0));
0911 }
0912 
0913 template <class T, class V, class U>
0914 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::false_type&, const std::false_type&)
0915 {
0916    using component_number_type = typename component_type<number<T> >::type;
0917 
0918    boost::multiprecision::detail::scoped_precision_options<component_number_type> sp(result);
0919    (void)sp;
0920 
0921    component_number_type x(v1), y(v2);
0922    assign_components(result, x.backend(), y.backend());
0923 }
0924 template <class T, class V, class U>
0925 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::true_type&, const std::false_type&)
0926 {
0927    boost::multiprecision::detail::scoped_source_precision<number<V>> scope;
0928    (void)scope;
0929    assign_components_imp2(result, number<V>(v1), v2, std::false_type(), std::false_type());
0930 }
0931 template <class T, class V, class U>
0932 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::true_type&, const std::true_type&)
0933 {
0934    boost::multiprecision::detail::scoped_source_precision<number<V>> scope1;
0935    boost::multiprecision::detail::scoped_source_precision<number<U>> scope2;
0936    (void)scope1;
0937    (void)scope2;
0938    assign_components_imp2(result, number<V>(v1), number<U>(v2), std::false_type(), std::false_type());
0939 }
0940 template <class T, class V, class U>
0941 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::false_type&, const std::true_type&)
0942 {
0943    boost::multiprecision::detail::scoped_source_precision<number<U>> scope;
0944    (void)scope;
0945    assign_components_imp2(result, v1, number<U>(v2), std::false_type(), std::false_type());
0946 }
0947 
0948 
0949 template <class T, class V, class U>
0950 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant<int, number_kind_rational>&)
0951 {
0952    result = v1;
0953    T t;
0954    t = v2;
0955    eval_divide(result, t);
0956 }
0957 
0958 template <class T, class V, class U, int N>
0959 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant<int, N>&)
0960 {
0961    assign_components_imp2(result, v1, v2, boost::multiprecision::detail::is_backend<V>(), boost::multiprecision::detail::is_backend<U>());
0962 }
0963 
0964 template <class T, class V, class U>
0965 inline BOOST_MP_CXX14_CONSTEXPR void assign_components(T& result, const V& v1, const U& v2)
0966 {
0967    return assign_components_imp(result, v1, v2, typename number_category<T>::type());
0968 }
0969 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
0970 template <class Result, class Traits>
0971 inline void assign_from_string_view(Result& result, const std::basic_string_view<char, Traits>& view)
0972 {
0973    // since most (all?) backends require a const char* to construct from, we just
0974    // convert to that:
0975    std::string s(view);
0976    result = s.c_str();
0977 }
0978 template <class Result, class Traits>
0979 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)
0980 {
0981    // since most (all?) backends require a const char* to construct from, we just
0982    // convert to that:
0983    std::string x(view_x), y(view_y);
0984    assign_components(result, x.c_str(), y.c_str());
0985 }
0986 #endif
0987 template <class R, int b>
0988 struct has_enough_bits
0989 {
0990    template <class T>
0991    struct type : public std::integral_constant<bool, !std::is_same<R, T>::value && (std::numeric_limits<T>::digits >= b)>
0992    {};
0993 };
0994 
0995 template <class R>
0996 struct terminal
0997 {
0998    BOOST_MP_CXX14_CONSTEXPR terminal(const R& v) : value(v) {}
0999    BOOST_MP_CXX14_CONSTEXPR terminal() {}
1000    BOOST_MP_CXX14_CONSTEXPR terminal& operator=(R val)
1001    {
1002       value = val;
1003       return *this;
1004    }
1005    R value;
1006    BOOST_MP_CXX14_CONSTEXPR operator R() const { return value; }
1007 };
1008 
1009 template <class Tuple, int i, class T, bool = (i == std::tuple_size<Tuple>::value)>
1010 struct find_index_of_type
1011 {
1012    static constexpr int value =
1013       std::is_same<T, typename std::tuple_element<static_cast<std::size_t>(i), Tuple>::type>::value
1014          ? i
1015          : find_index_of_type<Tuple, i + 1, T>::value;
1016 };
1017 template <class Tuple, int i, class T>
1018 struct find_index_of_type<Tuple, i, T, true>
1019 {
1020    static constexpr int value = -1;
1021 };
1022 
1023 
1024 template <class R, class B>
1025 struct calculate_next_larger_type
1026 {
1027    // Find which list we're looking through:
1028    using list_type = typename std::conditional<
1029        boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value,
1030        typename B::signed_types,
1031        typename std::conditional<
1032            boost::multiprecision::detail::is_unsigned<R>::value,
1033            typename B::unsigned_types,
1034            typename B::float_types>::type>::type;
1035    static constexpr int start = find_index_of_type<list_type, 0, R>::value;
1036    static constexpr int index_of_type = boost::multiprecision::detail::find_index_of_large_enough_type<list_type, start == INT_MAX ? 0 : start + 1, boost::multiprecision::detail::bits_of<R>::value> ::value;
1037    using type = typename boost::multiprecision::detail::dereference_tuple<index_of_type, list_type, terminal<R> >::type;
1038 };
1039 
1040 template <class R, class T>
1041 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<R>::value, bool>::type check_in_range(const T& t)
1042 {
1043    // Can t fit in an R?
1044    if ((t > 0) && std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (t > (std::numeric_limits<R>::max)()))
1045       return true;
1046    else
1047       return false;
1048 }
1049 
1050 template <class R, class B>
1051 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<R>::value>::type eval_convert_to(R* result, const B& backend)
1052 {
1053    using next_type = typename calculate_next_larger_type<R, B>::type;
1054    next_type                                               n = next_type();
1055    eval_convert_to(&n, backend);
1056    BOOST_IF_CONSTEXPR(!boost::multiprecision::detail::is_unsigned<R>::value && std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded)
1057    {
1058       if(n > static_cast<next_type>((std::numeric_limits<R>::max)()))
1059       {
1060          *result = (std::numeric_limits<R>::max)();
1061          return;
1062       }
1063    }
1064    BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_specialized&& std::numeric_limits<R>::is_bounded)
1065    {
1066       if (n < static_cast<next_type>((std::numeric_limits<R>::min)()))
1067       {
1068          *result = (std::numeric_limits<R>::min)();
1069          return;
1070       }
1071    }
1072    *result = static_cast<R>(n);
1073 }
1074 
1075 template <class R, class B>
1076 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !boost::multiprecision::detail::is_integral<R>::value && !std::is_enum<R>::value>::type eval_convert_to(R* result, const B& backend)
1077 {
1078    using next_type = typename calculate_next_larger_type<R, B>::type;
1079    next_type                                               n = next_type();
1080    eval_convert_to(&n, backend);
1081    BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded)
1082    {
1083       if ((n > (next_type)(std::numeric_limits<R>::max)() || (n < (next_type) - (std::numeric_limits<R>::max)())))
1084       {
1085          *result = n > 0 ? (std::numeric_limits<R>::max)() : -(std::numeric_limits<R>::max)();
1086       }
1087       else
1088          *result = static_cast<R>(n);
1089    }
1090    else
1091       *result = static_cast<R>(n);
1092 }
1093 
1094 template <class R, class B>
1095 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_enum<R>::value>::type eval_convert_to(R* result, const B& backend)
1096 {
1097    typename std::underlying_type<R>::type t{};
1098    eval_convert_to(&t, backend);
1099    *result = static_cast<R>(t);
1100 }
1101 
1102 #ifndef BOOST_MP_STANDALONE
1103 template <class R, class B>
1104 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const std::integral_constant<bool, false>&)
1105 {
1106    //
1107    // We ran out of types to try for the conversion, try
1108    // a lexical_cast and hope for the best:
1109    //
1110    BOOST_IF_CONSTEXPR (std::numeric_limits<R>::is_integer && !std::numeric_limits<R>::is_signed)
1111       if (eval_get_sign(backend) < 0)
1112          BOOST_MP_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour"));
1113    BOOST_MP_TRY {
1114       result->value = boost::lexical_cast<R>(backend.str(0, std::ios_base::fmtflags(0)));
1115    }
1116    BOOST_MP_CATCH (const bad_lexical_cast&)
1117    {
1118       if (eval_get_sign(backend) < 0)
1119       {
1120          BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_integer && !std::numeric_limits<R>::is_signed)
1121             *result = (std::numeric_limits<R>::max)(); // we should never get here, exception above will be raised.
1122          else BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_integer)
1123             *result = (std::numeric_limits<R>::min)();
1124          else
1125             *result = -(std::numeric_limits<R>::max)();
1126       }
1127       else
1128          *result = (std::numeric_limits<R>::max)();
1129    }
1130    BOOST_MP_CATCH_END
1131 }
1132 
1133 template <class R, class B>
1134 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const std::integral_constant<bool, true>&)
1135 {
1136    //
1137    // Last chance conversion to an unsigned integer.
1138    // We ran out of types to try for the conversion, try
1139    // a lexical_cast and hope for the best:
1140    //
1141    if (eval_get_sign(backend) < 0)
1142       BOOST_MP_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour"));
1143    BOOST_MP_TRY {
1144       B t(backend);
1145       R mask = ~static_cast<R>(0u);
1146       eval_bitwise_and(t, mask);
1147       result->value = boost::lexical_cast<R>(t.str(0, std::ios_base::fmtflags(0)));
1148    }
1149    BOOST_MP_CATCH (const bad_lexical_cast&)
1150    {
1151       // We should never really get here...
1152       *result = (std::numeric_limits<R>::max)();
1153    }
1154    BOOST_MP_CATCH_END
1155 }
1156 #else // Using standalone mode
1157 
1158 template <class R, class B>
1159 inline void last_chance_eval_convert_to(terminal<R>*, const B&, const std::integral_constant<bool, false>&)
1160 {
1161    static_assert(sizeof(R) == 1, "This type can not be used in standalone mode. Please de-activate and file a bug at https://github.com/boostorg/multiprecision/");
1162 }
1163 
1164 template <class R, class B>
1165 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const std::integral_constant<bool, true>&)
1166 {
1167    static_cast<void>(result);
1168    static_cast<void>(backend);
1169 
1170    static_assert(sizeof(R) == 1, "This type can not be used in standalone mode. Please de-activate and file a bug at https://github.com/boostorg/multiprecision/");
1171 }
1172 #endif
1173 
1174 template <class R, class B>
1175 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal<R>* result, const B& backend)
1176 {
1177    using tag_type = std::integral_constant<bool, boost::multiprecision::detail::is_unsigned<R>::value && number_category<B>::value == number_kind_integer>;
1178    last_chance_eval_convert_to(result, backend, tag_type());
1179 }
1180 
1181 template <class B1, class B2, expression_template_option et>
1182 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal<number<B1, et> >* result, const B2& backend)
1183 {
1184    //
1185    // We ran out of types to try for the conversion, try
1186    // a generic conversion and hope for the best:
1187    //
1188    boost::multiprecision::detail::generic_interconvert(result->value.backend(), backend, number_category<B1>(), number_category<B2>());
1189 }
1190 
1191 template <class B>
1192 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::string* result, const B& backend)
1193 {
1194    *result = backend.str(0, std::ios_base::fmtflags(0));
1195 }
1196 
1197 template <class B>
1198 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<float>* result, const B& backend)
1199 {
1200    using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1201    scalar_type                                                                            re, im;
1202    eval_real(re.backend(), backend);
1203    eval_imag(im.backend(), backend);
1204 
1205    *result = std::complex<float>(re.template convert_to<float>(), im.template convert_to<float>());
1206 }
1207 
1208 template <class B>
1209 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<double>* result, const B& backend)
1210 {
1211    using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1212    scalar_type                                                                            re, im;
1213    eval_real(re.backend(), backend);
1214    eval_imag(im.backend(), backend);
1215 
1216    *result = std::complex<double>(re.template convert_to<double>(), im.template convert_to<double>());
1217 }
1218 
1219 template <class B>
1220 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<long double>* result, const B& backend)
1221 {
1222    using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1223    scalar_type                                                                            re, im;
1224    eval_real(re.backend(), backend);
1225    eval_imag(im.backend(), backend);
1226 
1227    *result = std::complex<long double>(re.template convert_to<long double>(), im.template convert_to<long double>());
1228 }
1229 
1230 //
1231 // Functions:
1232 //
1233 template <class T, class U>
1234 inline BOOST_MP_CXX14_CONSTEXPR void eval_abs(T& result, const U& arg)
1235 {
1236    using type_list = typename U::signed_types            ;
1237    using front = typename std::tuple_element<0, type_list>::type;
1238    result = arg;
1239    if (arg.compare(front(0)) < 0)
1240       result.negate();
1241 }
1242 template <class T, class U>
1243 inline BOOST_MP_CXX14_CONSTEXPR void eval_fabs(T& result, const U& arg)
1244 {
1245    static_assert(number_category<T>::value == number_kind_floating_point, "The fabs function is only valid for floating point types.");
1246    using type_list = typename U::signed_types            ;
1247    using front = typename std::tuple_element<0, type_list>::type;
1248    result = arg;
1249    if (arg.compare(front(0)) < 0)
1250       result.negate();
1251 }
1252 
1253 template <class Backend>
1254 inline BOOST_MP_CXX14_CONSTEXPR int eval_fpclassify(const Backend& arg)
1255 {
1256    static_assert(number_category<Backend>::value == number_kind_floating_point, "The fpclassify function is only valid for floating point types.");
1257    return eval_is_zero(arg) ? FP_ZERO : FP_NORMAL;
1258 }
1259 
1260 template <class T>
1261 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmod(T& result, const T& a, const T& b)
1262 {
1263    static_assert(number_category<T>::value == number_kind_floating_point, "The fmod function is only valid for floating point types.");
1264    if ((&result == &a) || (&result == &b))
1265    {
1266       T temp;
1267       eval_fmod(temp, a, b);
1268       result = temp;
1269       return;
1270    }
1271    switch (eval_fpclassify(a))
1272    {
1273    case FP_ZERO:
1274       result = a;
1275       return;
1276    case FP_INFINITE:
1277    case FP_NAN:
1278       result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1279       errno  = EDOM;
1280       return;
1281    default:
1282       break;
1283    }
1284    switch (eval_fpclassify(b))
1285    {
1286    case FP_ZERO:
1287    case FP_NAN:
1288       result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1289       errno  = EDOM;
1290       return;
1291    default:
1292       break;
1293    }
1294    T n;
1295    eval_divide(result, a, b);
1296    if (eval_get_sign(result) < 0)
1297       eval_ceil(n, result);
1298    else
1299       eval_floor(n, result);
1300    eval_multiply(n, b);
1301    eval_subtract(result, a, n);
1302    if (eval_get_sign(result) != 0)
1303    {
1304       //
1305       // Sanity check, that due to rounding errors in division, 
1306       // we haven't accidently calculated the wrong value:
1307       // See https://github.com/boostorg/multiprecision/issues/604 for an example.
1308       //
1309       if (eval_get_sign(result) == eval_get_sign(b))
1310       {
1311          if (result.compare(b) >= 0)
1312          {
1313             eval_subtract(result, b);
1314          }
1315       }
1316       else
1317       {
1318          n = b;
1319          n.negate();
1320          if (result.compare(n) >= 0)
1321          {
1322             eval_subtract(result, n);
1323          }
1324       }
1325    }
1326 }
1327 template <class T, class A>
1328 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_fmod(T& result, const T& x, const A& a)
1329 {
1330    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1331    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1332    cast_type                                                                      c;
1333    c = a;
1334    eval_fmod(result, x, c);
1335 }
1336 
1337 template <class T, class A>
1338 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_fmod(T& result, const A& x, const T& a)
1339 {
1340    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1341    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1342    cast_type                                                                      c;
1343    c = x;
1344    eval_fmod(result, c, a);
1345 }
1346 
1347 template <class T>
1348 BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a);
1349 
1350 template <class T>
1351 inline BOOST_MP_CXX14_CONSTEXPR void eval_remquo(T& result, const T& a, const T& b, int* pi)
1352 {
1353    static_assert(number_category<T>::value == number_kind_floating_point, "The remquo function is only valid for floating point types.");
1354    if ((&result == &a) || (&result == &b))
1355    {
1356       T temp;
1357       eval_remquo(temp, a, b, pi);
1358       result = temp;
1359       return;
1360    }
1361    T n;
1362    eval_divide(result, a, b);
1363    eval_round(n, result);
1364    eval_convert_to(pi, n);
1365    eval_multiply(n, b);
1366    eval_subtract(result, a, n);
1367    if (eval_is_zero(result))
1368    {
1369       if (eval_signbit(a))
1370          result.negate();
1371    }
1372 }
1373 template <class T, class A>
1374 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_remquo(T& result, const T& x, const A& a, int* pi)
1375 {
1376    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1377    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1378    cast_type                                                                      c = cast_type();
1379    c = a;
1380    eval_remquo(result, x, c, pi);
1381 }
1382 template <class T, class A>
1383 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_remquo(T& result, const A& x, const T& a, int* pi)
1384 {
1385    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1386    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1387    cast_type                                                                      c = cast_type();
1388    c = x;
1389    eval_remquo(result, c, a, pi);
1390 }
1391 template <class T, class U, class V>
1392 inline BOOST_MP_CXX14_CONSTEXPR void eval_remainder(T& result, const U& a, const V& b)
1393 {
1394    int i(0);
1395    eval_remquo(result, a, b, &i);
1396 }
1397 
1398 template <class B>
1399 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const B& a, const B& b);
1400 template <class T, class U>
1401 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const T& a, const U& b);
1402 template <class B>
1403 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const B& a, const B& b);
1404 template <class T, class U>
1405 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const T& a, const U& b);
1406 
1407 template <class T>
1408 inline BOOST_MP_CXX14_CONSTEXPR void eval_fdim(T& result, const T& a, const T& b)
1409 {
1410    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1411    const ui_type                                                                zero = 0u;
1412    switch (eval_fpclassify(b))
1413    {
1414    case FP_NAN:
1415    case FP_INFINITE:
1416       result = zero;
1417       return;
1418    default:
1419       break;
1420    }
1421    switch (eval_fpclassify(a))
1422    {
1423    case FP_NAN:
1424       result = zero;
1425       return;
1426    case FP_INFINITE:
1427       result = a;
1428       return;
1429    default:
1430       break;
1431    }
1432    if (eval_gt(a, b))
1433    {
1434       eval_subtract(result, a, b);
1435    }
1436    else
1437       result = zero;
1438 }
1439 
1440 template <class T, class A>
1441 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value>::type eval_fdim(T& result, const T& a, const A& b)
1442 {
1443    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1444    using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type       ;
1445    const ui_type                                                                zero        = 0u;
1446    arithmetic_type                                                              canonical_b = b;
1447    switch (BOOST_MP_FPCLASSIFY(b))
1448    {
1449    case FP_NAN:
1450    case FP_INFINITE:
1451       result = zero;
1452       return;
1453    default:
1454       break;
1455    }
1456    switch (eval_fpclassify(a))
1457    {
1458    case FP_NAN:
1459       result = zero;
1460       return;
1461    case FP_INFINITE:
1462       result = a;
1463       return;
1464    default:
1465       break;
1466    }
1467    if (eval_gt(a, canonical_b))
1468    {
1469       eval_subtract(result, a, canonical_b);
1470    }
1471    else
1472       result = zero;
1473 }
1474 
1475 template <class T, class A>
1476 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value>::type eval_fdim(T& result, const A& a, const T& b)
1477 {
1478    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1479    using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type       ;
1480    const ui_type                                                                zero        = 0u;
1481    arithmetic_type                                                              canonical_a = a;
1482    switch (eval_fpclassify(b))
1483    {
1484    case FP_NAN:
1485    case FP_INFINITE:
1486       result = zero;
1487       return;
1488    default:
1489       break;
1490    }
1491    switch (BOOST_MP_FPCLASSIFY(a))
1492    {
1493    case FP_NAN:
1494       result = zero;
1495       return;
1496    case FP_INFINITE:
1497       result = std::numeric_limits<number<T> >::infinity().backend();
1498       return;
1499    default:
1500       break;
1501    }
1502    if (eval_gt(canonical_a, b))
1503    {
1504       eval_subtract(result, canonical_a, b);
1505    }
1506    else
1507       result = zero;
1508 }
1509 
1510 template <class T>
1511 inline BOOST_MP_CXX14_CONSTEXPR void eval_trunc(T& result, const T& a)
1512 {
1513    static_assert(number_category<T>::value == number_kind_floating_point, "The trunc function is only valid for floating point types.");
1514    switch (eval_fpclassify(a))
1515    {
1516    case FP_NAN:
1517       errno = EDOM;
1518       // fallthrough...
1519    case FP_ZERO:
1520    case FP_INFINITE:
1521       result = a;
1522       return;
1523    default:
1524       break;
1525    }
1526    if (eval_get_sign(a) < 0)
1527       eval_ceil(result, a);
1528    else
1529       eval_floor(result, a);
1530 }
1531 
1532 template <class T>
1533 inline BOOST_MP_CXX14_CONSTEXPR void eval_modf(T& result, T const& arg, T* pipart)
1534 {
1535    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1536    int                                                                          c = eval_fpclassify(arg);
1537    if (c == static_cast<int>(FP_NAN))
1538    {
1539       if (pipart)
1540          *pipart = arg;
1541       result = arg;
1542       return;
1543    }
1544    else if (c == static_cast<int>(FP_INFINITE))
1545    {
1546       if (pipart)
1547          *pipart = arg;
1548       result = ui_type(0u);
1549       return;
1550    }
1551    if (pipart)
1552    {
1553       eval_trunc(*pipart, arg);
1554       eval_subtract(result, arg, *pipart);
1555    }
1556    else
1557    {
1558       T ipart;
1559       eval_trunc(ipart, arg);
1560       eval_subtract(result, arg, ipart);
1561    }
1562 }
1563 
1564 template <class T>
1565 inline BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a)
1566 {
1567    static_assert(number_category<T>::value == number_kind_floating_point, "The round function is only valid for floating point types.");
1568    using fp_type = typename boost::multiprecision::detail::canonical<float, T>::type;
1569    int                                                                       c = eval_fpclassify(a);
1570    if (c == static_cast<int>(FP_NAN))
1571    {
1572       result = a;
1573       errno  = EDOM;
1574       return;
1575    }
1576    if ((c == FP_ZERO) || (c == static_cast<int>(FP_INFINITE)))
1577    {
1578       result = a;
1579    }
1580    else if (eval_get_sign(a) < 0)
1581    {
1582       eval_subtract(result, a, fp_type(0.5f));
1583       eval_ceil(result, result);
1584    }
1585    else
1586    {
1587       eval_add(result, a, fp_type(0.5f));
1588       eval_floor(result, result);
1589    }
1590 }
1591 
1592 template <class B>
1593 BOOST_MP_CXX14_CONSTEXPR void eval_lcm(B& result, const B& a, const B& b);
1594 template <class B>
1595 BOOST_MP_CXX14_CONSTEXPR void eval_gcd(B& result, const B& a, const B& b);
1596 
1597 template <class T, class Arithmetic>
1598 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_gcd(T& result, const T& a, const Arithmetic& b)
1599 {
1600    using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1601    using default_ops::eval_gcd;
1602    T t;
1603    t = static_cast<si_type>(b);
1604    eval_gcd(result, a, t);
1605 }
1606 template <class T, class Arithmetic>
1607 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_gcd(T& result, const Arithmetic& a, const T& b)
1608 {
1609    eval_gcd(result, b, a);
1610 }
1611 template <class T, class Arithmetic>
1612 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_lcm(T& result, const T& a, const Arithmetic& b)
1613 {
1614    using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1615    using default_ops::eval_lcm;
1616    T t;
1617    t = static_cast<si_type>(b);
1618    eval_lcm(result, a, t);
1619 }
1620 template <class T, class Arithmetic>
1621 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_lcm(T& result, const Arithmetic& a, const T& b)
1622 {
1623    eval_lcm(result, b, a);
1624 }
1625 
1626 template <class T>
1627 inline BOOST_MP_CXX14_CONSTEXPR std::size_t eval_lsb(const T& val)
1628 {
1629    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1630    int                                                                          c = eval_get_sign(val);
1631    if (c == 0)
1632    {
1633       BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1634    }
1635    if (c < 0)
1636    {
1637       BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1638    }
1639    std::size_t result = 0;
1640    T        mask, t;
1641    mask = ui_type(1);
1642    do
1643    {
1644       eval_bitwise_and(t, mask, val);
1645       ++result;
1646       eval_left_shift(mask, 1);
1647    } while (eval_is_zero(t));
1648 
1649    return --result;
1650 }
1651 
1652 template <class T>
1653 inline BOOST_MP_CXX14_CONSTEXPR std::ptrdiff_t eval_msb(const T& val)
1654 {
1655    int c = eval_get_sign(val);
1656    if (c == 0)
1657    {
1658       BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1659    }
1660    if (c < 0)
1661    {
1662       BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1663    }
1664    //
1665    // This implementation is really really rubbish - it does
1666    // a linear scan for the most-significant-bit.  We should really
1667    // do a binary search, but as none of our backends actually needs
1668    // this implementation, we'll leave it for now.  In fact for most
1669    // backends it's likely that there will always be a more efficient
1670    // native implementation possible.
1671    //
1672    std::size_t result = 0;
1673    T        t(val);
1674    while (!eval_is_zero(t))
1675    {
1676       eval_right_shift(t, 1);
1677       ++result;
1678    }
1679    --result;
1680 
1681    return static_cast<std::ptrdiff_t>(result);
1682 }
1683 
1684 template <class T>
1685 inline BOOST_MP_CXX14_CONSTEXPR bool eval_bit_test(const T& val, std::size_t index)
1686 {
1687    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1688    T                                                                            mask, t;
1689    mask = ui_type(1);
1690    eval_left_shift(mask, index);
1691    eval_bitwise_and(t, mask, val);
1692    return !eval_is_zero(t);
1693 }
1694 
1695 template <class T>
1696 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_set(T& val, std::size_t index)
1697 {
1698    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1699    T                                                                            mask;
1700    mask = ui_type(1);
1701    eval_left_shift(mask, index);
1702    eval_bitwise_or(val, mask);
1703 }
1704 
1705 template <class T>
1706 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_flip(T& val, std::size_t index)
1707 {
1708    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1709    T                                                                            mask;
1710    mask = ui_type(1);
1711    eval_left_shift(mask, index);
1712    eval_bitwise_xor(val, mask);
1713 }
1714 
1715 template <class T>
1716 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_unset(T& val, std::size_t index)
1717 {
1718    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1719    T                                                                            mask, t;
1720    mask = ui_type(1);
1721    eval_left_shift(mask, index);
1722    eval_bitwise_and(t, mask, val);
1723    if (!eval_is_zero(t))
1724       eval_bitwise_xor(val, mask);
1725 }
1726 
1727 template <class Backend>
1728 BOOST_MP_CXX14_CONSTEXPR void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r);
1729 
1730 template <class Backend>
1731 BOOST_MP_CXX14_CONSTEXPR void eval_karatsuba_sqrt(Backend& result, const Backend& x, Backend& r, Backend& t, size_t bits)
1732 {
1733    using default_ops::eval_is_zero;
1734    using default_ops::eval_subtract;
1735    using default_ops::eval_right_shift;
1736    using default_ops::eval_left_shift;
1737    using default_ops::eval_bit_set;
1738    using default_ops::eval_decrement;
1739    using default_ops::eval_bitwise_and;
1740    using default_ops::eval_add;
1741    using default_ops::eval_qr;
1742 
1743    using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1744 
1745    constexpr small_uint zero = 0u;
1746 
1747    // we can calculate it faster with std::sqrt
1748 #ifdef BOOST_HAS_INT128
1749    if (bits <= 128)
1750    {
1751       uint128_type a{}, b{}, c{};
1752       eval_convert_to(&a, x);
1753       c = boost::multiprecision::detail::karatsuba_sqrt(a, b, bits);
1754       r = number<Backend>::canonical_value(b);
1755       result = number<Backend>::canonical_value(c);
1756       return;
1757    }
1758 #else
1759    if (bits <= std::numeric_limits<std::uintmax_t>::digits)
1760    {
1761       std::uintmax_t a{ 0 }, b{ 0 }, c{ 0 };
1762       eval_convert_to(&a, x);
1763       c = boost::multiprecision::detail::karatsuba_sqrt(a, b, bits);
1764       r = number<Backend>::canonical_value(b);
1765       result = number<Backend>::canonical_value(c);
1766       return;
1767    }
1768 #endif
1769    // https://hal.inria.fr/file/index/docid/72854/filename/RR-3805.pdf
1770    std::size_t  b = bits / 4;
1771    Backend q(x);
1772    eval_right_shift(q, b * 2);
1773    Backend s;
1774    eval_karatsuba_sqrt(s, q, r, t, bits - b * 2);
1775    t = zero;
1776    eval_bit_set(t, static_cast<unsigned>(b * 2));
1777    eval_left_shift(r, b);
1778    eval_decrement(t);
1779    eval_bitwise_and(t, x);
1780    eval_right_shift(t, b);
1781    eval_add(t, r);
1782    eval_left_shift(s, 1u);
1783    eval_qr(t, s, q, r);
1784    eval_left_shift(r, b);
1785    t = zero;
1786    eval_bit_set(t, static_cast<unsigned>(b));
1787    eval_decrement(t);
1788    eval_bitwise_and(t, x);
1789    eval_add(r, t);
1790    eval_left_shift(s, b - 1);
1791    eval_add(s, q);
1792    eval_multiply(q, q);
1793    // we substract after, so it works for unsigned integers too
1794    if (r.compare(q) < 0)
1795    {
1796       t = s;
1797       eval_left_shift(t, 1u);
1798       eval_decrement(t);
1799       eval_add(r, t);
1800       eval_decrement(s);
1801    }
1802    eval_subtract(r, q);
1803    result = s;
1804 }
1805 
1806 template <class B>
1807 void BOOST_MP_CXX14_CONSTEXPR eval_integer_sqrt_bitwise(B& s, B& r, const B& x)
1808 {
1809    //
1810    // This is slow bit-by-bit integer square root, see for example
1811    // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
1812    // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
1813    // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
1814    // at some point.
1815    //
1816    using ui_type = typename boost::multiprecision::detail::canonical<unsigned char, B>::type;
1817 
1818    s = ui_type(0u);
1819    if (eval_get_sign(x) == 0)
1820    {
1821       r = ui_type(0u);
1822       return;
1823    }
1824    std::ptrdiff_t g = static_cast<std::ptrdiff_t>(eval_msb(x));
1825    if (g <= 1)
1826    {
1827       s = ui_type(1);
1828       eval_subtract(r, x, s);
1829       return;
1830    }
1831 
1832    B t;
1833    r = x;
1834    g /= 2;
1835    std::ptrdiff_t org_g = g;
1836    eval_bit_set(s, static_cast<std::size_t>(g));
1837    eval_bit_set(t, static_cast<std::size_t>(2 * g));
1838    eval_subtract(r, x, t);
1839    --g;
1840    if (eval_get_sign(r) == 0)
1841       return;
1842    std::ptrdiff_t msbr = static_cast<std::ptrdiff_t>(eval_msb(r));
1843    do
1844    {
1845       if (msbr >= org_g + g + 1)
1846       {
1847          t = s;
1848          eval_left_shift(t, static_cast<std::size_t>(g + 1));
1849          eval_bit_set(t, static_cast<std::size_t>(2 * g));
1850          if (t.compare(r) <= 0)
1851          {
1852             BOOST_MP_ASSERT(g >= 0);
1853             eval_bit_set(s, static_cast<std::size_t>(g));
1854             eval_subtract(r, t);
1855             if (eval_get_sign(r) == 0)
1856                return;
1857             msbr = static_cast<std::ptrdiff_t>(eval_msb(r));
1858          }
1859       }
1860       --g;
1861    } while (g >= 0);
1862 }
1863 
1864 template <class Backend>
1865 BOOST_MP_CXX14_CONSTEXPR void eval_integer_sqrt(Backend& result, Backend& r, const Backend& x)
1866 {
1867 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
1868    // recursive Karatsuba sqrt can cause issues in constexpr context:
1869    if (BOOST_MP_IS_CONST_EVALUATED(result.size()))
1870       return eval_integer_sqrt_bitwise(result, r, x);
1871 #endif
1872    using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1873 
1874    constexpr small_uint zero = 0u;
1875 
1876    if (eval_is_zero(x))
1877    {
1878       r = zero;
1879       result = zero;
1880       return;
1881    }
1882    Backend t;
1883    eval_karatsuba_sqrt(result, x, r, t, eval_msb(x) + 1);
1884 }
1885 
1886 template <class B>
1887 inline BOOST_MP_CXX14_CONSTEXPR void eval_conj(B& result, const B& val)
1888 {
1889    result = val; // assume non-complex result.
1890 }
1891 template <class B>
1892 inline BOOST_MP_CXX14_CONSTEXPR void eval_proj(B& result, const B& val)
1893 {
1894    result = val; // assume non-complex result.
1895 }
1896 
1897 //
1898 // These have to implemented by the backend, declared here so that our macro generated code compiles OK.
1899 //
1900 template <class T>
1901 typename std::enable_if<sizeof(T) == 0>::type eval_floor();
1902 template <class T>
1903 typename std::enable_if<sizeof(T) == 0>::type eval_ceil();
1904 template <class T>
1905 typename std::enable_if<sizeof(T) == 0>::type eval_trunc();
1906 template <class T>
1907 typename std::enable_if<sizeof(T) == 0>::type eval_sqrt();
1908 template <class T>
1909 typename std::enable_if<sizeof(T) == 0>::type eval_ldexp();
1910 template <class T>
1911 typename std::enable_if<sizeof(T) == 0>::type eval_frexp();
1912 // TODO implement default versions of these:
1913 template <class T>
1914 typename std::enable_if<sizeof(T) == 0>::type eval_asinh();
1915 template <class T>
1916 typename std::enable_if<sizeof(T) == 0>::type eval_acosh();
1917 template <class T>
1918 typename std::enable_if<sizeof(T) == 0>::type eval_atanh();
1919 
1920 //
1921 // eval_logb and eval_scalbn simply assume base 2 and forward to
1922 // eval_ldexp and eval_frexp:
1923 //
1924 template <class B>
1925 inline BOOST_MP_CXX14_CONSTEXPR typename B::exponent_type eval_ilogb(const B& val)
1926 {
1927    static_assert(!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");
1928    typename B::exponent_type e(0);
1929    switch (eval_fpclassify(val))
1930    {
1931    case FP_NAN:
1932 #ifdef FP_ILOGBNAN
1933       return FP_ILOGBNAN > 0 ? (std::numeric_limits<typename B::exponent_type>::max)() : (std::numeric_limits<typename B::exponent_type>::min)();
1934 #else
1935       return (std::numeric_limits<typename B::exponent_type>::max)();
1936 #endif
1937    case FP_INFINITE:
1938       return (std::numeric_limits<typename B::exponent_type>::max)();
1939    case FP_ZERO:
1940       return (std::numeric_limits<typename B::exponent_type>::min)();
1941    default:
1942       break;
1943    }
1944    B result;
1945    eval_frexp(result, val, &e);
1946    return e - 1;
1947 }
1948 
1949 template <class B>
1950 inline BOOST_MP_CXX14_CONSTEXPR void eval_logb(B& result, const B& val)
1951 {
1952    switch (eval_fpclassify(val))
1953    {
1954    case FP_NAN:
1955       result = val;
1956       errno  = EDOM;
1957       return;
1958    case FP_ZERO:
1959       result = std::numeric_limits<number<B> >::infinity().backend();
1960       result.negate();
1961       errno = ERANGE;
1962       return;
1963    case FP_INFINITE:
1964       result = val;
1965       if (eval_signbit(val))
1966          result.negate();
1967       return;
1968    default:
1969       break;
1970    }
1971    using max_t = typename std::conditional<std::is_same<std::intmax_t, long>::value, long long, std::intmax_t>::type;
1972    result = static_cast<max_t>(eval_ilogb(val));
1973 }
1974 template <class B, class A>
1975 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbn(B& result, const B& val, A e)
1976 {
1977    static_assert(!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");
1978    eval_ldexp(result, val, static_cast<typename B::exponent_type>(e));
1979 }
1980 template <class B, class A>
1981 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbln(B& result, const B& val, A e)
1982 {
1983    eval_scalbn(result, val, e);
1984 }
1985 
1986 template <class T>
1987 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, true> const&, const std::integral_constant<bool, false>&)
1988 {
1989    return eval_fpclassify(val) == FP_NAN;
1990 }
1991 template <class T>
1992 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, false> const&, const std::integral_constant<bool, true>&)
1993 {
1994    return BOOST_MP_ISNAN(val);
1995 }
1996 template <class T>
1997 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T&, std::integral_constant<bool, false> const&, const std::integral_constant<bool, false>&)
1998 {
1999    return false;
2000 }
2001 
2002 template <class T>
2003 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val)
2004 {
2005    return is_arg_nan(val, std::integral_constant<bool, boost::multiprecision::detail::is_backend<T>::value>(), std::is_floating_point<T>());
2006 }
2007 
2008 template <class T, class U, class V>
2009 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmax(T& result, const U& a, const V& b)
2010 {
2011    if (is_arg_nan(a))
2012       result = number<T>::canonical_value(b);
2013    else if (is_arg_nan(b))
2014       result = number<T>::canonical_value(a);
2015    else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
2016       result = number<T>::canonical_value(b);
2017    else
2018       result = number<T>::canonical_value(a);
2019 }
2020 template <class T, class U, class V>
2021 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmin(T& result, const U& a, const V& b)
2022 {
2023    if (is_arg_nan(a))
2024       result = number<T>::canonical_value(b);
2025    else if (is_arg_nan(b))
2026       result = number<T>::canonical_value(a);
2027    else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
2028       result = number<T>::canonical_value(a);
2029    else
2030       result = number<T>::canonical_value(b);
2031 }
2032 
2033 template <class R, class T, class U>
2034 inline BOOST_MP_CXX14_CONSTEXPR void eval_hypot(R& result, const T& a, const U& b)
2035 {
2036    //
2037    // Normalize x and y, so that both are positive and x >= y:
2038    //
2039    R x, y;
2040    x = number<R>::canonical_value(a);
2041    y = number<R>::canonical_value(b);
2042    if (eval_get_sign(x) < 0)
2043       x.negate();
2044    if (eval_get_sign(y) < 0)
2045       y.negate();
2046 
2047    // Special case, see C99 Annex F.
2048    // The order of the if's is important: do not change!
2049    int c1 = eval_fpclassify(x);
2050    int c2 = eval_fpclassify(y);
2051 
2052    if (c1 == FP_ZERO)
2053    {
2054       result = y;
2055       return;
2056    }
2057    if (c2 == FP_ZERO)
2058    {
2059       result = x;
2060       return;
2061    }
2062    if (c1 == FP_INFINITE)
2063    {
2064       result = x;
2065       return;
2066    }
2067    if ((c2 == FP_INFINITE) || (c2 == FP_NAN))
2068    {
2069       result = y;
2070       return;
2071    }
2072    if (c1 == FP_NAN)
2073    {
2074       result = x;
2075       return;
2076    }
2077 
2078    if (eval_gt(y, x))
2079       x.swap(y);
2080 
2081    eval_multiply(result, x, std::numeric_limits<number<R> >::epsilon().backend());
2082 
2083    if (eval_gt(result, y))
2084    {
2085       result = x;
2086       return;
2087    }
2088 
2089    R rat;
2090    eval_divide(rat, y, x);
2091    eval_multiply(result, rat, rat);
2092    eval_increment(result);
2093    eval_sqrt(rat, result);
2094    eval_multiply(result, rat, x);
2095 }
2096 
2097 template <class R, class T>
2098 inline BOOST_MP_CXX14_CONSTEXPR void eval_nearbyint(R& result, const T& a)
2099 {
2100    eval_round(result, a);
2101 }
2102 template <class R, class T>
2103 inline BOOST_MP_CXX14_CONSTEXPR void eval_rint(R& result, const T& a)
2104 {
2105    eval_nearbyint(result, a);
2106 }
2107 
2108 template <class T>
2109 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val)
2110 {
2111    return eval_get_sign(val) < 0 ? 1 : 0;
2112 }
2113 
2114 //
2115 // Real and imaginary parts:
2116 //
2117 template <class To, class From>
2118 inline BOOST_MP_CXX14_CONSTEXPR void eval_real(To& to, const From& from)
2119 {
2120    to = from;
2121 }
2122 template <class To, class From>
2123 inline BOOST_MP_CXX14_CONSTEXPR void eval_imag(To& to, const From&)
2124 {
2125    using ui_type = typename std::tuple_element<0, typename To::unsigned_types>::type;
2126    to = ui_type(0);
2127 }
2128 
2129 } // namespace default_ops
2130 namespace default_ops_adl {
2131 
2132 template <class To, class From>
2133 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real_imp(To& to, const From& from)
2134 {
2135    using to_component_type = typename component_type<number<To> >::type;
2136    typename to_component_type::backend_type           to_component;
2137    to_component = from;
2138    eval_set_real(to, to_component);
2139 }
2140 template <class To, class From>
2141 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag_imp(To& to, const From& from)
2142 {
2143    using to_component_type = typename component_type<number<To> >::type;
2144    typename to_component_type::backend_type           to_component;
2145    to_component = from;
2146    eval_set_imag(to, to_component);
2147 }
2148 
2149 } // namespace default_ops_adl
2150 namespace default_ops {
2151 
2152 template <class To, class From>
2153 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<To>::value == number_kind_complex>::type eval_set_real(To& to, const From& from)
2154 {
2155    default_ops_adl::eval_set_real_imp(to, from);
2156 }
2157 template <class To, class From>
2158 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<To>::value != number_kind_complex>::type eval_set_real(To& to, const From& from)
2159 {
2160    to = from;
2161 }
2162 
2163 template <class To, class From>
2164 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag(To& to, const From& from)
2165 {
2166    default_ops_adl::eval_set_imag_imp(to, from);
2167 }
2168 
2169 template <class T>
2170 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real(T& to, const T& from)
2171 {
2172    to = from;
2173 }
2174 template <class T>
2175 void BOOST_MP_CXX14_CONSTEXPR eval_set_imag(T&, const T&)
2176 {
2177    static_assert(sizeof(T) == INT_MAX, "eval_set_imag needs to be specialised for each specific backend");
2178 }
2179 
2180 //
2181 // These functions are implemented in separate files, but expanded inline here,
2182 // DO NOT CHANGE THE ORDER OF THESE INCLUDES:
2183 //
2184 #include <boost/multiprecision/detail/functions/constants.hpp>
2185 #include <boost/multiprecision/detail/functions/pow.hpp>
2186 #include <boost/multiprecision/detail/functions/trig.hpp>
2187 
2188 } // namespace default_ops
2189 
2190 //
2191 // Default versions of floating point classification routines:
2192 //
2193 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2194 inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2195 {
2196    using multiprecision::default_ops::eval_fpclassify;
2197    return eval_fpclassify(arg.backend());
2198 }
2199 template <class tag, class A1, class A2, class A3, class A4>
2200 inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2201 {
2202    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2203    return fpclassify                                                                     BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2204 }
2205 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2206 inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2207 {
2208    int v = fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg);
2209    return (v != static_cast<int>(FP_INFINITE)) && (v != static_cast<int>(FP_NAN));
2210 }
2211 template <class tag, class A1, class A2, class A3, class A4>
2212 inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2213 {
2214    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2215    return isfinite                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2216 }
2217 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2218 inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2219 {
2220    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NAN);
2221 }
2222 template <class tag, class A1, class A2, class A3, class A4>
2223 inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2224 {
2225    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2226    return isnan                                                                          BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2227 }
2228 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2229 inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2230 {
2231    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_INFINITE);
2232 }
2233 template <class tag, class A1, class A2, class A3, class A4>
2234 inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2235 {
2236    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2237    return isinf                                                                          BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2238 }
2239 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2240 inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2241 {
2242    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NORMAL);
2243 }
2244 template <class tag, class A1, class A2, class A3, class A4>
2245 inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2246 {
2247    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2248    return isnormal                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2249 }
2250 
2251 // Default versions of sign manipulation functions, if individual backends can do better than this
2252 // (for example with signed zero), then they should overload these functions further:
2253 
2254 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2255 inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2256 {
2257    return arg.sign();
2258 }
2259 template <class tag, class A1, class A2, class A3, class A4>
2260 inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2261 {
2262    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2263    return sign                                                                           BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2264 }
2265 
2266 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2267 inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2268 {
2269    using default_ops::eval_signbit;
2270    return static_cast<bool>(eval_signbit(arg.backend()));
2271 }
2272 template <class tag, class A1, class A2, class A3, class A4>
2273 inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2274 {
2275    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2276    return static_cast<bool>(signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)));
2277 }
2278 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2279 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2280 {
2281    return -arg;
2282 }
2283 template <class tag, class A1, class A2, class A3, class A4>
2284 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)
2285 {
2286    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2287    return changesign                                                                     BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2288 }
2289 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2290 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)
2291 {
2292    return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? (boost::multiprecision::changesign)(a) : a;
2293 }
2294 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2295 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)
2296 {
2297    return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2298 }
2299 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2300 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)
2301 {
2302    return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2303 }
2304 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2305 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)
2306 {
2307    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2308    return copysign                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2309 }
2310 //
2311 // real and imag:
2312 //
2313 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2314 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2315 real(const multiprecision::number<Backend, ExpressionTemplates>& a)
2316 {
2317    using default_ops::eval_real;
2318    using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2319    boost::multiprecision::detail::scoped_default_precision<result_type>                                              precision_guard(a);
2320    result_type                                                                                                       result;
2321    eval_real(result.backend(), a.backend());
2322    return result;
2323 }
2324 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2325 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2326 imag(const multiprecision::number<Backend, ExpressionTemplates>& a)
2327 {
2328    using default_ops::eval_imag;
2329    using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2330    boost::multiprecision::detail::scoped_default_precision<result_type>                                              precision_guard(a);
2331    result_type                                                                                                       result;
2332    eval_imag(result.backend(), a.backend());
2333    return result;
2334 }
2335 
2336 template <class tag, class A1, class A2, class A3, class A4>
2337 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2338 real(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2339 {
2340    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2341    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2342    return real(value_type(arg));
2343 }
2344 
2345 template <class tag, class A1, class A2, class A3, class A4>
2346 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2347 imag(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2348 {
2349    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2350    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2351    return imag(value_type(arg));
2352 }
2353 
2354 //
2355 // Complex number functions, these are overloaded at the Backend level, we just provide the
2356 // expression template versions here, plus overloads for non-complex types:
2357 //
2358 #ifdef BOOST_MP_MATH_AVAILABLE
2359 template <class T, expression_template_option ExpressionTemplates>
2360 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2361 abs(const number<T, ExpressionTemplates>& v)
2362 {
2363    return boost::math::hypot(real(v), imag(v));
2364 }
2365 template <class tag, class A1, class A2, class A3, class A4>
2366 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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::type
2367 abs(const detail::expression<tag, A1, A2, A3, A4>& v)
2368 {
2369    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2370    return abs(static_cast<number_type>(v));
2371 }
2372 
2373 template <class T, expression_template_option ExpressionTemplates>
2374 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
2375 arg(const number<T, ExpressionTemplates>& v)
2376 {
2377    return atan2(imag(v), real(v));
2378 }
2379 template <class T, expression_template_option ExpressionTemplates>
2380 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
2381 arg(const number<T, ExpressionTemplates>&)
2382 {
2383    return 0;
2384 }
2385 template <class tag, class A1, class A2, class A3, class A4>
2386 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
2387 arg(const detail::expression<tag, A1, A2, A3, A4>& v)
2388 {
2389    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2390    return arg(static_cast<number_type>(v));
2391 }
2392 #endif // BOOST_MP_MATH_AVAILABLE
2393 
2394 template <class T, expression_template_option ExpressionTemplates>
2395 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2396 norm(const number<T, ExpressionTemplates>& v)
2397 {
2398    typename component_type<number<T, ExpressionTemplates> >::type a(real(v)), b(imag(v));
2399    return a * a + b * b;
2400 }
2401 template <class T, expression_template_option ExpressionTemplates>
2402 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value != number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
2403 norm(const number<T, ExpressionTemplates>& v)
2404 {
2405    return v * v;
2406 }
2407 template <class tag, class A1, class A2, class A3, class A4>
2408 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2409 norm(const detail::expression<tag, A1, A2, A3, A4>& v)
2410 {
2411    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2412    return norm(static_cast<number_type>(v));
2413 }
2414 
2415 template <class Backend, expression_template_option ExpressionTemplates>
2416 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r, number<Backend, ExpressionTemplates> const& theta)
2417 {
2418    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2419 }
2420 
2421 template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
2422 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2423                      typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2424 polar(detail::expression<tag, A1, A2, A3, A4> const& r, number<Backend, ExpressionTemplates> const& theta)
2425 {
2426    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2427 }
2428 
2429 template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2430 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2431                      typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2432 polar(number<Backend, ExpressionTemplates> const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2433 {
2434    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2435 }
2436 
2437 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2438 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, typename detail::expression<tagb, A1b, A2b, A3b, A4b>::result_type>::value,
2439                      typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2440 polar(detail::expression<tag, A1, A2, A3, A4> const& r, detail::expression<tagb, A1b, A2b, A3b, A4b> const& theta)
2441 {
2442    using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2443    return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2444 }
2445 //
2446 // We also allow the first argument to polar to be an arithmetic type (probably a literal):
2447 //
2448 template <class Scalar, class Backend, expression_template_option ExpressionTemplates>
2449 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<Scalar>::value, typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2450 polar(Scalar const& r, number<Backend, ExpressionTemplates> const& theta)
2451 {
2452    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2453 }
2454 
2455 template <class tag, class A1, class A2, class A3, class A4, class Scalar>
2456 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<Scalar>::value,
2457                      typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2458 polar(Scalar const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2459 {
2460    using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2461    return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2462 }
2463 //
2464 // Single argument overloads:
2465 //
2466 template <class Backend, expression_template_option ExpressionTemplates>
2467 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r)
2468 {
2469    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(r);
2470 }
2471 
2472 template <class tag, class A1, class A2, class A3, class A4>
2473 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2474 polar(detail::expression<tag, A1, A2, A3, A4> const& r)
2475 {
2476    return typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type(r);
2477 }
2478 
2479 } // namespace multiprecision
2480 
2481 namespace math {
2482 
2483 //
2484 // Import Math functions here, so they can be found by Boost.Math:
2485 //
2486 using boost::multiprecision::changesign;
2487 using boost::multiprecision::copysign;
2488 using boost::multiprecision::fpclassify;
2489 using boost::multiprecision::isfinite;
2490 using boost::multiprecision::isinf;
2491 using boost::multiprecision::isnan;
2492 using boost::multiprecision::isnormal;
2493 using boost::multiprecision::sign;
2494 using boost::multiprecision::signbit;
2495 
2496 #ifndef BOOST_MP_MATH_AVAILABLE
2497 namespace policies {
2498 
2499 template <typename... Args>
2500 class policy {};
2501 
2502 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2503 void raise_rounding_error(T1, T2, T3, T4, T5)
2504 {
2505    BOOST_MP_THROW_EXCEPTION(std::runtime_error("Rounding error"));
2506 }
2507 
2508 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2509 void raise_overflow_error(T1, T2, T3, T4, T5)
2510 {
2511    BOOST_MP_THROW_EXCEPTION(std::overflow_error("Overflow error"));
2512 }
2513 
2514 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2515 void raise_evaluation_error(T1, T2, T3, T4, T5)
2516 {
2517    BOOST_MP_THROW_EXCEPTION(std::runtime_error("Evaluation error"));
2518 }
2519 
2520 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2521 void raise_domain_error(T1, T2, T3, T4, T5)
2522 {
2523    BOOST_MP_THROW_EXCEPTION(std::domain_error("Domain error"));
2524 }
2525 
2526 template <typename T, typename... Args>
2527 struct is_policy
2528 {
2529    static constexpr bool value = false;
2530 };
2531 
2532 template <typename... Args>
2533 struct is_policy<policy<Args...>>
2534 {
2535    static constexpr bool value = true;
2536 };
2537 
2538 } // namespace policies
2539 #endif
2540 
2541 } // namespace math
2542 
2543 namespace multiprecision {
2544 #ifdef BOOST_MP_MATH_AVAILABLE
2545 using c99_error_policy = ::boost::math::policies::policy<
2546     ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>,
2547     ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>,
2548     ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>,
2549     ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>,
2550     ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error> >;
2551 
2552 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2553 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2554     asinh
2555     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2556 {
2557    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2558    return boost::math::asinh(arg, c99_error_policy());
2559 }
2560 template <class tag, class A1, class A2, class A3, class A4>
2561 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
2562     asinh
2563     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2564 {
2565    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2566    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2567    return asinh(value_type(arg));
2568 }
2569 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2570 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2571     acosh
2572     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2573 {
2574    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2575    return boost::math::acosh(arg, c99_error_policy());
2576 }
2577 template <class tag, class A1, class A2, class A3, class A4>
2578 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
2579     acosh
2580     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2581 {
2582    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2583    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2584    return acosh(value_type(arg));
2585 }
2586 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2587 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2588     atanh
2589     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2590 {
2591    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2592    return boost::math::atanh(arg, c99_error_policy());
2593 }
2594 template <class tag, class A1, class A2, class A3, class A4>
2595 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
2596     atanh
2597     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2598 {
2599    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2600    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2601    return atanh(value_type(arg));
2602 }
2603 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2604 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2605 {
2606    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2607    return boost::math::cbrt(arg, c99_error_policy());
2608 }
2609 template <class tag, class A1, class A2, class A3, class A4>
2610 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)
2611 {
2612    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2613    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2614    return cbrt(value_type(arg));
2615 }
2616 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2617 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2618 {
2619    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2620    return boost::math::erf(arg, c99_error_policy());
2621 }
2622 template <class tag, class A1, class A2, class A3, class A4>
2623 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)
2624 {
2625    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2626    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2627    return erf(value_type(arg));
2628 }
2629 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2630 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2631 {
2632    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2633    return boost::math::erfc(arg, c99_error_policy());
2634 }
2635 template <class tag, class A1, class A2, class A3, class A4>
2636 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)
2637 {
2638    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2639    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2640    return erfc(value_type(arg));
2641 }
2642 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2643 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2644 {
2645    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2646    return boost::math::expm1(arg, c99_error_policy());
2647 }
2648 template <class tag, class A1, class A2, class A3, class A4>
2649 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)
2650 {
2651    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2652    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2653    return expm1(value_type(arg));
2654 }
2655 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2656 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2657 {
2658    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2659    multiprecision::number<Backend, ExpressionTemplates>                                    result;
2660    result = boost::math::lgamma(arg, c99_error_policy());
2661    if ((boost::multiprecision::isnan)(result) && !(boost::multiprecision::isnan)(arg))
2662    {
2663       result = std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::infinity();
2664       errno  = ERANGE;
2665    }
2666    return result;
2667 }
2668 template <class tag, class A1, class A2, class A3, class A4>
2669 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)
2670 {
2671    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2672    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2673    return lgamma(value_type(arg));
2674 }
2675 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2676 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2677 {
2678    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2679    if ((arg == 0) && std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::has_infinity)
2680    {
2681       errno = ERANGE;
2682       return 1 / arg;
2683    }
2684    return boost::math::tgamma(arg, c99_error_policy());
2685 }
2686 template <class tag, class A1, class A2, class A3, class A4>
2687 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)
2688 {
2689    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2690    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2691    return tgamma(value_type(arg));
2692 }
2693 
2694 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2695 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2696 {
2697    return lround(arg);
2698 }
2699 template <class tag, class A1, class A2, class A3, class A4>
2700 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2701 {
2702    return lround(arg);
2703 }
2704 #ifndef BOOST_NO_LONG_LONG
2705 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2706 inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2707 {
2708    return llround(arg);
2709 }
2710 template <class tag, class A1, class A2, class A3, class A4>
2711 inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2712 {
2713    return llround(arg);
2714 }
2715 #endif
2716 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2717 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2718 {
2719    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2720    return boost::math::log1p(arg, c99_error_policy());
2721 }
2722 template <class tag, class A1, class A2, class A3, class A4>
2723 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)
2724 {
2725    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2726    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2727    return log1p(value_type(arg));
2728 }
2729 
2730 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2731 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)
2732 {
2733    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2734    return boost::math::nextafter(a, b, c99_error_policy());
2735 }
2736 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2737 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)
2738 {
2739    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2740    return nextafter                                                                        BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2741 }
2742 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2743 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)
2744 {
2745    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2746    return nextafter                                                                        BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2747 }
2748 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2749 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)
2750 {
2751    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2752    detail::scoped_default_precision<value_type>                                          precision_guard(a, b);
2753    return nextafter                                                                      BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2754 }
2755 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2756 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)
2757 {
2758    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2759    return boost::math::nextafter(a, b, c99_error_policy());
2760 }
2761 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2762 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)
2763 {
2764    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2765    return nexttoward                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2766 }
2767 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2768 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)
2769 {
2770    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2771    return nexttoward                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2772 }
2773 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2774 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)
2775 {
2776    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2777    detail::scoped_default_precision<value_type>                                          precision_guard(a, b);
2778    return nexttoward                                                                     BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2779 }
2780 #endif // BOOST_MP_MATH_AVAILABLE
2781 
2782 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2783 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2784 {
2785    static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2786    static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2787    using default_ops::eval_add;
2788    eval_add(result.backend(), a.backend(), b.backend());
2789    return result;
2790 }
2791 
2792 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2793 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2794 {
2795    static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2796    static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2797    using default_ops::eval_subtract;
2798    eval_subtract(result.backend(), a.backend(), b.backend());
2799    return result;
2800 }
2801 
2802 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2803 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2804 {
2805    static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2806    static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2807    using default_ops::eval_multiply;
2808    eval_multiply(result.backend(), a.backend(), b.backend());
2809    return result;
2810 }
2811 
2812 template <class B, expression_template_option ET, class I>
2813 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2814 add(number<B, ET>& result, const I& a, const I& b)
2815 {
2816    using default_ops::eval_add;
2817    using canonical_type = typename detail::canonical<I, B>::type;
2818    eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2819    return result;
2820 }
2821 
2822 template <class B, expression_template_option ET, class I>
2823 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2824 subtract(number<B, ET>& result, const I& a, const I& b)
2825 {
2826    using default_ops::eval_subtract;
2827    using canonical_type = typename detail::canonical<I, B>::type;
2828    eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2829    return result;
2830 }
2831 
2832 template <class B, expression_template_option ET, class I>
2833 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2834 multiply(number<B, ET>& result, const I& a, const I& b)
2835 {
2836    using default_ops::eval_multiply;
2837    using canonical_type = typename detail::canonical<I, B>::type;
2838    eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2839    return result;
2840 }
2841 
2842 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2843 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)
2844 {
2845    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2846    return std::move(trunc(number_type(v), pol));
2847 }
2848 
2849 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2850 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates> trunc(const number<Backend, ExpressionTemplates>& v, const Policy&)
2851 {
2852    using default_ops::eval_trunc;
2853    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(v);
2854    number<Backend, ExpressionTemplates>                                                    result;
2855    eval_trunc(result.backend(), v.backend());
2856    return result;
2857 }
2858 
2859 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2860 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2861 {
2862    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2863    number_type                                                           r(trunc(v, pol));
2864    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2865       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", nullptr, number_type(v), 0, pol);
2866    return r.template convert_to<int>();
2867 }
2868 template <class tag, class A1, class A2, class A3, class A4>
2869 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2870 {
2871    return itrunc(v, boost::math::policies::policy<>());
2872 }
2873 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2874 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v, const Policy& pol)
2875 {
2876    number<Backend, ExpressionTemplates> r(trunc(v, pol));
2877    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2878       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", nullptr, v, 0, pol);
2879    return r.template convert_to<int>();
2880 }
2881 template <class Backend, expression_template_option ExpressionTemplates>
2882 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v)
2883 {
2884    return itrunc(v, boost::math::policies::policy<>());
2885 }
2886 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2887 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2888 {
2889    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2890    number_type                                                           r(trunc(v, pol));
2891    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2892       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", nullptr, number_type(v), 0L, pol);
2893    return r.template convert_to<long>();
2894 }
2895 template <class tag, class A1, class A2, class A3, class A4>
2896 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2897 {
2898    return ltrunc(v, boost::math::policies::policy<>());
2899 }
2900 template <class T, expression_template_option ExpressionTemplates, class Policy>
2901 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2902 {
2903    number<T, ExpressionTemplates> r(trunc(v, pol));
2904    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2905       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", nullptr, v, 0L, pol);
2906    return r.template convert_to<long>();
2907 }
2908 template <class T, expression_template_option ExpressionTemplates>
2909 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v)
2910 {
2911    return ltrunc(v, boost::math::policies::policy<>());
2912 }
2913 #ifndef BOOST_NO_LONG_LONG
2914 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2915 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2916 {
2917    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2918    number_type                                                           r(trunc(v, pol));
2919    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2920       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", nullptr, number_type(v), 0LL, pol);
2921    return r.template convert_to<long long>();
2922 }
2923 template <class tag, class A1, class A2, class A3, class A4>
2924 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2925 {
2926    return lltrunc(v, boost::math::policies::policy<>());
2927 }
2928 template <class T, expression_template_option ExpressionTemplates, class Policy>
2929 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2930 {
2931    number<T, ExpressionTemplates> r(trunc(v, pol));
2932    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2933       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", nullptr, v, 0LL, pol);
2934    return r.template convert_to<long long>();
2935 }
2936 template <class T, expression_template_option ExpressionTemplates>
2937 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v)
2938 {
2939    return lltrunc(v, boost::math::policies::policy<>());
2940 }
2941 #endif
2942 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2943 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)
2944 {
2945    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2946    return std::move(round(static_cast<number_type>(v), pol));
2947 }
2948 template <class T, expression_template_option ExpressionTemplates, class Policy>
2949 inline BOOST_MP_CXX14_CONSTEXPR number<T, ExpressionTemplates> round(const number<T, ExpressionTemplates>& v, const Policy&)
2950 {
2951    using default_ops::eval_round;
2952    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2953    number<T, ExpressionTemplates>                                                    result;
2954    eval_round(result.backend(), v.backend());
2955    return result;
2956 }
2957 
2958 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2959 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2960 {
2961    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2962    number_type                                                           r(round(v, pol));
2963    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2964       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, number_type(v), 0, pol);
2965    return r.template convert_to<int>();
2966 }
2967 template <class tag, class A1, class A2, class A3, class A4>
2968 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v)
2969 {
2970    return iround(v, boost::math::policies::policy<>());
2971 }
2972 template <class T, expression_template_option ExpressionTemplates, class Policy>
2973 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2974 {
2975    number<T, ExpressionTemplates> r(round(v, pol));
2976    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2977       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, v, 0, pol);
2978    return r.template convert_to<int>();
2979 }
2980 template <class T, expression_template_option ExpressionTemplates>
2981 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v)
2982 {
2983    return iround(v, boost::math::policies::policy<>());
2984 }
2985 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2986 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2987 {
2988    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2989    number_type                                                           r(round(v, pol));
2990    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2991       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", nullptr, number_type(v), 0L, pol);
2992    return r.template convert_to<long>();
2993 }
2994 template <class tag, class A1, class A2, class A3, class A4>
2995 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v)
2996 {
2997    return lround(v, boost::math::policies::policy<>());
2998 }
2999 template <class T, expression_template_option ExpressionTemplates, class Policy>
3000 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v, const Policy& pol)
3001 {
3002    number<T, ExpressionTemplates> r(round(v, pol));
3003    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
3004       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", nullptr, v, 0L, pol);
3005    return r.template convert_to<long>();
3006 }
3007 template <class T, expression_template_option ExpressionTemplates>
3008 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v)
3009 {
3010    return lround(v, boost::math::policies::policy<>());
3011 }
3012 #ifndef BOOST_NO_LONG_LONG
3013 template <class tag, class A1, class A2, class A3, class A4, class Policy>
3014 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
3015 {
3016    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3017    number_type                                                           r(round(v, pol));
3018    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
3019       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, number_type(v), 0LL, pol);
3020    return r.template convert_to<long long>();
3021 }
3022 template <class tag, class A1, class A2, class A3, class A4>
3023 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v)
3024 {
3025    return llround(v, boost::math::policies::policy<>());
3026 }
3027 template <class T, expression_template_option ExpressionTemplates, class Policy>
3028 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v, const Policy& pol)
3029 {
3030    number<T, ExpressionTemplates> r(round(v, pol));
3031    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
3032       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, v, 0LL, pol);
3033    return r.template convert_to<long long>();
3034 }
3035 template <class T, expression_template_option ExpressionTemplates>
3036 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v)
3037 {
3038    return llround(v, boost::math::policies::policy<>());
3039 }
3040 #endif
3041 //
3042 // frexp does not return an expression template since we require the
3043 // integer argument to be evaluated even if the returned value is
3044 // not assigned to anything...
3045 //
3046 template <class T, expression_template_option ExpressionTemplates>
3047 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, short* pint)
3048 {
3049    using default_ops::eval_frexp;
3050    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3051    number<T, ExpressionTemplates>                                                    result;
3052    eval_frexp(result.backend(), v.backend(), pint);
3053    return result;
3054 }
3055 template <class tag, class A1, class A2, class A3, class A4>
3056 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
3057 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, short* pint)
3058 {
3059    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3060    return std::move(frexp(static_cast<number_type>(v), pint));
3061 }
3062 template <class T, expression_template_option ExpressionTemplates>
3063 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, int* pint)
3064 {
3065    using default_ops::eval_frexp;
3066    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3067    number<T, ExpressionTemplates>                                                    result;
3068    eval_frexp(result.backend(), v.backend(), pint);
3069    return result;
3070 }
3071 template <class tag, class A1, class A2, class A3, class A4>
3072 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
3073 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, int* pint)
3074 {
3075    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3076    return std::move(frexp(static_cast<number_type>(v), pint));
3077 }
3078 template <class T, expression_template_option ExpressionTemplates>
3079 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, long* pint)
3080 {
3081    using default_ops::eval_frexp;
3082    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3083    number<T, ExpressionTemplates>                                                    result;
3084    eval_frexp(result.backend(), v.backend(), pint);
3085    return result;
3086 }
3087 template <class tag, class A1, class A2, class A3, class A4>
3088 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
3089 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long* pint)
3090 {
3091    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3092    return std::move(frexp(static_cast<number_type>(v), pint));
3093 }
3094 template <class T, expression_template_option ExpressionTemplates>
3095 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, long long* pint)
3096 {
3097    using default_ops::eval_frexp;
3098    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3099    number<T, ExpressionTemplates>                                                    result;
3100    eval_frexp(result.backend(), v.backend(), pint);
3101    return result;
3102 }
3103 template <class tag, class A1, class A2, class A3, class A4>
3104 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
3105 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long long* pint)
3106 {
3107    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3108    return std::move(frexp(static_cast<number_type>(v), pint));
3109 }
3110 //
3111 // modf does not return an expression template since we require the
3112 // second argument to be evaluated even if the returned value is
3113 // not assigned to anything...
3114 //
3115 template <class T, expression_template_option ExpressionTemplates>
3116 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type modf(const number<T, ExpressionTemplates>& v, number<T, ExpressionTemplates>* pipart)
3117 {
3118    using default_ops::eval_modf;
3119    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3120    number<T, ExpressionTemplates>                                                    result;
3121    eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : nullptr);
3122    return result;
3123 }
3124 template <class T, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
3125 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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)
3126 {
3127    using default_ops::eval_modf;
3128    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3129    number<T, ExpressionTemplates>                                                    result, arg(v);
3130    eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : nullptr);
3131    return result;
3132 }
3133 
3134 //
3135 // Integer square root:
3136 //
3137 template <class B, expression_template_option ExpressionTemplates>
3138 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3139 sqrt(const number<B, ExpressionTemplates>& x)
3140 {
3141    using default_ops::eval_integer_sqrt;
3142    number<B, ExpressionTemplates> s, r;
3143    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3144    return s;
3145 }
3146 template <class tag, class A1, class A2, class A3, class A4>
3147 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
3148          sqrt(const detail::expression<tag, A1, A2, A3, A4>& arg)
3149 {
3150    using default_ops::eval_integer_sqrt;
3151    using result_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3152    detail::scoped_default_precision<result_type> precision_guard(arg);
3153    result_type                                   result, v(arg), r;
3154    eval_integer_sqrt(result.backend(), r.backend(), v.backend());
3155    return result;
3156 }
3157 
3158 //
3159 // fma:
3160 //
3161 
3162 namespace default_ops {
3163 
3164 struct fma_func
3165 {
3166    template <class B, class T, class U, class V>
3167    BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, const V& c) const
3168    {
3169       eval_multiply_add(result, a, b, c);
3170    }
3171 };
3172 
3173 } // namespace default_ops
3174 
3175 template <class Backend, class U, class V>
3176 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3177         (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3178         (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3179         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3180     detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V> >::type
3181 fma(const number<Backend, et_on>& a, const U& b, const V& c)
3182 {
3183    return detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V>(
3184        default_ops::fma_func(), a, b, c);
3185 }
3186 
3187 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U, class V>
3188 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3189         (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3190         (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3191         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3192     detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V> >::type
3193 fma(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, const V& c)
3194 {
3195    return detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V>(
3196        default_ops::fma_func(), a, b, c);
3197 }
3198 
3199 template <class Backend, class U, class V>
3200 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3201         (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3202         (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3203         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3204     number<Backend, et_off> >::type
3205 fma(const number<Backend, et_off>& a, const U& b, const V& c)
3206 {
3207    using default_ops::eval_multiply_add;
3208    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3209    number<Backend, et_off>                                                    result;
3210    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));
3211    return result;
3212 }
3213 
3214 template <class U, class Backend, class V>
3215 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3216         (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3217         boost::multiprecision::detail::is_arithmetic<U>::value &&
3218         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3219     detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V> >::type
3220 fma(const U& a, const number<Backend, et_on>& b, const V& c)
3221 {
3222    return detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V>(
3223        default_ops::fma_func(), a, b, c);
3224 }
3225 
3226 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
3227 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3228         (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3229         boost::multiprecision::detail::is_arithmetic<U>::value &&
3230         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3231     detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V> >::type
3232 fma(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, const V& c)
3233 {
3234    return detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V>(
3235        default_ops::fma_func(), a, b, c);
3236 }
3237 
3238 template <class U, class Backend, class V>
3239 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3240         (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3241         boost::multiprecision::detail::is_arithmetic<U>::value &&
3242         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3243     number<Backend, et_off> >::type
3244 fma(const U& a, const number<Backend, et_off>& b, const V& c)
3245 {
3246    using default_ops::eval_multiply_add;
3247    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3248    number<Backend, et_off>                                                    result;
3249    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));
3250    return result;
3251 }
3252 
3253 template <class U, class V, class Backend>
3254 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3255         (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3256         boost::multiprecision::detail::is_arithmetic<U>::value &&
3257         boost::multiprecision::detail::is_arithmetic<V>::value,
3258     detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> > >::type
3259 fma(const U& a, const V& b, const number<Backend, et_on>& c)
3260 {
3261    return detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> >(
3262        default_ops::fma_func(), a, b, c);
3263 }
3264 
3265 template <class U, class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3266 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3267         (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3268         boost::multiprecision::detail::is_arithmetic<U>::value &&
3269         boost::multiprecision::detail::is_arithmetic<V>::value,
3270     detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
3271 fma(const U& a, const V& b, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& c)
3272 {
3273    return detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(
3274        default_ops::fma_func(), a, b, c);
3275 }
3276 
3277 template <class U, class V, class Backend>
3278 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3279         (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3280         boost::multiprecision::detail::is_arithmetic<U>::value &&
3281         boost::multiprecision::detail::is_arithmetic<V>::value,
3282         number<Backend, et_off> >::type
3283 fma(const U& a, const V& b, const number<Backend, et_off>& c)
3284 {
3285    using default_ops::eval_multiply_add;
3286    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3287    number<Backend, et_off>                                                    result;
3288    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));
3289    return result;
3290 }
3291 
3292 namespace default_ops {
3293 
3294 struct remquo_func
3295 {
3296    template <class B, class T, class U>
3297    BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, int* pi) const
3298    {
3299       eval_remquo(result, a, b, pi);
3300    }
3301 };
3302 
3303 } // namespace default_ops
3304 
3305 template <class Backend, class U>
3306 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3307     number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3308     detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*> >::type
3309 remquo(const number<Backend, et_on>& a, const U& b, int* pi)
3310 {
3311    return detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*>(
3312        default_ops::remquo_func(), a, b, pi);
3313 }
3314 
3315 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U>
3316 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3317     number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point,
3318     detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*> >::type
3319 remquo(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, int* pi)
3320 {
3321    return detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*>(
3322        default_ops::remquo_func(), a, b, pi);
3323 }
3324 
3325 template <class U, class Backend>
3326 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3327     (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3328     detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*> >::type
3329 remquo(const U& a, const number<Backend, et_on>& b, int* pi)
3330 {
3331    return detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*>(
3332        default_ops::remquo_func(), a, b, pi);
3333 }
3334 
3335 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3336 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3337     (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,
3338     detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*> >::type
3339 remquo(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, int* pi)
3340 {
3341    return detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*>(
3342        default_ops::remquo_func(), a, b, pi);
3343 }
3344 
3345 template <class Backend, class U>
3346 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3347     number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3348     number<Backend, et_off> >::type
3349 remquo(const number<Backend, et_off>& a, const U& b, int* pi)
3350 {
3351    using default_ops::eval_remquo;
3352    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3353    number<Backend, et_off>                                                    result;
3354    eval_remquo(result.backend(), a.backend(), number<Backend, et_off>::canonical_value(b), pi);
3355    return result;
3356 }
3357 template <class U, class Backend>
3358 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3359     (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3360     number<Backend, et_off> >::type
3361 remquo(const U& a, const number<Backend, et_off>& b, int* pi)
3362 {
3363    using default_ops::eval_remquo;
3364    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3365    number<Backend, et_off>                                                    result;
3366    eval_remquo(result.backend(), number<Backend, et_off>::canonical_value(a), b.backend(), pi);
3367    return result;
3368 }
3369 
3370 template <class B, expression_template_option ExpressionTemplates>
3371 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3372 sqrt(const number<B, ExpressionTemplates>& x, number<B, ExpressionTemplates>& r)
3373 {
3374    using default_ops::eval_integer_sqrt;
3375    detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(x, r);
3376    number<B, ExpressionTemplates>                                                    s;
3377    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3378    return s;
3379 }
3380 template <class B, expression_template_option ExpressionTemplates, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3381 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3382 sqrt(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& arg, number<B, ExpressionTemplates>& r)
3383 {
3384    using default_ops::eval_integer_sqrt;
3385    detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(r);
3386    number<B, ExpressionTemplates>                                                    s;
3387    number<B, ExpressionTemplates>                                                    x(arg);
3388    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3389    return s;
3390 }
3391 
3392 // clang-format off
3393 //
3394 // Regrettably, when the argument to a function is an rvalue we must return by value, and not return an
3395 // expression template, otherwise we can end up with dangling references.
3396 // See https://github.com/boostorg/multiprecision/issues/175.
3397 //
3398 #define UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3399    template <class Backend>                                                                                                                                                                               \
3400    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> > ::type                                                                      \
3401    func(number<Backend, et_on>&& arg)                                                                                                                                                                     \
3402    {                                                                                                                                                                                                      \
3403       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg);                                                                                                    \
3404       number<Backend, et_on>                                                    result;                                                                                                                  \
3405       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                         \
3406       BOOST_JOIN(eval_, func)(result.backend(), arg.backend());                                                                                                                                                                  \
3407       return result;                                                                                                                                                                       \
3408    }                                                                                                                                                                                                      \
3409 
3410 #define BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3411    template <class Backend>                                                                                                                                                                                                                                \
3412    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> >::type func(number<Backend, et_on>&& arg, const number<Backend, et_on>& a)                                                                                              \
3413    {                                                                                                                                                                                                                                                       \
3414       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a);                                                                                                                                                  \
3415       number<Backend, et_on>                                                    result;                                                                                                                                                                   \
3416       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3417       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3418       return result;                                                                                                                                                                                                                        \
3419    }                                                                                                                                                                                                                                                       \
3420    template <class Backend>                                                                                                                                                                                                                                \
3421    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> >::type func(const number<Backend, et_on>& arg, number<Backend, et_on>&& a)                                                                                              \
3422    {                                                                                                                                                                                                                                                       \
3423       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a);                                                                                                                                                  \
3424       number<Backend, et_on>                                                    result;                                                                                                                                                                   \
3425       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3426       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3427       return result;                                                                                                                                                                                                                        \
3428    }                                                                                                                                                                                                                                                       \
3429    template <class Backend>                                                                                                                                                                                                                                \
3430    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> >::type func(number<Backend, et_on>&& arg, number<Backend, et_on>&& a)                                                                                              \
3431    {                                                                                                                                                                                                                                                       \
3432       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a);                                                                                                                                                  \
3433       number<Backend, et_on>                                                    result;                                                                                                                                                                   \
3434       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3435       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3436       return result;                                                                                                                                                                                                                        \
3437    }                                                                                                                                                                                                                                                       \
3438    template <class Backend, class tag, class A1, class A2, class A3, class A4>                                                                                                                                                                             \
3439    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),                           \
3440            number<Backend, et_on> > ::type                                                                                                                                                                       \
3441    func(number<Backend, et_on>&& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                    \
3442    {                                                                                                                                                                                                                                                       \
3443       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3444              number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3445    }                                                                                                                                                                                                                                                       \
3446    template <class tag, class A1, class A2, class A3, class A4, class Backend>                                                                                                                                                                             \
3447    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),                           \
3448            number<Backend, et_on> > ::type                                                                                                                                                                       \
3449    func(const detail::expression<tag, A1, A2, A3, A4>& arg, number<Backend, et_on>&& a)                                                                                    \
3450    {                                                                                                                                                                                                                                                       \
3451       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3452              detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3453    }                                                                                                                                                                                                                                                       \
3454    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3455    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3456            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3457            number<Backend, et_on> >::type                                                                                                                                                                                                     \
3458    func(number<Backend, et_on>&& arg, const Arithmetic& a)                                                                                                                                               \
3459    {                                                                                                                                                                                                                                                       \
3460       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>,                                                                                                                                                      \
3461              number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                                                         \
3462    }                                                                                                                                                                                                                                                       \
3463    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3464    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3465            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3466            number<Backend, et_on> > ::type                                                                                                                                                                                                    \
3467    func(const Arithmetic& arg, number<Backend, et_on>&& a)                                                                                                                                              \
3468    {                                                                                                                                                                                                                                                       \
3469       return detail::expression<                                                                                                                                                                                                                           \
3470                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3471              Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                                                          \
3472    }                                                                                                                                                                                                                                                       \
3473 
3474 
3475 #define UNARY_OP_FUNCTOR(func, category)                                                                                                                                                                  \
3476    namespace detail {                                                                                                                                                                                     \
3477    template <class Backend>                                                                                                                                                                               \
3478    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                                                                                                                                                  \
3479    {                                                                                                                                                                                                      \
3480       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const                                                                                                                                          \
3481       {                                                                                                                                                                                                   \
3482          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                      \
3483          BOOST_JOIN(eval_, func)                                                                                                                                                                          \
3484          (result, arg);                                                                                                                                                                                   \
3485       }                                                                                                                                                                                                   \
3486       template <class U>                                                                                                                                                                                  \
3487       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg) const                                                                                                                                                \
3488       {                                                                                                                                                                                                   \
3489          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                      \
3490          Backend temp;                                                                                                                                                                                    \
3491          BOOST_JOIN(eval_, func)                                                                                                                                                                          \
3492          (temp, arg);                                                                                                                                                                                     \
3493          result = std::move(temp);                                                                                                                                                                                   \
3494       }                                                                                                                                                                                                   \
3495    };                                                                                                                                                                                                     \
3496    }                                                                                                                                                                                                      \
3497                                                                                                                                                                                                           \
3498    template <class tag, class A1, class A2, class A3, class A4>                                                                                                                                           \
3499    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category,                                                                     \
3500                                                         detail::expression<detail::function,                                                                                                              \
3501                                                         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,            \
3502                                                         detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                \
3503    func(const detail::expression<tag, A1, A2, A3, A4>& arg)                                                                    \
3504    {                                                                                                                                                                                                      \
3505       return detail::expression<                                                                                                                                                                          \
3506                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                               \
3507              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); \
3508    }                                                                                                                                                                                                      \
3509    template <class Backend>                                                                                                                                                                               \
3510    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category,                                                                                                      \
3511           detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, number<Backend, et_on> > > ::type                                                       \
3512    func(const number<Backend, et_on>& arg)                                                                                                                                                                \
3513    {                                                                                                                                                                                                      \
3514       return detail::expression<                                                                                                                                                                          \
3515                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                     \
3516              number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg);                                                                                        \
3517    }                                                                                                                                                                                                      \
3518    template <class Backend>                                                                                                                                                                               \
3519    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                    \
3520        boost::multiprecision::number_category<Backend>::value == category,                                                                                                                                \
3521        number<Backend, et_off> >::type                                                                                                                                                                    \
3522    func(const number<Backend, et_off>& arg)                                                                                                                                                               \
3523    {                                                                                                                                                                                                      \
3524       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                    \
3525       number<Backend, et_off>                                                    result;                                                                                                                  \
3526       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                         \
3527       BOOST_JOIN(eval_, func)(result.backend(), arg.backend());                                                                                                                                                                  \
3528       return result;                                                                                                                                                                       \
3529    }\
3530    UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3531 
3532 #define BINARY_OP_FUNCTOR(func, category)                                                                                                                                                                                                                  \
3533    namespace detail {                                                                                                                                                                                                                                      \
3534    template <class Backend>                                                                                                                                                                                                                                \
3535    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                                                                                                                                                                                                   \
3536    {                                                                                                                                                                                                                                                       \
3537       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Backend& a) const                                                                                                                                                                         \
3538       {                                                                                                                                                                                                                                                    \
3539          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3540          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3541          (result, arg, a);                                                                                                                                                                                                                                 \
3542       }                                                                                                                                                                                                                                                    \
3543       template <class Arithmetic>                                                                                                                                                                                                                          \
3544       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Arithmetic& a) const                                                                                                                                                                      \
3545       {                                                                                                                                                                                                                                                    \
3546          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3547          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3548          (result, arg, number<Backend>::canonical_value(a));                                                                                                                                                                                               \
3549       }                                                                                                                                                                                                                                                    \
3550       template <class Arithmetic>                                                                                                                                                                                                                          \
3551       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Arithmetic& arg, const Backend& a) const                                                                                                                                                                      \
3552       {                                                                                                                                                                                                                                                    \
3553          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3554          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3555          (result, number<Backend>::canonical_value(arg), a);                                                                                                                                                                                               \
3556       }                                                                                                                                                                                                                                                    \
3557       template <class U>                                                                                                                                                                                                                                   \
3558       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Backend& a) const                                                                                                                                                                               \
3559       {                                                                                                                                                                                                                                                    \
3560          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3561          Backend r;                                                                                                                                                                                                                                        \
3562          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3563          (r, arg, a);                                                                                                                                                                                                                                      \
3564          result = std::move(r);                                                                                                                                                                                                                                       \
3565       }                                                                                                                                                                                                                                                    \
3566       template <class U, class Arithmetic>                                                                                                                                                                                                                 \
3567       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Arithmetic& a) const                                                                                                                                                                            \
3568       {                                                                                                                                                                                                                                                    \
3569          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3570          Backend r;                                                                                                                                                                                                                                        \
3571          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3572          (r, arg, number<Backend>::canonical_value(a));                                                                                                                                                                                                    \
3573          result = std::move(r);                                                                                                                                                                                                                                       \
3574       }                                                                                                                                                                                                                                                    \
3575       template <class U, class Arithmetic>                                                                                                                                                                                                                 \
3576       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Arithmetic& arg, const Backend& a) const                                                                                                                                                                            \
3577       {                                                                                                                                                                                                                                                    \
3578          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3579          Backend r;                                                                                                                                                                                                                                        \
3580          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3581          (r, number<Backend>::canonical_value(arg), a);                                                                                                                                                                                                    \
3582          result = std::move(r);                                                                                                                                                                                                                                       \
3583       }                                                                                                                                                                                                                                                    \
3584    };                                                                                                                                                                                                                                                      \
3585    }                                                                                                                                                                                                                                                       \
3586    template <class Backend>                                                                                                                                                                                                                                \
3587    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, detail::expression<detail::function, \
3588          detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, number<Backend, et_on>, number<Backend, et_on> > > ::type                                                                                                                                                                \
3589    func(const number<Backend, et_on>& arg, const number<Backend, et_on>& a)                                                                                              \
3590    {                                                                                                                                                                                                                                                       \
3591       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3592              number<Backend, et_on>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                                              \
3593    }                                                                                                                                                                                                                                                       \
3594    template <class Backend, class tag, class A1, class A2, class A3, class A4>                                                                                                                                                                             \
3595    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),                           \
3596            detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                                                                                       \
3597    func(const number<Backend, et_on>& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                    \
3598    {                                                                                                                                                                                                                                                       \
3599       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3600              number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3601    }                                                                                                                                                                                                                                                       \
3602    template <class tag, class A1, class A2, class A3, class A4, class Backend>                                                                                                                                                                             \
3603    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value),                           \
3604            detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > > ::type                                                                                                                                                                       \
3605    func(const detail::expression<tag, A1, A2, A3, A4>& arg, const number<Backend, et_on>& a)                                                                                    \
3606    {                                                                                                                                                                                                                                                       \
3607       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3608              detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3609    }                                                                                                                                                                                                                                                       \
3610    template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>                                                                                                                                    \
3611    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category) && (number_category<detail::expression<tagb, A1b, A2b, A3b, A4b> >::value == category),                                                                          \
3612            detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3613            detail::expression<tag, A1, A2, A3, A4>, detail::expression<tagb, A1b, A2b, A3b, A4b> > > ::type                                                                                                                                                 \
3614    func(const detail::expression<tag, A1, A2, A3, A4>& arg, const detail::expression<tagb, A1b, A2b, A3b, A4b>& a)                                        \
3615    {                                                                                                                                                                                                                                                       \
3616       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3617              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); \
3618    }                                                                                                                                                                                                                                                       \
3619    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3620    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3621            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3622            detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3623            number<Backend, et_on>, Arithmetic> > ::type                                                                                                                                                                                                     \
3624    func(const number<Backend, et_on>& arg, const Arithmetic& a)                                                                                                                                               \
3625    {                                                                                                                                                                                                                                                       \
3626       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>,                                                                                                                                                      \
3627              number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                                                         \
3628    }                                                                                                                                                                                                                                                       \
3629    template <class tag, class A1, class A2, class A3, class A4, class Arithmetic>                                                                                                                                                                          \
3630    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3631            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),                                              \
3632            detail::expression<                                                                                                                                                                                                                             \
3633                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3634            detail::expression<tag, A1, A2, A3, A4>, Arithmetic> > ::type                                                                                                                                                                                    \
3635    func(const detail::expression<tag, A1, A2, A3, A4>& arg, const Arithmetic& a)                                                                                                             \
3636    {                                                                                                                                                                                                                                                       \
3637       return detail::expression<                                                                                                                                                                                                                           \
3638                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3639              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);                                  \
3640    }                                                                                                                                                                                                                                                       \
3641    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3642    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3643            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3644            detail::expression<                                                                                                                                                                                                                             \
3645                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3646            Arithmetic, number<Backend, et_on> > > ::type                                                                                                                                                                                                    \
3647    func(const Arithmetic& arg, const number<Backend, et_on>& a)                                                                                                                                              \
3648    {                                                                                                                                                                                                                                                       \
3649       return detail::expression<                                                                                                                                                                                                                           \
3650                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3651              Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                                                          \
3652    }                                                                                                                                                                                                                                                       \
3653    template <class tag, class A1, class A2, class A3, class A4, class Arithmetic>                                                                                                                                                                          \
3654        inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3655            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),                                              \
3656            detail::expression<                                                                                                                                                                                                                             \
3657                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3658            Arithmetic, detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                                                                                                   \
3659    func(const Arithmetic& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                                            \
3660    {                                                                                                                                                                                                                                                       \
3661       return detail::expression<                                                                                                                                                                                                                           \
3662                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3663              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);                                   \
3664    }                                                                                                                                                                                                                                                       \
3665    template <class Backend>                                                                                                                                                                                                                                \
3666    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category), number<Backend, et_off> >::type                                                                                                                                                                                             \
3667    func(const number<Backend, et_off>& arg, const number<Backend, et_off>& a)                                                                                                                                                                              \
3668    {                                                                                                                                                                                                                                                       \
3669       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);                                                                                                                                                  \
3670       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3671       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3672       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3673       return result;                                                                                                                                                                                                                        \
3674    }                                                                                                                                                                                                                                                       \
3675    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3676    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                            \
3677        is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),                                                                                                                        \
3678        number<Backend, et_off> >::type                                                                                                                                                                                                                     \
3679    func(const number<Backend, et_off>& arg, const Arithmetic& a)                                                                                                                                                                                           \
3680    {                                                                                                                                                                                                                                                       \
3681       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                                                                     \
3682       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3683       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3684       BOOST_JOIN(eval_, func)                                                                                                                                                                                                                              \
3685       (result.backend(), arg.backend(), number<Backend, et_off>::canonical_value(a));                                                                                                                                                                      \
3686       return result;                                                                                                                                                                                                                        \
3687    }                                                                                                                                                                                                                                                       \
3688    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3689    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                            \
3690        is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),                                                                                                                        \
3691        number<Backend, et_off> >::type                                                                                                                                                                                                                     \
3692    func(const Arithmetic& a, const number<Backend, et_off>& arg)                                                                                                                                                                                           \
3693    {                                                                                                                                                                                                                                                       \
3694       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                                                                     \
3695       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3696       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3697       BOOST_JOIN(eval_, func)                                                                                                                                                                                                                              \
3698       (result.backend(), number<Backend, et_off>::canonical_value(a), arg.backend());                                                                                                                                                                      \
3699       return result;                                                                                                                                                                                                                        \
3700    }\
3701    BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)
3702 
3703 #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)                                                                                                                                                            \
3704    template <class tag, class A1, class A2, class A3, class A4>                                                                                                                                                     \
3705        inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                 \
3706            (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),                                                                                                                          \
3707            detail::expression<                                                                                                                                                                                      \
3708                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                           \
3709            detail::expression<tag, A1, A2, A3, A4>, Arg2> > ::type                                                                                                                                                   \
3710                                                            func(const detail::expression<tag, A1, A2, A3, A4>& arg, Arg2 const& a)                                                                                  \
3711    {                                                                                                                                                                                                                \
3712       return detail::expression<                                                                                                                                                                                    \
3713                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                         \
3714              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); \
3715    }                                                                                                                                                                                                                \
3716    template <class Backend>                                                                                                                                                                                         \
3717        inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                 \
3718            (number_category<Backend>::value == category),                                                                                                                                                           \
3719            detail::expression<                                                                                                                                                                                      \
3720                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                 \
3721            number<Backend, et_on>, Arg2> > ::type                                                                                                                                                                    \
3722                                           func(const number<Backend, et_on>& arg, Arg2 const& a)                                                                                                                    \
3723    {                                                                                                                                                                                                                \
3724       return detail::expression<                                                                                                                                                                                    \
3725                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                               \
3726              number<Backend, et_on>, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                        \
3727    }                                                                                                                                                                                                                \
3728    template <class Backend>                                                                                                                                                                                         \
3729    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                     \
3730        (number_category<Backend>::value == category),                                                                                                                                                               \
3731        number<Backend, et_off> >::type                                                                                                                                                                              \
3732    func(const number<Backend, et_off>& arg, Arg2 const& a)                                                                                                                                                          \
3733    {                                                                                                                                                                                                                \
3734       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);                                                                                                           \
3735       number<Backend, et_off>                                                    result;                                                                                                                            \
3736       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                   \
3737       BOOST_JOIN(eval_, func)                                                                                                                                                                                       \
3738       (result.backend(), arg.backend(), a);                                                                                                                                                                         \
3739       return result;                                                                                                                                                                                 \
3740    }
3741 
3742 #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)                  \
3743    namespace detail {                                                   \
3744    template <class Backend>                                             \
3745    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                \
3746    {                                                                    \
3747       template <class Arg>                                              \
3748       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, Backend const& arg, Arg a) const \
3749       {                                                                 \
3750          using default_ops::BOOST_JOIN(eval_, func);                    \
3751          BOOST_JOIN(eval_, func)                                        \
3752          (result, arg, a);                                              \
3753       }                                                                 \
3754       template <class U, class Arg>                                              \
3755       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, Backend const& arg, Arg a) const \
3756       {                                                                 \
3757          using default_ops::BOOST_JOIN(eval_, func);                    \
3758          Backend temp;                                                  \
3759          BOOST_JOIN(eval_, func)                                        \
3760          (temp, arg, a);                                                \
3761          result = std::move(temp);                                  \
3762       }                                                                 \
3763    };                                                                   \
3764    }                                                                    \
3765                                                                         \
3766    HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)
3767 
3768 // clang-format on
3769 
3770 namespace detail {
3771 template <class Backend>
3772 struct abs_funct
3773 {
3774    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3775    {
3776       using default_ops::eval_abs;
3777       eval_abs(result, arg);
3778    }
3779 };
3780 template <class Backend>
3781 struct conj_funct
3782 {
3783    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3784    {
3785       using default_ops::eval_conj;
3786       eval_conj(result, arg);
3787    }
3788    //
3789    // To allow for mixed complex/scalar arithmetic where conj is called on the scalar type (as in Eigen)
3790    // we provide an overload that will promote the arg to the distination type:
3791    //
3792    template <class Other>
3793    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_constructible<Other, Backend>::value>::type operator()(Other& result, const Backend& arg) const
3794    {
3795       using default_ops::eval_conj;
3796       Other t(arg);
3797       eval_conj(result, t);
3798    }
3799 };
3800 template <class Backend>
3801 struct proj_funct
3802 {
3803    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3804    {
3805       using default_ops::eval_proj;
3806       eval_proj(result, arg);
3807    }
3808 };
3809 
3810 } // namespace detail
3811 
3812 template <class tag, class A1, class A2, class A3, class A4>
3813 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex,
3814                                     detail::expression<
3815                                         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
3816 abs(const detail::expression<tag, A1, A2, A3, A4>& arg)
3817 {
3818    return detail::expression<
3819        detail::function, detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3820        detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3821 }
3822 template <class Backend>
3823 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex,
3824                              detail::expression<
3825                                  detail::function, detail::abs_funct<Backend>, number<Backend, et_on> > >::type
3826 abs(const number<Backend, et_on>& arg)
3827 {
3828    return detail::expression<
3829        detail::function, detail::abs_funct<Backend>, number<Backend, et_on> >(
3830        detail::abs_funct<Backend>(), arg);
3831 }
3832 template <class Backend>
3833 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, number<Backend, et_off> >::type
3834 abs(const number<Backend, et_off>& arg)
3835 {
3836    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3837    number<Backend, et_off>                                                    result;
3838    using default_ops::eval_abs;
3839    eval_abs(result.backend(), arg.backend());
3840    return result;
3841 }
3842 
3843 template <class tag, class A1, class A2, class A3, class A4>
3844 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3845     detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3846 conj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3847 {
3848    return detail::expression<
3849        detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3850        detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3851 }
3852 template <class Backend>
3853 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3854     detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >
3855 conj(const number<Backend, et_on>& arg)
3856 {
3857    return detail::expression<
3858        detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >(
3859        detail::conj_funct<Backend>(), arg);
3860 }
3861 template <class Backend>
3862 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3863 conj(const number<Backend, et_off>& arg)
3864 {
3865    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3866    number<Backend, et_off>                                                    result;
3867    using default_ops::eval_conj;
3868    eval_conj(result.backend(), arg.backend());
3869    return result;
3870 }
3871 
3872 template <class tag, class A1, class A2, class A3, class A4>
3873 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3874     detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3875 proj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3876 {
3877    return detail::expression<
3878        detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3879        detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3880 }
3881 template <class Backend>
3882 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3883     detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >
3884 proj(const number<Backend, et_on>& arg)
3885 {
3886    return detail::expression<
3887        detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >(
3888        detail::proj_funct<Backend>(), arg);
3889 }
3890 template <class Backend>
3891 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3892 proj(const number<Backend, et_off>& arg)
3893 {
3894    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3895    number<Backend, et_off>                                                    result;
3896    using default_ops::eval_proj;
3897    eval_proj(result.backend(), arg.backend());
3898    return result;
3899 }
3900 
3901 UNARY_OP_FUNCTOR(fabs, number_kind_floating_point)
3902 UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point)
3903 UNARY_OP_FUNCTOR(floor, number_kind_floating_point)
3904 UNARY_OP_FUNCTOR(ceil, number_kind_floating_point)
3905 UNARY_OP_FUNCTOR(trunc, number_kind_floating_point)
3906 UNARY_OP_FUNCTOR(round, number_kind_floating_point)
3907 UNARY_OP_FUNCTOR(exp, number_kind_floating_point)
3908 UNARY_OP_FUNCTOR(exp2, number_kind_floating_point)
3909 UNARY_OP_FUNCTOR(log, number_kind_floating_point)
3910 UNARY_OP_FUNCTOR(log10, number_kind_floating_point)
3911 UNARY_OP_FUNCTOR(cos, number_kind_floating_point)
3912 UNARY_OP_FUNCTOR(sin, number_kind_floating_point)
3913 UNARY_OP_FUNCTOR(tan, number_kind_floating_point)
3914 UNARY_OP_FUNCTOR(asin, number_kind_floating_point)
3915 UNARY_OP_FUNCTOR(acos, number_kind_floating_point)
3916 UNARY_OP_FUNCTOR(atan, number_kind_floating_point)
3917 UNARY_OP_FUNCTOR(cosh, number_kind_floating_point)
3918 UNARY_OP_FUNCTOR(sinh, number_kind_floating_point)
3919 UNARY_OP_FUNCTOR(tanh, number_kind_floating_point)
3920 UNARY_OP_FUNCTOR(log2, number_kind_floating_point)
3921 UNARY_OP_FUNCTOR(nearbyint, number_kind_floating_point)
3922 UNARY_OP_FUNCTOR(rint, number_kind_floating_point)
3923 
3924 HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point)
3925 //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point)
3926 HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point)
3927 //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point)
3928 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point)
3929 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point)
3930 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long long, number_kind_floating_point)
3931 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*, number_kind_floating_point)
3932 BINARY_OP_FUNCTOR(pow, number_kind_floating_point)
3933 BINARY_OP_FUNCTOR(fmod, number_kind_floating_point)
3934 BINARY_OP_FUNCTOR(fmax, number_kind_floating_point)
3935 BINARY_OP_FUNCTOR(fmin, number_kind_floating_point)
3936 BINARY_OP_FUNCTOR(atan2, number_kind_floating_point)
3937 BINARY_OP_FUNCTOR(fdim, number_kind_floating_point)
3938 BINARY_OP_FUNCTOR(hypot, number_kind_floating_point)
3939 BINARY_OP_FUNCTOR(remainder, number_kind_floating_point)
3940 
3941 UNARY_OP_FUNCTOR(logb, number_kind_floating_point)
3942 HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point)
3943 HETERO_BINARY_OP_FUNCTOR(scalbln, short, number_kind_floating_point)
3944 HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point)
3945 HETERO_BINARY_OP_FUNCTOR_B(scalbln, int, number_kind_floating_point)
3946 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point)
3947 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long, number_kind_floating_point)
3948 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long long, number_kind_floating_point)
3949 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long long, number_kind_floating_point)
3950 
3951 //
3952 // Complex functions:
3953 //
3954 UNARY_OP_FUNCTOR(exp, number_kind_complex)
3955 UNARY_OP_FUNCTOR(log, number_kind_complex)
3956 UNARY_OP_FUNCTOR(log10, number_kind_complex)
3957 BINARY_OP_FUNCTOR(pow, number_kind_complex)
3958 UNARY_OP_FUNCTOR(sqrt, number_kind_complex)
3959 UNARY_OP_FUNCTOR(sin, number_kind_complex)
3960 UNARY_OP_FUNCTOR(cos, number_kind_complex)
3961 UNARY_OP_FUNCTOR(tan, number_kind_complex)
3962 UNARY_OP_FUNCTOR(asin, number_kind_complex)
3963 UNARY_OP_FUNCTOR(acos, number_kind_complex)
3964 UNARY_OP_FUNCTOR(atan, number_kind_complex)
3965 UNARY_OP_FUNCTOR(sinh, number_kind_complex)
3966 UNARY_OP_FUNCTOR(cosh, number_kind_complex)
3967 UNARY_OP_FUNCTOR(tanh, number_kind_complex)
3968 UNARY_OP_FUNCTOR(asinh, number_kind_complex)
3969 UNARY_OP_FUNCTOR(acosh, number_kind_complex)
3970 UNARY_OP_FUNCTOR(atanh, number_kind_complex)
3971 
3972 //
3973 // Integer functions:
3974 //
3975 BINARY_OP_FUNCTOR(gcd, number_kind_integer)
3976 BINARY_OP_FUNCTOR(lcm, number_kind_integer)
3977 HETERO_BINARY_OP_FUNCTOR(pow, unsigned, number_kind_integer)
3978 
3979 #undef BINARY_OP_FUNCTOR
3980 #undef UNARY_OP_FUNCTOR
3981 
3982 //
3983 // ilogb:
3984 //
3985 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3986 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == number_kind_floating_point, typename Backend::exponent_type>::type
3987 ilogb(const multiprecision::number<Backend, ExpressionTemplates>& val)
3988 {
3989    using default_ops::eval_ilogb;
3990    return eval_ilogb(val.backend());
3991 }
3992 
3993 template <class tag, class A1, class A2, class A3, class A4>
3994 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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
3995 ilogb(const detail::expression<tag, A1, A2, A3, A4>& val)
3996 {
3997    using default_ops::eval_ilogb;
3998    typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type arg(val);
3999    return eval_ilogb(arg.backend());
4000 }
4001 
4002 } //namespace multiprecision
4003 
4004 namespace math {
4005 
4006 
4007 //
4008 // Overload of Boost.Math functions that find the wrong overload when used with number:
4009 //
4010 namespace detail {
4011 
4012 template <class T>
4013 T sinc_pi_imp(T);
4014 template <class T, class Policy>
4015 T sinhc_pi_imp(T, const Policy&);
4016 
4017 } // namespace detail
4018 
4019 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
4020 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
4021 {
4022    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
4023    return detail::sinc_pi_imp(x);
4024 }
4025 
4026 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
4027 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
4028 {
4029    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
4030    return detail::sinc_pi_imp(x);
4031 }
4032 
4033 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
4034 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
4035 {
4036    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
4037    return detail::sinhc_pi_imp(x, boost::math::policies::policy<>());
4038 }
4039 
4040 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
4041 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy& pol)
4042 {
4043    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x, pol);
4044    return detail::sinhc_pi_imp(x, pol);
4045 }
4046 
4047 using boost::multiprecision::gcd;
4048 using boost::multiprecision::lcm;
4049 
4050 #ifdef BOOST_MSVC
4051 #pragma warning(pop)
4052 #endif
4053 } // namespace math
4054 
4055 namespace integer {
4056 
4057 using boost::multiprecision::gcd;
4058 using boost::multiprecision::lcm;
4059 
4060 } // namespace integer
4061 
4062 } // namespace boost
4063 
4064 //
4065 // This has to come last of all:
4066 //
4067 #include <boost/multiprecision/detail/no_et_ops.hpp>
4068 #include <boost/multiprecision/detail/et_ops.hpp>
4069 //
4070 // min/max overloads:
4071 //
4072 #include <boost/multiprecision/detail/min_max.hpp>
4073 
4074 #endif