Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:19

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    }
1282    switch (eval_fpclassify(b))
1283    {
1284    case FP_ZERO:
1285    case FP_NAN:
1286       result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1287       errno  = EDOM;
1288       return;
1289    }
1290    T n;
1291    eval_divide(result, a, b);
1292    if (eval_get_sign(result) < 0)
1293       eval_ceil(n, result);
1294    else
1295       eval_floor(n, result);
1296    eval_multiply(n, b);
1297    eval_subtract(result, a, n);
1298 }
1299 template <class T, class A>
1300 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)
1301 {
1302    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1303    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1304    cast_type                                                                      c;
1305    c = a;
1306    eval_fmod(result, x, c);
1307 }
1308 
1309 template <class T, class A>
1310 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)
1311 {
1312    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1313    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1314    cast_type                                                                      c;
1315    c = x;
1316    eval_fmod(result, c, a);
1317 }
1318 
1319 template <class T>
1320 BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a);
1321 
1322 template <class T>
1323 inline BOOST_MP_CXX14_CONSTEXPR void eval_remquo(T& result, const T& a, const T& b, int* pi)
1324 {
1325    static_assert(number_category<T>::value == number_kind_floating_point, "The remquo function is only valid for floating point types.");
1326    if ((&result == &a) || (&result == &b))
1327    {
1328       T temp;
1329       eval_remquo(temp, a, b, pi);
1330       result = temp;
1331       return;
1332    }
1333    T n;
1334    eval_divide(result, a, b);
1335    eval_round(n, result);
1336    eval_convert_to(pi, n);
1337    eval_multiply(n, b);
1338    eval_subtract(result, a, n);
1339    if (eval_is_zero(result))
1340    {
1341       if (eval_signbit(a))
1342          result.negate();
1343    }
1344 }
1345 template <class T, class A>
1346 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)
1347 {
1348    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1349    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1350    cast_type                                                                      c = cast_type();
1351    c = a;
1352    eval_remquo(result, x, c, pi);
1353 }
1354 template <class T, class A>
1355 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)
1356 {
1357    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
1358    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1359    cast_type                                                                      c = cast_type();
1360    c = x;
1361    eval_remquo(result, c, a, pi);
1362 }
1363 template <class T, class U, class V>
1364 inline BOOST_MP_CXX14_CONSTEXPR void eval_remainder(T& result, const U& a, const V& b)
1365 {
1366    int i(0);
1367    eval_remquo(result, a, b, &i);
1368 }
1369 
1370 template <class B>
1371 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const B& a, const B& b);
1372 template <class T, class U>
1373 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const T& a, const U& b);
1374 template <class B>
1375 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const B& a, const B& b);
1376 template <class T, class U>
1377 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const T& a, const U& b);
1378 
1379 template <class T>
1380 inline BOOST_MP_CXX14_CONSTEXPR void eval_fdim(T& result, const T& a, const T& b)
1381 {
1382    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1383    const ui_type                                                                zero = 0u;
1384    switch (eval_fpclassify(b))
1385    {
1386    case FP_NAN:
1387    case FP_INFINITE:
1388       result = zero;
1389       return;
1390    }
1391    switch (eval_fpclassify(a))
1392    {
1393    case FP_NAN:
1394       result = zero;
1395       return;
1396    case FP_INFINITE:
1397       result = a;
1398       return;
1399    }
1400    if (eval_gt(a, b))
1401    {
1402       eval_subtract(result, a, b);
1403    }
1404    else
1405       result = zero;
1406 }
1407 
1408 template <class T, class A>
1409 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)
1410 {
1411    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1412    using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type       ;
1413    const ui_type                                                                zero        = 0u;
1414    arithmetic_type                                                              canonical_b = b;
1415    switch (BOOST_MP_FPCLASSIFY(b))
1416    {
1417    case FP_NAN:
1418    case FP_INFINITE:
1419       result = zero;
1420       return;
1421    }
1422    switch (eval_fpclassify(a))
1423    {
1424    case FP_NAN:
1425       result = zero;
1426       return;
1427    case FP_INFINITE:
1428       result = a;
1429       return;
1430    }
1431    if (eval_gt(a, canonical_b))
1432    {
1433       eval_subtract(result, a, canonical_b);
1434    }
1435    else
1436       result = zero;
1437 }
1438 
1439 template <class T, class A>
1440 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)
1441 {
1442    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1443    using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type       ;
1444    const ui_type                                                                zero        = 0u;
1445    arithmetic_type                                                              canonical_a = a;
1446    switch (eval_fpclassify(b))
1447    {
1448    case FP_NAN:
1449    case FP_INFINITE:
1450       result = zero;
1451       return;
1452    }
1453    switch (BOOST_MP_FPCLASSIFY(a))
1454    {
1455    case FP_NAN:
1456       result = zero;
1457       return;
1458    case FP_INFINITE:
1459       result = std::numeric_limits<number<T> >::infinity().backend();
1460       return;
1461    }
1462    if (eval_gt(canonical_a, b))
1463    {
1464       eval_subtract(result, canonical_a, b);
1465    }
1466    else
1467       result = zero;
1468 }
1469 
1470 template <class T>
1471 inline BOOST_MP_CXX14_CONSTEXPR void eval_trunc(T& result, const T& a)
1472 {
1473    static_assert(number_category<T>::value == number_kind_floating_point, "The trunc function is only valid for floating point types.");
1474    switch (eval_fpclassify(a))
1475    {
1476    case FP_NAN:
1477       errno = EDOM;
1478       // fallthrough...
1479    case FP_ZERO:
1480    case FP_INFINITE:
1481       result = a;
1482       return;
1483    }
1484    if (eval_get_sign(a) < 0)
1485       eval_ceil(result, a);
1486    else
1487       eval_floor(result, a);
1488 }
1489 
1490 template <class T>
1491 inline BOOST_MP_CXX14_CONSTEXPR void eval_modf(T& result, T const& arg, T* pipart)
1492 {
1493    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1494    int                                                                          c = eval_fpclassify(arg);
1495    if (c == static_cast<int>(FP_NAN))
1496    {
1497       if (pipart)
1498          *pipart = arg;
1499       result = arg;
1500       return;
1501    }
1502    else if (c == static_cast<int>(FP_INFINITE))
1503    {
1504       if (pipart)
1505          *pipart = arg;
1506       result = ui_type(0u);
1507       return;
1508    }
1509    if (pipart)
1510    {
1511       eval_trunc(*pipart, arg);
1512       eval_subtract(result, arg, *pipart);
1513    }
1514    else
1515    {
1516       T ipart;
1517       eval_trunc(ipart, arg);
1518       eval_subtract(result, arg, ipart);
1519    }
1520 }
1521 
1522 template <class T>
1523 inline BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a)
1524 {
1525    static_assert(number_category<T>::value == number_kind_floating_point, "The round function is only valid for floating point types.");
1526    using fp_type = typename boost::multiprecision::detail::canonical<float, T>::type;
1527    int                                                                       c = eval_fpclassify(a);
1528    if (c == static_cast<int>(FP_NAN))
1529    {
1530       result = a;
1531       errno  = EDOM;
1532       return;
1533    }
1534    if ((c == FP_ZERO) || (c == static_cast<int>(FP_INFINITE)))
1535    {
1536       result = a;
1537    }
1538    else if (eval_get_sign(a) < 0)
1539    {
1540       eval_subtract(result, a, fp_type(0.5f));
1541       eval_ceil(result, result);
1542    }
1543    else
1544    {
1545       eval_add(result, a, fp_type(0.5f));
1546       eval_floor(result, result);
1547    }
1548 }
1549 
1550 template <class B>
1551 BOOST_MP_CXX14_CONSTEXPR void eval_lcm(B& result, const B& a, const B& b);
1552 template <class B>
1553 BOOST_MP_CXX14_CONSTEXPR void eval_gcd(B& result, const B& a, const B& b);
1554 
1555 template <class T, class Arithmetic>
1556 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)
1557 {
1558    using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1559    using default_ops::eval_gcd;
1560    T t;
1561    t = static_cast<si_type>(b);
1562    eval_gcd(result, a, t);
1563 }
1564 template <class T, class Arithmetic>
1565 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)
1566 {
1567    eval_gcd(result, b, a);
1568 }
1569 template <class T, class Arithmetic>
1570 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)
1571 {
1572    using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1573    using default_ops::eval_lcm;
1574    T t;
1575    t = static_cast<si_type>(b);
1576    eval_lcm(result, a, t);
1577 }
1578 template <class T, class Arithmetic>
1579 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)
1580 {
1581    eval_lcm(result, b, a);
1582 }
1583 
1584 template <class T>
1585 inline BOOST_MP_CXX14_CONSTEXPR std::size_t eval_lsb(const T& val)
1586 {
1587    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1588    int                                                                          c = eval_get_sign(val);
1589    if (c == 0)
1590    {
1591       BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1592    }
1593    if (c < 0)
1594    {
1595       BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1596    }
1597    std::size_t result = 0;
1598    T        mask, t;
1599    mask = ui_type(1);
1600    do
1601    {
1602       eval_bitwise_and(t, mask, val);
1603       ++result;
1604       eval_left_shift(mask, 1);
1605    } while (eval_is_zero(t));
1606 
1607    return --result;
1608 }
1609 
1610 template <class T>
1611 inline BOOST_MP_CXX14_CONSTEXPR std::ptrdiff_t eval_msb(const T& val)
1612 {
1613    int c = eval_get_sign(val);
1614    if (c == 0)
1615    {
1616       BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1617    }
1618    if (c < 0)
1619    {
1620       BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1621    }
1622    //
1623    // This implementation is really really rubbish - it does
1624    // a linear scan for the most-significant-bit.  We should really
1625    // do a binary search, but as none of our backends actually needs
1626    // this implementation, we'll leave it for now.  In fact for most
1627    // backends it's likely that there will always be a more efficient
1628    // native implementation possible.
1629    //
1630    std::size_t result = 0;
1631    T        t(val);
1632    while (!eval_is_zero(t))
1633    {
1634       eval_right_shift(t, 1);
1635       ++result;
1636    }
1637    --result;
1638 
1639    return static_cast<std::ptrdiff_t>(result);
1640 }
1641 
1642 template <class T>
1643 inline BOOST_MP_CXX14_CONSTEXPR bool eval_bit_test(const T& val, std::size_t index)
1644 {
1645    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1646    T                                                                            mask, t;
1647    mask = ui_type(1);
1648    eval_left_shift(mask, index);
1649    eval_bitwise_and(t, mask, val);
1650    return !eval_is_zero(t);
1651 }
1652 
1653 template <class T>
1654 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_set(T& val, std::size_t index)
1655 {
1656    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1657    T                                                                            mask;
1658    mask = ui_type(1);
1659    eval_left_shift(mask, index);
1660    eval_bitwise_or(val, mask);
1661 }
1662 
1663 template <class T>
1664 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_flip(T& val, std::size_t index)
1665 {
1666    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1667    T                                                                            mask;
1668    mask = ui_type(1);
1669    eval_left_shift(mask, index);
1670    eval_bitwise_xor(val, mask);
1671 }
1672 
1673 template <class T>
1674 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_unset(T& val, std::size_t index)
1675 {
1676    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1677    T                                                                            mask, t;
1678    mask = ui_type(1);
1679    eval_left_shift(mask, index);
1680    eval_bitwise_and(t, mask, val);
1681    if (!eval_is_zero(t))
1682       eval_bitwise_xor(val, mask);
1683 }
1684 
1685 template <class Backend>
1686 BOOST_MP_CXX14_CONSTEXPR void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r);
1687 
1688 template <class Backend>
1689 BOOST_MP_CXX14_CONSTEXPR void eval_karatsuba_sqrt(Backend& result, const Backend& x, Backend& r, Backend& t, size_t bits)
1690 {
1691    using default_ops::eval_is_zero;
1692    using default_ops::eval_subtract;
1693    using default_ops::eval_right_shift;
1694    using default_ops::eval_left_shift;
1695    using default_ops::eval_bit_set;
1696    using default_ops::eval_decrement;
1697    using default_ops::eval_bitwise_and;
1698    using default_ops::eval_add;
1699    using default_ops::eval_qr;
1700 
1701    using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1702 
1703    constexpr small_uint zero = 0u;
1704 
1705    // we can calculate it faster with std::sqrt
1706 #ifdef BOOST_HAS_INT128
1707    if (bits <= 128)
1708    {
1709       uint128_type a{}, b{}, c{};
1710       eval_convert_to(&a, x);
1711       c = boost::multiprecision::detail::karatsuba_sqrt(a, b, bits);
1712       r = number<Backend>::canonical_value(b);
1713       result = number<Backend>::canonical_value(c);
1714       return;
1715    }
1716 #else
1717    if (bits <= std::numeric_limits<std::uintmax_t>::digits)
1718    {
1719       std::uintmax_t a{ 0 }, b{ 0 }, c{ 0 };
1720       eval_convert_to(&a, x);
1721       c = boost::multiprecision::detail::karatsuba_sqrt(a, b, bits);
1722       r = number<Backend>::canonical_value(b);
1723       result = number<Backend>::canonical_value(c);
1724       return;
1725    }
1726 #endif
1727    // https://hal.inria.fr/file/index/docid/72854/filename/RR-3805.pdf
1728    std::size_t  b = bits / 4;
1729    Backend q(x);
1730    eval_right_shift(q, b * 2);
1731    Backend s;
1732    eval_karatsuba_sqrt(s, q, r, t, bits - b * 2);
1733    t = zero;
1734    eval_bit_set(t, static_cast<unsigned>(b * 2));
1735    eval_left_shift(r, b);
1736    eval_decrement(t);
1737    eval_bitwise_and(t, x);
1738    eval_right_shift(t, b);
1739    eval_add(t, r);
1740    eval_left_shift(s, 1u);
1741    eval_qr(t, s, q, r);
1742    eval_left_shift(r, b);
1743    t = zero;
1744    eval_bit_set(t, static_cast<unsigned>(b));
1745    eval_decrement(t);
1746    eval_bitwise_and(t, x);
1747    eval_add(r, t);
1748    eval_left_shift(s, b - 1);
1749    eval_add(s, q);
1750    eval_multiply(q, q);
1751    // we substract after, so it works for unsigned integers too
1752    if (r.compare(q) < 0)
1753    {
1754       t = s;
1755       eval_left_shift(t, 1u);
1756       eval_decrement(t);
1757       eval_add(r, t);
1758       eval_decrement(s);
1759    }
1760    eval_subtract(r, q);
1761    result = s;
1762 }
1763 
1764 template <class B>
1765 void BOOST_MP_CXX14_CONSTEXPR eval_integer_sqrt_bitwise(B& s, B& r, const B& x)
1766 {
1767    //
1768    // This is slow bit-by-bit integer square root, see for example
1769    // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
1770    // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
1771    // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
1772    // at some point.
1773    //
1774    using ui_type = typename boost::multiprecision::detail::canonical<unsigned char, B>::type;
1775 
1776    s = ui_type(0u);
1777    if (eval_get_sign(x) == 0)
1778    {
1779       r = ui_type(0u);
1780       return;
1781    }
1782    std::ptrdiff_t g = static_cast<std::ptrdiff_t>(eval_msb(x));
1783    if (g <= 1)
1784    {
1785       s = ui_type(1);
1786       eval_subtract(r, x, s);
1787       return;
1788    }
1789 
1790    B t;
1791    r = x;
1792    g /= 2;
1793    std::ptrdiff_t org_g = g;
1794    eval_bit_set(s, static_cast<std::size_t>(g));
1795    eval_bit_set(t, static_cast<std::size_t>(2 * g));
1796    eval_subtract(r, x, t);
1797    --g;
1798    if (eval_get_sign(r) == 0)
1799       return;
1800    std::ptrdiff_t msbr = static_cast<std::ptrdiff_t>(eval_msb(r));
1801    do
1802    {
1803       if (msbr >= org_g + g + 1)
1804       {
1805          t = s;
1806          eval_left_shift(t, static_cast<std::size_t>(g + 1));
1807          eval_bit_set(t, static_cast<std::size_t>(2 * g));
1808          if (t.compare(r) <= 0)
1809          {
1810             BOOST_MP_ASSERT(g >= 0);
1811             eval_bit_set(s, static_cast<std::size_t>(g));
1812             eval_subtract(r, t);
1813             if (eval_get_sign(r) == 0)
1814                return;
1815             msbr = static_cast<std::ptrdiff_t>(eval_msb(r));
1816          }
1817       }
1818       --g;
1819    } while (g >= 0);
1820 }
1821 
1822 template <class Backend>
1823 BOOST_MP_CXX14_CONSTEXPR void eval_integer_sqrt(Backend& result, Backend& r, const Backend& x)
1824 {
1825 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
1826    // recursive Karatsuba sqrt can cause issues in constexpr context:
1827    if (BOOST_MP_IS_CONST_EVALUATED(result.size()))
1828       return eval_integer_sqrt_bitwise(result, r, x);
1829 #endif
1830    using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1831 
1832    constexpr small_uint zero = 0u;
1833 
1834    if (eval_is_zero(x))
1835    {
1836       r = zero;
1837       result = zero;
1838       return;
1839    }
1840    Backend t;
1841    eval_karatsuba_sqrt(result, x, r, t, eval_msb(x) + 1);
1842 }
1843 
1844 template <class B>
1845 inline BOOST_MP_CXX14_CONSTEXPR void eval_conj(B& result, const B& val)
1846 {
1847    result = val; // assume non-complex result.
1848 }
1849 template <class B>
1850 inline BOOST_MP_CXX14_CONSTEXPR void eval_proj(B& result, const B& val)
1851 {
1852    result = val; // assume non-complex result.
1853 }
1854 
1855 //
1856 // These have to implemented by the backend, declared here so that our macro generated code compiles OK.
1857 //
1858 template <class T>
1859 typename std::enable_if<sizeof(T) == 0>::type eval_floor();
1860 template <class T>
1861 typename std::enable_if<sizeof(T) == 0>::type eval_ceil();
1862 template <class T>
1863 typename std::enable_if<sizeof(T) == 0>::type eval_trunc();
1864 template <class T>
1865 typename std::enable_if<sizeof(T) == 0>::type eval_sqrt();
1866 template <class T>
1867 typename std::enable_if<sizeof(T) == 0>::type eval_ldexp();
1868 template <class T>
1869 typename std::enable_if<sizeof(T) == 0>::type eval_frexp();
1870 // TODO implement default versions of these:
1871 template <class T>
1872 typename std::enable_if<sizeof(T) == 0>::type eval_asinh();
1873 template <class T>
1874 typename std::enable_if<sizeof(T) == 0>::type eval_acosh();
1875 template <class T>
1876 typename std::enable_if<sizeof(T) == 0>::type eval_atanh();
1877 
1878 //
1879 // eval_logb and eval_scalbn simply assume base 2 and forward to
1880 // eval_ldexp and eval_frexp:
1881 //
1882 template <class B>
1883 inline BOOST_MP_CXX14_CONSTEXPR typename B::exponent_type eval_ilogb(const B& val)
1884 {
1885    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");
1886    typename B::exponent_type e(0);
1887    switch (eval_fpclassify(val))
1888    {
1889    case FP_NAN:
1890 #ifdef FP_ILOGBNAN
1891       return FP_ILOGBNAN > 0 ? (std::numeric_limits<typename B::exponent_type>::max)() : (std::numeric_limits<typename B::exponent_type>::min)();
1892 #else
1893       return (std::numeric_limits<typename B::exponent_type>::max)();
1894 #endif
1895    case FP_INFINITE:
1896       return (std::numeric_limits<typename B::exponent_type>::max)();
1897    case FP_ZERO:
1898       return (std::numeric_limits<typename B::exponent_type>::min)();
1899    }
1900    B result;
1901    eval_frexp(result, val, &e);
1902    return e - 1;
1903 }
1904 
1905 template <class B>
1906 inline BOOST_MP_CXX14_CONSTEXPR void eval_logb(B& result, const B& val)
1907 {
1908    switch (eval_fpclassify(val))
1909    {
1910    case FP_NAN:
1911       result = val;
1912       errno  = EDOM;
1913       return;
1914    case FP_ZERO:
1915       result = std::numeric_limits<number<B> >::infinity().backend();
1916       result.negate();
1917       errno = ERANGE;
1918       return;
1919    case FP_INFINITE:
1920       result = val;
1921       if (eval_signbit(val))
1922          result.negate();
1923       return;
1924    }
1925    using max_t = typename std::conditional<std::is_same<std::intmax_t, long>::value, long long, std::intmax_t>::type;
1926    result = static_cast<max_t>(eval_ilogb(val));
1927 }
1928 template <class B, class A>
1929 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbn(B& result, const B& val, A e)
1930 {
1931    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");
1932    eval_ldexp(result, val, static_cast<typename B::exponent_type>(e));
1933 }
1934 template <class B, class A>
1935 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbln(B& result, const B& val, A e)
1936 {
1937    eval_scalbn(result, val, e);
1938 }
1939 
1940 template <class T>
1941 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, true> const&, const std::integral_constant<bool, false>&)
1942 {
1943    return eval_fpclassify(val) == FP_NAN;
1944 }
1945 template <class T>
1946 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, false> const&, const std::integral_constant<bool, true>&)
1947 {
1948    return BOOST_MP_ISNAN(val);
1949 }
1950 template <class T>
1951 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T&, std::integral_constant<bool, false> const&, const std::integral_constant<bool, false>&)
1952 {
1953    return false;
1954 }
1955 
1956 template <class T>
1957 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val)
1958 {
1959    return is_arg_nan(val, std::integral_constant<bool, boost::multiprecision::detail::is_backend<T>::value>(), std::is_floating_point<T>());
1960 }
1961 
1962 template <class T, class U, class V>
1963 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmax(T& result, const U& a, const V& b)
1964 {
1965    if (is_arg_nan(a))
1966       result = number<T>::canonical_value(b);
1967    else if (is_arg_nan(b))
1968       result = number<T>::canonical_value(a);
1969    else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1970       result = number<T>::canonical_value(b);
1971    else
1972       result = number<T>::canonical_value(a);
1973 }
1974 template <class T, class U, class V>
1975 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmin(T& result, const U& a, const V& b)
1976 {
1977    if (is_arg_nan(a))
1978       result = number<T>::canonical_value(b);
1979    else if (is_arg_nan(b))
1980       result = number<T>::canonical_value(a);
1981    else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1982       result = number<T>::canonical_value(a);
1983    else
1984       result = number<T>::canonical_value(b);
1985 }
1986 
1987 template <class R, class T, class U>
1988 inline BOOST_MP_CXX14_CONSTEXPR void eval_hypot(R& result, const T& a, const U& b)
1989 {
1990    //
1991    // Normalize x and y, so that both are positive and x >= y:
1992    //
1993    R x, y;
1994    x = number<R>::canonical_value(a);
1995    y = number<R>::canonical_value(b);
1996    if (eval_get_sign(x) < 0)
1997       x.negate();
1998    if (eval_get_sign(y) < 0)
1999       y.negate();
2000 
2001    // Special case, see C99 Annex F.
2002    // The order of the if's is important: do not change!
2003    int c1 = eval_fpclassify(x);
2004    int c2 = eval_fpclassify(y);
2005 
2006    if (c1 == FP_ZERO)
2007    {
2008       result = y;
2009       return;
2010    }
2011    if (c2 == FP_ZERO)
2012    {
2013       result = x;
2014       return;
2015    }
2016    if (c1 == FP_INFINITE)
2017    {
2018       result = x;
2019       return;
2020    }
2021    if ((c2 == FP_INFINITE) || (c2 == FP_NAN))
2022    {
2023       result = y;
2024       return;
2025    }
2026    if (c1 == FP_NAN)
2027    {
2028       result = x;
2029       return;
2030    }
2031 
2032    if (eval_gt(y, x))
2033       x.swap(y);
2034 
2035    eval_multiply(result, x, std::numeric_limits<number<R> >::epsilon().backend());
2036 
2037    if (eval_gt(result, y))
2038    {
2039       result = x;
2040       return;
2041    }
2042 
2043    R rat;
2044    eval_divide(rat, y, x);
2045    eval_multiply(result, rat, rat);
2046    eval_increment(result);
2047    eval_sqrt(rat, result);
2048    eval_multiply(result, rat, x);
2049 }
2050 
2051 template <class R, class T>
2052 inline BOOST_MP_CXX14_CONSTEXPR void eval_nearbyint(R& result, const T& a)
2053 {
2054    eval_round(result, a);
2055 }
2056 template <class R, class T>
2057 inline BOOST_MP_CXX14_CONSTEXPR void eval_rint(R& result, const T& a)
2058 {
2059    eval_nearbyint(result, a);
2060 }
2061 
2062 template <class T>
2063 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val)
2064 {
2065    return eval_get_sign(val) < 0 ? 1 : 0;
2066 }
2067 
2068 //
2069 // Real and imaginary parts:
2070 //
2071 template <class To, class From>
2072 inline BOOST_MP_CXX14_CONSTEXPR void eval_real(To& to, const From& from)
2073 {
2074    to = from;
2075 }
2076 template <class To, class From>
2077 inline BOOST_MP_CXX14_CONSTEXPR void eval_imag(To& to, const From&)
2078 {
2079    using ui_type = typename std::tuple_element<0, typename To::unsigned_types>::type;
2080    to = ui_type(0);
2081 }
2082 
2083 } // namespace default_ops
2084 namespace default_ops_adl {
2085 
2086 template <class To, class From>
2087 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real_imp(To& to, const From& from)
2088 {
2089    using to_component_type = typename component_type<number<To> >::type;
2090    typename to_component_type::backend_type           to_component;
2091    to_component = from;
2092    eval_set_real(to, to_component);
2093 }
2094 template <class To, class From>
2095 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag_imp(To& to, const From& from)
2096 {
2097    using to_component_type = typename component_type<number<To> >::type;
2098    typename to_component_type::backend_type           to_component;
2099    to_component = from;
2100    eval_set_imag(to, to_component);
2101 }
2102 
2103 } // namespace default_ops_adl
2104 namespace default_ops {
2105 
2106 template <class To, class From>
2107 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)
2108 {
2109    default_ops_adl::eval_set_real_imp(to, from);
2110 }
2111 template <class To, class From>
2112 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)
2113 {
2114    to = from;
2115 }
2116 
2117 template <class To, class From>
2118 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag(To& to, const From& from)
2119 {
2120    default_ops_adl::eval_set_imag_imp(to, from);
2121 }
2122 
2123 template <class T>
2124 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real(T& to, const T& from)
2125 {
2126    to = from;
2127 }
2128 template <class T>
2129 void BOOST_MP_CXX14_CONSTEXPR eval_set_imag(T&, const T&)
2130 {
2131    static_assert(sizeof(T) == INT_MAX, "eval_set_imag needs to be specialised for each specific backend");
2132 }
2133 
2134 //
2135 // These functions are implemented in separate files, but expanded inline here,
2136 // DO NOT CHANGE THE ORDER OF THESE INCLUDES:
2137 //
2138 #include <boost/multiprecision/detail/functions/constants.hpp>
2139 #include <boost/multiprecision/detail/functions/pow.hpp>
2140 #include <boost/multiprecision/detail/functions/trig.hpp>
2141 
2142 } // namespace default_ops
2143 
2144 //
2145 // Default versions of floating point classification routines:
2146 //
2147 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2148 inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2149 {
2150    using multiprecision::default_ops::eval_fpclassify;
2151    return eval_fpclassify(arg.backend());
2152 }
2153 template <class tag, class A1, class A2, class A3, class A4>
2154 inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2155 {
2156    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2157    return fpclassify                                                                     BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2158 }
2159 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2160 inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2161 {
2162    int v = fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg);
2163    return (v != static_cast<int>(FP_INFINITE)) && (v != static_cast<int>(FP_NAN));
2164 }
2165 template <class tag, class A1, class A2, class A3, class A4>
2166 inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2167 {
2168    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2169    return isfinite                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2170 }
2171 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2172 inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2173 {
2174    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NAN);
2175 }
2176 template <class tag, class A1, class A2, class A3, class A4>
2177 inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2178 {
2179    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2180    return isnan                                                                          BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2181 }
2182 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2183 inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2184 {
2185    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_INFINITE);
2186 }
2187 template <class tag, class A1, class A2, class A3, class A4>
2188 inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2189 {
2190    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2191    return isinf                                                                          BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2192 }
2193 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2194 inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2195 {
2196    return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NORMAL);
2197 }
2198 template <class tag, class A1, class A2, class A3, class A4>
2199 inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2200 {
2201    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2202    return isnormal                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2203 }
2204 
2205 // Default versions of sign manipulation functions, if individual backends can do better than this
2206 // (for example with signed zero), then they should overload these functions further:
2207 
2208 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2209 inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2210 {
2211    return arg.sign();
2212 }
2213 template <class tag, class A1, class A2, class A3, class A4>
2214 inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2215 {
2216    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2217    return sign                                                                           BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2218 }
2219 
2220 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2221 inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2222 {
2223    using default_ops::eval_signbit;
2224    return static_cast<bool>(eval_signbit(arg.backend()));
2225 }
2226 template <class tag, class A1, class A2, class A3, class A4>
2227 inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2228 {
2229    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2230    return static_cast<bool>(signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)));
2231 }
2232 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2233 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2234 {
2235    return -arg;
2236 }
2237 template <class tag, class A1, class A2, class A3, class A4>
2238 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)
2239 {
2240    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2241    return changesign                                                                     BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2242 }
2243 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2244 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)
2245 {
2246    return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? (boost::multiprecision::changesign)(a) : a;
2247 }
2248 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2249 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)
2250 {
2251    return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2252 }
2253 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2254 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)
2255 {
2256    return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2257 }
2258 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2259 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)
2260 {
2261    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2262    return copysign                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2263 }
2264 //
2265 // real and imag:
2266 //
2267 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2268 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2269 real(const multiprecision::number<Backend, ExpressionTemplates>& a)
2270 {
2271    using default_ops::eval_real;
2272    using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2273    boost::multiprecision::detail::scoped_default_precision<result_type>                                              precision_guard(a);
2274    result_type                                                                                                       result;
2275    eval_real(result.backend(), a.backend());
2276    return result;
2277 }
2278 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2279 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2280 imag(const multiprecision::number<Backend, ExpressionTemplates>& a)
2281 {
2282    using default_ops::eval_imag;
2283    using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2284    boost::multiprecision::detail::scoped_default_precision<result_type>                                              precision_guard(a);
2285    result_type                                                                                                       result;
2286    eval_imag(result.backend(), a.backend());
2287    return result;
2288 }
2289 
2290 template <class tag, class A1, class A2, class A3, class A4>
2291 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2292 real(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2293 {
2294    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2295    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2296    return real(value_type(arg));
2297 }
2298 
2299 template <class tag, class A1, class A2, class A3, class A4>
2300 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2301 imag(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2302 {
2303    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2304    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2305    return imag(value_type(arg));
2306 }
2307 
2308 //
2309 // Complex number functions, these are overloaded at the Backend level, we just provide the
2310 // expression template versions here, plus overloads for non-complex types:
2311 //
2312 #ifdef BOOST_MP_MATH_AVAILABLE
2313 template <class T, expression_template_option ExpressionTemplates>
2314 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2315 abs(const number<T, ExpressionTemplates>& v)
2316 {
2317    return std::move(boost::math::hypot(real(v), imag(v)));
2318 }
2319 template <class tag, class A1, class A2, class A3, class A4>
2320 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
2321 abs(const detail::expression<tag, A1, A2, A3, A4>& v)
2322 {
2323    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2324    return std::move(abs(static_cast<number_type>(v)));
2325 }
2326 
2327 template <class T, expression_template_option ExpressionTemplates>
2328 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
2329 arg(const number<T, ExpressionTemplates>& v)
2330 {
2331    return std::move(atan2(imag(v), real(v)));
2332 }
2333 template <class T, expression_template_option ExpressionTemplates>
2334 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
2335 arg(const number<T, ExpressionTemplates>&)
2336 {
2337    return 0;
2338 }
2339 template <class tag, class A1, class A2, class A3, class A4>
2340 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
2341 arg(const detail::expression<tag, A1, A2, A3, A4>& v)
2342 {
2343    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2344    return std::move(arg(static_cast<number_type>(v)));
2345 }
2346 #endif // BOOST_MP_MATH_AVAILABLE
2347 
2348 template <class T, expression_template_option ExpressionTemplates>
2349 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2350 norm(const number<T, ExpressionTemplates>& v)
2351 {
2352    typename component_type<number<T, ExpressionTemplates> >::type a(real(v)), b(imag(v));
2353    return std::move(a * a + b * b);
2354 }
2355 template <class T, expression_template_option ExpressionTemplates>
2356 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
2357 norm(const number<T, ExpressionTemplates>& v)
2358 {
2359    return v * v;
2360 }
2361 template <class tag, class A1, class A2, class A3, class A4>
2362 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2363 norm(const detail::expression<tag, A1, A2, A3, A4>& v)
2364 {
2365    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2366    return std::move(norm(static_cast<number_type>(v)));
2367 }
2368 
2369 template <class Backend, expression_template_option ExpressionTemplates>
2370 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r, number<Backend, ExpressionTemplates> const& theta)
2371 {
2372    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2373 }
2374 
2375 template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
2376 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,
2377                      typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2378 polar(detail::expression<tag, A1, A2, A3, A4> const& r, number<Backend, ExpressionTemplates> const& theta)
2379 {
2380    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2381 }
2382 
2383 template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2384 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,
2385                      typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2386 polar(number<Backend, ExpressionTemplates> const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2387 {
2388    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2389 }
2390 
2391 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2392 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,
2393                      typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2394 polar(detail::expression<tag, A1, A2, A3, A4> const& r, detail::expression<tagb, A1b, A2b, A3b, A4b> const& theta)
2395 {
2396    using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2397    return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2398 }
2399 //
2400 // We also allow the first argument to polar to be an arithmetic type (probably a literal):
2401 //
2402 template <class Scalar, class Backend, expression_template_option ExpressionTemplates>
2403 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
2404 polar(Scalar const& r, number<Backend, ExpressionTemplates> const& theta)
2405 {
2406    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2407 }
2408 
2409 template <class tag, class A1, class A2, class A3, class A4, class Scalar>
2410 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<Scalar>::value,
2411                      typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2412 polar(Scalar const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2413 {
2414    using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2415    return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2416 }
2417 //
2418 // Single argument overloads:
2419 //
2420 template <class Backend, expression_template_option ExpressionTemplates>
2421 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r)
2422 {
2423    return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(r);
2424 }
2425 
2426 template <class tag, class A1, class A2, class A3, class A4>
2427 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2428 polar(detail::expression<tag, A1, A2, A3, A4> const& r)
2429 {
2430    return typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type(r);
2431 }
2432 
2433 } // namespace multiprecision
2434 
2435 namespace math {
2436 
2437 //
2438 // Import Math functions here, so they can be found by Boost.Math:
2439 //
2440 using boost::multiprecision::changesign;
2441 using boost::multiprecision::copysign;
2442 using boost::multiprecision::fpclassify;
2443 using boost::multiprecision::isfinite;
2444 using boost::multiprecision::isinf;
2445 using boost::multiprecision::isnan;
2446 using boost::multiprecision::isnormal;
2447 using boost::multiprecision::sign;
2448 using boost::multiprecision::signbit;
2449 
2450 #ifndef BOOST_MP_MATH_AVAILABLE
2451 namespace policies {
2452 
2453 template <typename... Args>
2454 class policy {};
2455 
2456 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2457 void raise_rounding_error(T1, T2, T3, T4, T5)
2458 {
2459    BOOST_MP_THROW_EXCEPTION(std::runtime_error("Rounding error"));
2460 }
2461 
2462 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2463 void raise_overflow_error(T1, T2, T3, T4, T5)
2464 {
2465    BOOST_MP_THROW_EXCEPTION(std::runtime_error("Overflow error"));
2466 }
2467 
2468 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2469 void raise_evaluation_error(T1, T2, T3, T4, T5)
2470 {
2471    BOOST_MP_THROW_EXCEPTION(std::runtime_error("Evaluation error"));
2472 }
2473 
2474 template <typename T, typename... Args>
2475 struct is_policy
2476 {
2477    static constexpr bool value = false;
2478 };
2479 
2480 template <typename... Args>
2481 struct is_policy<policy<Args...>>
2482 {
2483    static constexpr bool value = true;
2484 };
2485 
2486 } // namespace policies
2487 #endif
2488 
2489 } // namespace math
2490 
2491 namespace multiprecision {
2492 #ifdef BOOST_MP_MATH_AVAILABLE
2493 using c99_error_policy = ::boost::math::policies::policy<
2494     ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>,
2495     ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>,
2496     ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>,
2497     ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>,
2498     ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error> >;
2499 
2500 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2501 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2502     asinh
2503     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2504 {
2505    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2506    return boost::math::asinh(arg, c99_error_policy());
2507 }
2508 template <class tag, class A1, class A2, class A3, class A4>
2509 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
2510     asinh
2511     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2512 {
2513    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2514    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2515    return asinh(value_type(arg));
2516 }
2517 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2518 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2519     acosh
2520     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2521 {
2522    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2523    return boost::math::acosh(arg, c99_error_policy());
2524 }
2525 template <class tag, class A1, class A2, class A3, class A4>
2526 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
2527     acosh
2528     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2529 {
2530    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2531    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2532    return acosh(value_type(arg));
2533 }
2534 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2535 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2536     atanh
2537     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2538 {
2539    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2540    return boost::math::atanh(arg, c99_error_policy());
2541 }
2542 template <class tag, class A1, class A2, class A3, class A4>
2543 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
2544     atanh
2545     BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2546 {
2547    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2548    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2549    return atanh(value_type(arg));
2550 }
2551 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2552 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2553 {
2554    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2555    return boost::math::cbrt(arg, c99_error_policy());
2556 }
2557 template <class tag, class A1, class A2, class A3, class A4>
2558 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)
2559 {
2560    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2561    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2562    return cbrt(value_type(arg));
2563 }
2564 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2565 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2566 {
2567    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2568    return boost::math::erf(arg, c99_error_policy());
2569 }
2570 template <class tag, class A1, class A2, class A3, class A4>
2571 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)
2572 {
2573    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2574    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2575    return erf(value_type(arg));
2576 }
2577 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2578 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2579 {
2580    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2581    return boost::math::erfc(arg, c99_error_policy());
2582 }
2583 template <class tag, class A1, class A2, class A3, class A4>
2584 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)
2585 {
2586    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2587    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2588    return erfc(value_type(arg));
2589 }
2590 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2591 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2592 {
2593    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2594    return boost::math::expm1(arg, c99_error_policy());
2595 }
2596 template <class tag, class A1, class A2, class A3, class A4>
2597 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)
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 expm1(value_type(arg));
2602 }
2603 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2604 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2605 {
2606    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2607    multiprecision::number<Backend, ExpressionTemplates>                                    result;
2608    result = boost::math::lgamma(arg, c99_error_policy());
2609    if ((boost::multiprecision::isnan)(result) && !(boost::multiprecision::isnan)(arg))
2610    {
2611       result = std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::infinity();
2612       errno  = ERANGE;
2613    }
2614    return result;
2615 }
2616 template <class tag, class A1, class A2, class A3, class A4>
2617 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)
2618 {
2619    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2620    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2621    return lgamma(value_type(arg));
2622 }
2623 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2624 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2625 {
2626    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2627    if ((arg == 0) && std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::has_infinity)
2628    {
2629       errno = ERANGE;
2630       return 1 / arg;
2631    }
2632    return boost::math::tgamma(arg, c99_error_policy());
2633 }
2634 template <class tag, class A1, class A2, class A3, class A4>
2635 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)
2636 {
2637    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2638    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2639    return tgamma(value_type(arg));
2640 }
2641 
2642 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2643 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2644 {
2645    return lround(arg);
2646 }
2647 template <class tag, class A1, class A2, class A3, class A4>
2648 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2649 {
2650    return lround(arg);
2651 }
2652 #ifndef BOOST_NO_LONG_LONG
2653 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2654 inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2655 {
2656    return llround(arg);
2657 }
2658 template <class tag, class A1, class A2, class A3, class A4>
2659 inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2660 {
2661    return llround(arg);
2662 }
2663 #endif
2664 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2665 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2666 {
2667    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2668    return boost::math::log1p(arg, c99_error_policy());
2669 }
2670 template <class tag, class A1, class A2, class A3, class A4>
2671 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)
2672 {
2673    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2674    detail::scoped_default_precision<value_type>                                          precision_guard(arg);
2675    return log1p(value_type(arg));
2676 }
2677 
2678 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2679 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)
2680 {
2681    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2682    return boost::math::nextafter(a, b, c99_error_policy());
2683 }
2684 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2685 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)
2686 {
2687    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2688    return nextafter                                                                        BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2689 }
2690 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2691 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)
2692 {
2693    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2694    return nextafter                                                                        BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2695 }
2696 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2697 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)
2698 {
2699    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2700    detail::scoped_default_precision<value_type>                                          precision_guard(a, b);
2701    return nextafter                                                                      BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2702 }
2703 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2704 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)
2705 {
2706    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2707    return boost::math::nextafter(a, b, c99_error_policy());
2708 }
2709 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2710 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)
2711 {
2712    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2713    return nexttoward                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2714 }
2715 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2716 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)
2717 {
2718    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2719    return nexttoward                                                                       BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2720 }
2721 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2722 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)
2723 {
2724    using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2725    detail::scoped_default_precision<value_type>                                          precision_guard(a, b);
2726    return nexttoward                                                                     BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2727 }
2728 #endif // BOOST_MP_MATH_AVAILABLE
2729 
2730 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2731 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2732 {
2733    static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2734    static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2735    using default_ops::eval_add;
2736    eval_add(result.backend(), a.backend(), b.backend());
2737    return result;
2738 }
2739 
2740 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2741 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2742 {
2743    static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2744    static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2745    using default_ops::eval_subtract;
2746    eval_subtract(result.backend(), a.backend(), b.backend());
2747    return result;
2748 }
2749 
2750 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2751 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2752 {
2753    static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2754    static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2755    using default_ops::eval_multiply;
2756    eval_multiply(result.backend(), a.backend(), b.backend());
2757    return result;
2758 }
2759 
2760 template <class B, expression_template_option ET, class I>
2761 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2762 add(number<B, ET>& result, const I& a, const I& b)
2763 {
2764    using default_ops::eval_add;
2765    using canonical_type = typename detail::canonical<I, B>::type;
2766    eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2767    return result;
2768 }
2769 
2770 template <class B, expression_template_option ET, class I>
2771 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2772 subtract(number<B, ET>& result, const I& a, const I& b)
2773 {
2774    using default_ops::eval_subtract;
2775    using canonical_type = typename detail::canonical<I, B>::type;
2776    eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2777    return result;
2778 }
2779 
2780 template <class B, expression_template_option ET, class I>
2781 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2782 multiply(number<B, ET>& result, const I& a, const I& b)
2783 {
2784    using default_ops::eval_multiply;
2785    using canonical_type = typename detail::canonical<I, B>::type;
2786    eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2787    return result;
2788 }
2789 
2790 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2791 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)
2792 {
2793    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2794    return std::move(trunc(number_type(v), pol));
2795 }
2796 
2797 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2798 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates> trunc(const number<Backend, ExpressionTemplates>& v, const Policy&)
2799 {
2800    using default_ops::eval_trunc;
2801    detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(v);
2802    number<Backend, ExpressionTemplates>                                                    result;
2803    eval_trunc(result.backend(), v.backend());
2804    return result;
2805 }
2806 
2807 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2808 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2809 {
2810    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2811    number_type                                                           r(trunc(v, pol));
2812    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2813       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", nullptr, number_type(v), 0, pol);
2814    return r.template convert_to<int>();
2815 }
2816 template <class tag, class A1, class A2, class A3, class A4>
2817 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2818 {
2819    return itrunc(v, boost::math::policies::policy<>());
2820 }
2821 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2822 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v, const Policy& pol)
2823 {
2824    number<Backend, ExpressionTemplates> r(trunc(v, pol));
2825    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2826       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", nullptr, v, 0, pol);
2827    return r.template convert_to<int>();
2828 }
2829 template <class Backend, expression_template_option ExpressionTemplates>
2830 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v)
2831 {
2832    return itrunc(v, boost::math::policies::policy<>());
2833 }
2834 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2835 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2836 {
2837    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2838    number_type                                                           r(trunc(v, pol));
2839    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2840       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", nullptr, number_type(v), 0L, pol);
2841    return r.template convert_to<long>();
2842 }
2843 template <class tag, class A1, class A2, class A3, class A4>
2844 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2845 {
2846    return ltrunc(v, boost::math::policies::policy<>());
2847 }
2848 template <class T, expression_template_option ExpressionTemplates, class Policy>
2849 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2850 {
2851    number<T, ExpressionTemplates> r(trunc(v, pol));
2852    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2853       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", nullptr, v, 0L, pol);
2854    return r.template convert_to<long>();
2855 }
2856 template <class T, expression_template_option ExpressionTemplates>
2857 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v)
2858 {
2859    return ltrunc(v, boost::math::policies::policy<>());
2860 }
2861 #ifndef BOOST_NO_LONG_LONG
2862 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2863 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2864 {
2865    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2866    number_type                                                           r(trunc(v, pol));
2867    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2868       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", nullptr, number_type(v), 0LL, pol);
2869    return r.template convert_to<long long>();
2870 }
2871 template <class tag, class A1, class A2, class A3, class A4>
2872 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2873 {
2874    return lltrunc(v, boost::math::policies::policy<>());
2875 }
2876 template <class T, expression_template_option ExpressionTemplates, class Policy>
2877 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2878 {
2879    number<T, ExpressionTemplates> r(trunc(v, pol));
2880    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2881       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", nullptr, v, 0LL, pol);
2882    return r.template convert_to<long long>();
2883 }
2884 template <class T, expression_template_option ExpressionTemplates>
2885 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v)
2886 {
2887    return lltrunc(v, boost::math::policies::policy<>());
2888 }
2889 #endif
2890 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2891 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)
2892 {
2893    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2894    return std::move(round(static_cast<number_type>(v), pol));
2895 }
2896 template <class T, expression_template_option ExpressionTemplates, class Policy>
2897 inline BOOST_MP_CXX14_CONSTEXPR number<T, ExpressionTemplates> round(const number<T, ExpressionTemplates>& v, const Policy&)
2898 {
2899    using default_ops::eval_round;
2900    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2901    number<T, ExpressionTemplates>                                                    result;
2902    eval_round(result.backend(), v.backend());
2903    return result;
2904 }
2905 
2906 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2907 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2908 {
2909    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2910    number_type                                                           r(round(v, pol));
2911    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2912       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, number_type(v), 0, pol);
2913    return r.template convert_to<int>();
2914 }
2915 template <class tag, class A1, class A2, class A3, class A4>
2916 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v)
2917 {
2918    return iround(v, boost::math::policies::policy<>());
2919 }
2920 template <class T, expression_template_option ExpressionTemplates, class Policy>
2921 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2922 {
2923    number<T, ExpressionTemplates> r(round(v, pol));
2924    if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2925       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, v, 0, pol);
2926    return r.template convert_to<int>();
2927 }
2928 template <class T, expression_template_option ExpressionTemplates>
2929 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v)
2930 {
2931    return iround(v, boost::math::policies::policy<>());
2932 }
2933 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2934 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2935 {
2936    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2937    number_type                                                           r(round(v, pol));
2938    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2939       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", nullptr, number_type(v), 0L, pol);
2940    return r.template convert_to<long>();
2941 }
2942 template <class tag, class A1, class A2, class A3, class A4>
2943 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v)
2944 {
2945    return lround(v, boost::math::policies::policy<>());
2946 }
2947 template <class T, expression_template_option ExpressionTemplates, class Policy>
2948 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2949 {
2950    number<T, ExpressionTemplates> r(round(v, pol));
2951    if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2952       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", nullptr, v, 0L, pol);
2953    return r.template convert_to<long>();
2954 }
2955 template <class T, expression_template_option ExpressionTemplates>
2956 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v)
2957 {
2958    return lround(v, boost::math::policies::policy<>());
2959 }
2960 #ifndef BOOST_NO_LONG_LONG
2961 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2962 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2963 {
2964    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2965    number_type                                                           r(round(v, pol));
2966    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2967       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, number_type(v), 0LL, pol);
2968    return r.template convert_to<long long>();
2969 }
2970 template <class tag, class A1, class A2, class A3, class A4>
2971 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v)
2972 {
2973    return llround(v, boost::math::policies::policy<>());
2974 }
2975 template <class T, expression_template_option ExpressionTemplates, class Policy>
2976 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2977 {
2978    number<T, ExpressionTemplates> r(round(v, pol));
2979    if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2980       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, v, 0LL, pol);
2981    return r.template convert_to<long long>();
2982 }
2983 template <class T, expression_template_option ExpressionTemplates>
2984 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v)
2985 {
2986    return llround(v, boost::math::policies::policy<>());
2987 }
2988 #endif
2989 //
2990 // frexp does not return an expression template since we require the
2991 // integer argument to be evaluated even if the returned value is
2992 // not assigned to anything...
2993 //
2994 template <class T, expression_template_option ExpressionTemplates>
2995 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)
2996 {
2997    using default_ops::eval_frexp;
2998    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2999    number<T, ExpressionTemplates>                                                    result;
3000    eval_frexp(result.backend(), v.backend(), pint);
3001    return result;
3002 }
3003 template <class tag, class A1, class A2, class A3, class A4>
3004 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
3005 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, short* pint)
3006 {
3007    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3008    return std::move(frexp(static_cast<number_type>(v), pint));
3009 }
3010 template <class T, expression_template_option ExpressionTemplates>
3011 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)
3012 {
3013    using default_ops::eval_frexp;
3014    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3015    number<T, ExpressionTemplates>                                                    result;
3016    eval_frexp(result.backend(), v.backend(), pint);
3017    return result;
3018 }
3019 template <class tag, class A1, class A2, class A3, class A4>
3020 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
3021 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, int* pint)
3022 {
3023    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3024    return std::move(frexp(static_cast<number_type>(v), pint));
3025 }
3026 template <class T, expression_template_option ExpressionTemplates>
3027 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)
3028 {
3029    using default_ops::eval_frexp;
3030    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3031    number<T, ExpressionTemplates>                                                    result;
3032    eval_frexp(result.backend(), v.backend(), pint);
3033    return result;
3034 }
3035 template <class tag, class A1, class A2, class A3, class A4>
3036 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
3037 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long* pint)
3038 {
3039    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3040    return std::move(frexp(static_cast<number_type>(v), pint));
3041 }
3042 template <class T, expression_template_option ExpressionTemplates>
3043 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)
3044 {
3045    using default_ops::eval_frexp;
3046    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3047    number<T, ExpressionTemplates>                                                    result;
3048    eval_frexp(result.backend(), v.backend(), pint);
3049    return result;
3050 }
3051 template <class tag, class A1, class A2, class A3, class A4>
3052 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
3053 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long long* pint)
3054 {
3055    using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3056    return std::move(frexp(static_cast<number_type>(v), pint));
3057 }
3058 //
3059 // modf does not return an expression template since we require the
3060 // second argument to be evaluated even if the returned value is
3061 // not assigned to anything...
3062 //
3063 template <class T, expression_template_option ExpressionTemplates>
3064 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)
3065 {
3066    using default_ops::eval_modf;
3067    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3068    number<T, ExpressionTemplates>                                                    result;
3069    eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : nullptr);
3070    return result;
3071 }
3072 template <class T, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
3073 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)
3074 {
3075    using default_ops::eval_modf;
3076    detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3077    number<T, ExpressionTemplates>                                                    result, arg(v);
3078    eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : nullptr);
3079    return result;
3080 }
3081 
3082 //
3083 // Integer square root:
3084 //
3085 template <class B, expression_template_option ExpressionTemplates>
3086 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3087 sqrt(const number<B, ExpressionTemplates>& x)
3088 {
3089    using default_ops::eval_integer_sqrt;
3090    number<B, ExpressionTemplates> s, r;
3091    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3092    return s;
3093 }
3094 template <class tag, class A1, class A2, class A3, class A4>
3095 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
3096          sqrt(const detail::expression<tag, A1, A2, A3, A4>& arg)
3097 {
3098    using default_ops::eval_integer_sqrt;
3099    using result_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3100    detail::scoped_default_precision<result_type> precision_guard(arg);
3101    result_type                                   result, v(arg), r;
3102    eval_integer_sqrt(result.backend(), r.backend(), v.backend());
3103    return result;
3104 }
3105 
3106 //
3107 // fma:
3108 //
3109 
3110 namespace default_ops {
3111 
3112 struct fma_func
3113 {
3114    template <class B, class T, class U, class V>
3115    BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, const V& c) const
3116    {
3117       eval_multiply_add(result, a, b, c);
3118    }
3119 };
3120 
3121 } // namespace default_ops
3122 
3123 template <class Backend, class U, class V>
3124 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3125         (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3126         (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3127         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3128     detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V> >::type
3129 fma(const number<Backend, et_on>& a, const U& b, const V& c)
3130 {
3131    return detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V>(
3132        default_ops::fma_func(), a, b, c);
3133 }
3134 
3135 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U, class V>
3136 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3137         (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3138         (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3139         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3140     detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V> >::type
3141 fma(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, const V& c)
3142 {
3143    return detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V>(
3144        default_ops::fma_func(), a, b, c);
3145 }
3146 
3147 template <class Backend, class U, class V>
3148 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3149         (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3150         (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3151         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3152     number<Backend, et_off> >::type
3153 fma(const number<Backend, et_off>& a, const U& b, const V& c)
3154 {
3155    using default_ops::eval_multiply_add;
3156    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3157    number<Backend, et_off>                                                    result;
3158    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));
3159    return result;
3160 }
3161 
3162 template <class U, class Backend, class V>
3163 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3164         (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3165         boost::multiprecision::detail::is_arithmetic<U>::value &&
3166         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3167     detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V> >::type
3168 fma(const U& a, const number<Backend, et_on>& b, const V& c)
3169 {
3170    return detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V>(
3171        default_ops::fma_func(), a, b, c);
3172 }
3173 
3174 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
3175 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3176         (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3177         boost::multiprecision::detail::is_arithmetic<U>::value &&
3178         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3179     detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V> >::type
3180 fma(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, const V& c)
3181 {
3182    return detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V>(
3183        default_ops::fma_func(), a, b, c);
3184 }
3185 
3186 template <class U, class Backend, class V>
3187 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3188         (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3189         boost::multiprecision::detail::is_arithmetic<U>::value &&
3190         (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3191     number<Backend, et_off> >::type
3192 fma(const U& a, const number<Backend, et_off>& b, const V& c)
3193 {
3194    using default_ops::eval_multiply_add;
3195    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3196    number<Backend, et_off>                                                    result;
3197    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));
3198    return result;
3199 }
3200 
3201 template <class U, class V, class Backend>
3202 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3203         (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3204         boost::multiprecision::detail::is_arithmetic<U>::value &&
3205         boost::multiprecision::detail::is_arithmetic<V>::value,
3206     detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> > >::type
3207 fma(const U& a, const V& b, const number<Backend, et_on>& c)
3208 {
3209    return detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> >(
3210        default_ops::fma_func(), a, b, c);
3211 }
3212 
3213 template <class U, class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3214 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3215         (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3216         boost::multiprecision::detail::is_arithmetic<U>::value &&
3217         boost::multiprecision::detail::is_arithmetic<V>::value,
3218     detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
3219 fma(const U& a, const V& b, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& c)
3220 {
3221    return detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(
3222        default_ops::fma_func(), a, b, c);
3223 }
3224 
3225 template <class U, class V, class Backend>
3226 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3227         (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3228         boost::multiprecision::detail::is_arithmetic<U>::value &&
3229         boost::multiprecision::detail::is_arithmetic<V>::value,
3230         number<Backend, et_off> >::type
3231 fma(const U& a, const V& b, const number<Backend, et_off>& c)
3232 {
3233    using default_ops::eval_multiply_add;
3234    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3235    number<Backend, et_off>                                                    result;
3236    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));
3237    return result;
3238 }
3239 
3240 namespace default_ops {
3241 
3242 struct remquo_func
3243 {
3244    template <class B, class T, class U>
3245    BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, int* pi) const
3246    {
3247       eval_remquo(result, a, b, pi);
3248    }
3249 };
3250 
3251 } // namespace default_ops
3252 
3253 template <class Backend, class U>
3254 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3255     number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3256     detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*> >::type
3257 remquo(const number<Backend, et_on>& a, const U& b, int* pi)
3258 {
3259    return detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*>(
3260        default_ops::remquo_func(), a, b, pi);
3261 }
3262 
3263 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U>
3264 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3265     number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point,
3266     detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*> >::type
3267 remquo(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, int* pi)
3268 {
3269    return detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*>(
3270        default_ops::remquo_func(), a, b, pi);
3271 }
3272 
3273 template <class U, class Backend>
3274 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3275     (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3276     detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*> >::type
3277 remquo(const U& a, const number<Backend, et_on>& b, int* pi)
3278 {
3279    return detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*>(
3280        default_ops::remquo_func(), a, b, pi);
3281 }
3282 
3283 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3284 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3285     (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,
3286     detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*> >::type
3287 remquo(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, int* pi)
3288 {
3289    return detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*>(
3290        default_ops::remquo_func(), a, b, pi);
3291 }
3292 
3293 template <class Backend, class U>
3294 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3295     number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3296     number<Backend, et_off> >::type
3297 remquo(const number<Backend, et_off>& a, const U& b, int* pi)
3298 {
3299    using default_ops::eval_remquo;
3300    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3301    number<Backend, et_off>                                                    result;
3302    eval_remquo(result.backend(), a.backend(), number<Backend, et_off>::canonical_value(b), pi);
3303    return result;
3304 }
3305 template <class U, class Backend>
3306 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3307     (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3308     number<Backend, et_off> >::type
3309 remquo(const U& a, const number<Backend, et_off>& b, int* pi)
3310 {
3311    using default_ops::eval_remquo;
3312    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3313    number<Backend, et_off>                                                    result;
3314    eval_remquo(result.backend(), number<Backend, et_off>::canonical_value(a), b.backend(), pi);
3315    return result;
3316 }
3317 
3318 template <class B, expression_template_option ExpressionTemplates>
3319 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3320 sqrt(const number<B, ExpressionTemplates>& x, number<B, ExpressionTemplates>& r)
3321 {
3322    using default_ops::eval_integer_sqrt;
3323    detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(x, r);
3324    number<B, ExpressionTemplates>                                                    s;
3325    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3326    return s;
3327 }
3328 template <class B, expression_template_option ExpressionTemplates, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3329 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3330 sqrt(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& arg, number<B, ExpressionTemplates>& r)
3331 {
3332    using default_ops::eval_integer_sqrt;
3333    detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(r);
3334    number<B, ExpressionTemplates>                                                    s;
3335    number<B, ExpressionTemplates>                                                    x(arg);
3336    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3337    return s;
3338 }
3339 
3340 // clang-format off
3341 //
3342 // Regrettably, when the argument to a function is an rvalue we must return by value, and not return an
3343 // expression template, otherwise we can end up with dangling references.
3344 // See https://github.com/boostorg/multiprecision/issues/175.
3345 //
3346 #define UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3347    template <class Backend>                                                                                                                                                                               \
3348    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> > ::type                                                                      \
3349    func(number<Backend, et_on>&& arg)                                                                                                                                                                     \
3350    {                                                                                                                                                                                                      \
3351       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg);                                                                                                    \
3352       number<Backend, et_on>                                                    result;                                                                                                                  \
3353       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                         \
3354       BOOST_JOIN(eval_, func)(result.backend(), arg.backend());                                                                                                                                                                  \
3355       return result;                                                                                                                                                                       \
3356    }                                                                                                                                                                                                      \
3357 
3358 #define BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3359    template <class Backend>                                                                                                                                                                                                                                \
3360    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)                                                                                              \
3361    {                                                                                                                                                                                                                                                       \
3362       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a);                                                                                                                                                  \
3363       number<Backend, et_on>                                                    result;                                                                                                                                                                   \
3364       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3365       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3366       return result;                                                                                                                                                                                                                        \
3367    }                                                                                                                                                                                                                                                       \
3368    template <class Backend>                                                                                                                                                                                                                                \
3369    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)                                                                                              \
3370    {                                                                                                                                                                                                                                                       \
3371       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a);                                                                                                                                                  \
3372       number<Backend, et_on>                                                    result;                                                                                                                                                                   \
3373       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3374       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3375       return result;                                                                                                                                                                                                                        \
3376    }                                                                                                                                                                                                                                                       \
3377    template <class Backend>                                                                                                                                                                                                                                \
3378    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)                                                                                              \
3379    {                                                                                                                                                                                                                                                       \
3380       detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a);                                                                                                                                                  \
3381       number<Backend, et_on>                                                    result;                                                                                                                                                                   \
3382       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3383       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3384       return result;                                                                                                                                                                                                                        \
3385    }                                                                                                                                                                                                                                                       \
3386    template <class Backend, class tag, class A1, class A2, class A3, class A4>                                                                                                                                                                             \
3387    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),                           \
3388            number<Backend, et_on> > ::type                                                                                                                                                                       \
3389    func(number<Backend, et_on>&& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                    \
3390    {                                                                                                                                                                                                                                                       \
3391       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3392              number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3393    }                                                                                                                                                                                                                                                       \
3394    template <class tag, class A1, class A2, class A3, class A4, class Backend>                                                                                                                                                                             \
3395    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),                           \
3396            number<Backend, et_on> > ::type                                                                                                                                                                       \
3397    func(const detail::expression<tag, A1, A2, A3, A4>& arg, number<Backend, et_on>&& a)                                                                                    \
3398    {                                                                                                                                                                                                                                                       \
3399       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3400              detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3401    }                                                                                                                                                                                                                                                       \
3402    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3403    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3404            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3405            number<Backend, et_on> >::type                                                                                                                                                                                                     \
3406    func(number<Backend, et_on>&& arg, const Arithmetic& a)                                                                                                                                               \
3407    {                                                                                                                                                                                                                                                       \
3408       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>,                                                                                                                                                      \
3409              number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                                                         \
3410    }                                                                                                                                                                                                                                                       \
3411    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3412    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3413            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3414            number<Backend, et_on> > ::type                                                                                                                                                                                                    \
3415    func(const Arithmetic& arg, number<Backend, et_on>&& a)                                                                                                                                              \
3416    {                                                                                                                                                                                                                                                       \
3417       return detail::expression<                                                                                                                                                                                                                           \
3418                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3419              Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                                                          \
3420    }                                                                                                                                                                                                                                                       \
3421 
3422 
3423 #define UNARY_OP_FUNCTOR(func, category)                                                                                                                                                                  \
3424    namespace detail {                                                                                                                                                                                     \
3425    template <class Backend>                                                                                                                                                                               \
3426    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                                                                                                                                                  \
3427    {                                                                                                                                                                                                      \
3428       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const                                                                                                                                          \
3429       {                                                                                                                                                                                                   \
3430          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                      \
3431          BOOST_JOIN(eval_, func)                                                                                                                                                                          \
3432          (result, arg);                                                                                                                                                                                   \
3433       }                                                                                                                                                                                                   \
3434       template <class U>                                                                                                                                                                                  \
3435       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg) const                                                                                                                                                \
3436       {                                                                                                                                                                                                   \
3437          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                      \
3438          Backend temp;                                                                                                                                                                                    \
3439          BOOST_JOIN(eval_, func)                                                                                                                                                                          \
3440          (temp, arg);                                                                                                                                                                                     \
3441          result = std::move(temp);                                                                                                                                                                                   \
3442       }                                                                                                                                                                                                   \
3443    };                                                                                                                                                                                                     \
3444    }                                                                                                                                                                                                      \
3445                                                                                                                                                                                                           \
3446    template <class tag, class A1, class A2, class A3, class A4>                                                                                                                                           \
3447    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category,                                                                     \
3448                                                         detail::expression<detail::function,                                                                                                              \
3449                                                         detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,            \
3450                                                         detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                \
3451    func(const detail::expression<tag, A1, A2, A3, A4>& arg)                                                                    \
3452    {                                                                                                                                                                                                      \
3453       return detail::expression<                                                                                                                                                                          \
3454                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                               \
3455              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); \
3456    }                                                                                                                                                                                                      \
3457    template <class Backend>                                                                                                                                                                               \
3458    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category,                                                                                                      \
3459           detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, number<Backend, et_on> > > ::type                                                       \
3460    func(const number<Backend, et_on>& arg)                                                                                                                                                                \
3461    {                                                                                                                                                                                                      \
3462       return detail::expression<                                                                                                                                                                          \
3463                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                     \
3464              number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg);                                                                                        \
3465    }                                                                                                                                                                                                      \
3466    template <class Backend>                                                                                                                                                                               \
3467    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                    \
3468        boost::multiprecision::number_category<Backend>::value == category,                                                                                                                                \
3469        number<Backend, et_off> >::type                                                                                                                                                                    \
3470    func(const number<Backend, et_off>& arg)                                                                                                                                                               \
3471    {                                                                                                                                                                                                      \
3472       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                    \
3473       number<Backend, et_off>                                                    result;                                                                                                                  \
3474       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                         \
3475       BOOST_JOIN(eval_, func)(result.backend(), arg.backend());                                                                                                                                                                  \
3476       return result;                                                                                                                                                                       \
3477    }\
3478    UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3479 
3480 #define BINARY_OP_FUNCTOR(func, category)                                                                                                                                                                                                                  \
3481    namespace detail {                                                                                                                                                                                                                                      \
3482    template <class Backend>                                                                                                                                                                                                                                \
3483    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                                                                                                                                                                                                   \
3484    {                                                                                                                                                                                                                                                       \
3485       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Backend& a) const                                                                                                                                                                         \
3486       {                                                                                                                                                                                                                                                    \
3487          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3488          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3489          (result, arg, a);                                                                                                                                                                                                                                 \
3490       }                                                                                                                                                                                                                                                    \
3491       template <class Arithmetic>                                                                                                                                                                                                                          \
3492       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Arithmetic& a) const                                                                                                                                                                      \
3493       {                                                                                                                                                                                                                                                    \
3494          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3495          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3496          (result, arg, number<Backend>::canonical_value(a));                                                                                                                                                                                               \
3497       }                                                                                                                                                                                                                                                    \
3498       template <class Arithmetic>                                                                                                                                                                                                                          \
3499       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Arithmetic& arg, const Backend& a) const                                                                                                                                                                      \
3500       {                                                                                                                                                                                                                                                    \
3501          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3502          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3503          (result, number<Backend>::canonical_value(arg), a);                                                                                                                                                                                               \
3504       }                                                                                                                                                                                                                                                    \
3505       template <class U>                                                                                                                                                                                                                                   \
3506       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Backend& a) const                                                                                                                                                                               \
3507       {                                                                                                                                                                                                                                                    \
3508          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3509          Backend r;                                                                                                                                                                                                                                        \
3510          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3511          (r, arg, a);                                                                                                                                                                                                                                      \
3512          result = std::move(r);                                                                                                                                                                                                                                       \
3513       }                                                                                                                                                                                                                                                    \
3514       template <class U, class Arithmetic>                                                                                                                                                                                                                 \
3515       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Arithmetic& a) const                                                                                                                                                                            \
3516       {                                                                                                                                                                                                                                                    \
3517          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3518          Backend r;                                                                                                                                                                                                                                        \
3519          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3520          (r, arg, number<Backend>::canonical_value(a));                                                                                                                                                                                                    \
3521          result = std::move(r);                                                                                                                                                                                                                                       \
3522       }                                                                                                                                                                                                                                                    \
3523       template <class U, class Arithmetic>                                                                                                                                                                                                                 \
3524       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Arithmetic& arg, const Backend& a) const                                                                                                                                                                            \
3525       {                                                                                                                                                                                                                                                    \
3526          using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                       \
3527          Backend r;                                                                                                                                                                                                                                        \
3528          BOOST_JOIN(eval_, func)                                                                                                                                                                                                                           \
3529          (r, number<Backend>::canonical_value(arg), a);                                                                                                                                                                                                    \
3530          result = std::move(r);                                                                                                                                                                                                                                       \
3531       }                                                                                                                                                                                                                                                    \
3532    };                                                                                                                                                                                                                                                      \
3533    }                                                                                                                                                                                                                                                       \
3534    template <class Backend>                                                                                                                                                                                                                                \
3535    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, detail::expression<detail::function, \
3536          detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, number<Backend, et_on>, number<Backend, et_on> > > ::type                                                                                                                                                                \
3537    func(const number<Backend, et_on>& arg, const number<Backend, et_on>& a)                                                                                              \
3538    {                                                                                                                                                                                                                                                       \
3539       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3540              number<Backend, et_on>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                                              \
3541    }                                                                                                                                                                                                                                                       \
3542    template <class Backend, class tag, class A1, class A2, class A3, class A4>                                                                                                                                                                             \
3543    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),                           \
3544            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                                                                                                                                                                       \
3545    func(const number<Backend, et_on>& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                    \
3546    {                                                                                                                                                                                                                                                       \
3547       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3548              number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3549    }                                                                                                                                                                                                                                                       \
3550    template <class tag, class A1, class A2, class A3, class A4, class Backend>                                                                                                                                                                             \
3551    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),                           \
3552            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                                                                                                                                                                       \
3553    func(const detail::expression<tag, A1, A2, A3, A4>& arg, const number<Backend, et_on>& a)                                                                                    \
3554    {                                                                                                                                                                                                                                                       \
3555       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3556              detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                             \
3557    }                                                                                                                                                                                                                                                       \
3558    template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>                                                                                                                                    \
3559    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),                                                                          \
3560            detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3561            detail::expression<tag, A1, A2, A3, A4>, detail::expression<tagb, A1b, A2b, A3b, A4b> > > ::type                                                                                                                                                 \
3562    func(const detail::expression<tag, A1, A2, A3, A4>& arg, const detail::expression<tagb, A1b, A2b, A3b, A4b>& a)                                        \
3563    {                                                                                                                                                                                                                                                       \
3564       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>,                                                                                \
3565              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); \
3566    }                                                                                                                                                                                                                                                       \
3567    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3568    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3569            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3570            detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3571            number<Backend, et_on>, Arithmetic> > ::type                                                                                                                                                                                                     \
3572    func(const number<Backend, et_on>& arg, const Arithmetic& a)                                                                                                                                               \
3573    {                                                                                                                                                                                                                                                       \
3574       return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>,                                                                                                                                                      \
3575              number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a);                                                                                                                         \
3576    }                                                                                                                                                                                                                                                       \
3577    template <class tag, class A1, class A2, class A3, class A4, class Arithmetic>                                                                                                                                                                          \
3578    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3579            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),                                              \
3580            detail::expression<                                                                                                                                                                                                                             \
3581                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3582            detail::expression<tag, A1, A2, A3, A4>, Arithmetic> > ::type                                                                                                                                                                                    \
3583    func(const detail::expression<tag, A1, A2, A3, A4>& arg, const Arithmetic& a)                                                                                                             \
3584    {                                                                                                                                                                                                                                                       \
3585       return detail::expression<                                                                                                                                                                                                                           \
3586                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3587              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);                                  \
3588    }                                                                                                                                                                                                                                                       \
3589    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3590    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3591            is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category),                                                                                                                     \
3592            detail::expression<                                                                                                                                                                                                                             \
3593                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                        \
3594            Arithmetic, number<Backend, et_on> > > ::type                                                                                                                                                                                                    \
3595    func(const Arithmetic& arg, const number<Backend, et_on>& a)                                                                                                                                              \
3596    {                                                                                                                                                                                                                                                       \
3597       return detail::expression<                                                                                                                                                                                                                           \
3598                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                                                      \
3599              Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                                                          \
3600    }                                                                                                                                                                                                                                                       \
3601    template <class tag, class A1, class A2, class A3, class A4, class Arithmetic>                                                                                                                                                                          \
3602        inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                        \
3603            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),                                              \
3604            detail::expression<                                                                                                                                                                                                                             \
3605                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                  \
3606            Arithmetic, detail::expression<tag, A1, A2, A3, A4> > > ::type                                                                                                                                                                                   \
3607    func(const Arithmetic& arg, const detail::expression<tag, A1, A2, A3, A4>& a)                                                                                                            \
3608    {                                                                                                                                                                                                                                                       \
3609       return detail::expression<                                                                                                                                                                                                                           \
3610                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                                                                \
3611              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);                                   \
3612    }                                                                                                                                                                                                                                                       \
3613    template <class Backend>                                                                                                                                                                                                                                \
3614    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category), number<Backend, et_off> >::type                                                                                                                                                                                             \
3615    func(const number<Backend, et_off>& arg, const number<Backend, et_off>& a)                                                                                                                                                                              \
3616    {                                                                                                                                                                                                                                                       \
3617       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);                                                                                                                                                  \
3618       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3619       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3620       BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend());                                                                                                                                                                                                      \
3621       return result;                                                                                                                                                                                                                        \
3622    }                                                                                                                                                                                                                                                       \
3623    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3624    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                            \
3625        is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),                                                                                                                        \
3626        number<Backend, et_off> >::type                                                                                                                                                                                                                     \
3627    func(const number<Backend, et_off>& arg, const Arithmetic& a)                                                                                                                                                                                           \
3628    {                                                                                                                                                                                                                                                       \
3629       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                                                                     \
3630       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3631       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3632       BOOST_JOIN(eval_, func)                                                                                                                                                                                                                              \
3633       (result.backend(), arg.backend(), number<Backend, et_off>::canonical_value(a));                                                                                                                                                                      \
3634       return result;                                                                                                                                                                                                                        \
3635    }                                                                                                                                                                                                                                                       \
3636    template <class Backend, class Arithmetic>                                                                                                                                                                                                              \
3637    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                                                            \
3638        is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category),                                                                                                                        \
3639        number<Backend, et_off> >::type                                                                                                                                                                                                                     \
3640    func(const Arithmetic& a, const number<Backend, et_off>& arg)                                                                                                                                                                                           \
3641    {                                                                                                                                                                                                                                                       \
3642       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);                                                                                                                                                     \
3643       number<Backend, et_off>                                                    result;                                                                                                                                                                   \
3644       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                                                          \
3645       BOOST_JOIN(eval_, func)                                                                                                                                                                                                                              \
3646       (result.backend(), number<Backend, et_off>::canonical_value(a), arg.backend());                                                                                                                                                                      \
3647       return result;                                                                                                                                                                                                                        \
3648    }\
3649    BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)
3650 
3651 #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)                                                                                                                                                            \
3652    template <class tag, class A1, class A2, class A3, class A4>                                                                                                                                                     \
3653        inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                 \
3654            (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),                                                                                                                          \
3655            detail::expression<                                                                                                                                                                                      \
3656                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                           \
3657            detail::expression<tag, A1, A2, A3, A4>, Arg2> > ::type                                                                                                                                                   \
3658                                                            func(const detail::expression<tag, A1, A2, A3, A4>& arg, Arg2 const& a)                                                                                  \
3659    {                                                                                                                                                                                                                \
3660       return detail::expression<                                                                                                                                                                                    \
3661                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>,                                         \
3662              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); \
3663    }                                                                                                                                                                                                                \
3664    template <class Backend>                                                                                                                                                                                         \
3665        inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                 \
3666            (number_category<Backend>::value == category),                                                                                                                                                           \
3667            detail::expression<                                                                                                                                                                                      \
3668                detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                                 \
3669            number<Backend, et_on>, Arg2> > ::type                                                                                                                                                                    \
3670                                           func(const number<Backend, et_on>& arg, Arg2 const& a)                                                                                                                    \
3671    {                                                                                                                                                                                                                \
3672       return detail::expression<                                                                                                                                                                                    \
3673                  detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>,                                                                                                               \
3674              number<Backend, et_on>, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a);                                                                                        \
3675    }                                                                                                                                                                                                                \
3676    template <class Backend>                                                                                                                                                                                         \
3677    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<                                                                                                                                                                                     \
3678        (number_category<Backend>::value == category),                                                                                                                                                               \
3679        number<Backend, et_off> >::type                                                                                                                                                                              \
3680    func(const number<Backend, et_off>& arg, Arg2 const& a)                                                                                                                                                          \
3681    {                                                                                                                                                                                                                \
3682       detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a);                                                                                                           \
3683       number<Backend, et_off>                                                    result;                                                                                                                            \
3684       using default_ops::BOOST_JOIN(eval_, func);                                                                                                                                                                   \
3685       BOOST_JOIN(eval_, func)                                                                                                                                                                                       \
3686       (result.backend(), arg.backend(), a);                                                                                                                                                                         \
3687       return result;                                                                                                                                                                                 \
3688    }
3689 
3690 #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)                  \
3691    namespace detail {                                                   \
3692    template <class Backend>                                             \
3693    struct BOOST_JOIN(category, BOOST_JOIN(func, _funct))                \
3694    {                                                                    \
3695       template <class Arg>                                              \
3696       BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, Backend const& arg, Arg a) const \
3697       {                                                                 \
3698          using default_ops::BOOST_JOIN(eval_, func);                    \
3699          BOOST_JOIN(eval_, func)                                        \
3700          (result, arg, a);                                              \
3701       }                                                                 \
3702       template <class U, class Arg>                                              \
3703       BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, Backend const& arg, Arg a) const \
3704       {                                                                 \
3705          using default_ops::BOOST_JOIN(eval_, func);                    \
3706          Backend temp;                                                  \
3707          BOOST_JOIN(eval_, func)                                        \
3708          (temp, arg, a);                                                \
3709          result = std::move(temp);                                  \
3710       }                                                                 \
3711    };                                                                   \
3712    }                                                                    \
3713                                                                         \
3714    HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)
3715 
3716 // clang-format on
3717 
3718 namespace detail {
3719 template <class Backend>
3720 struct abs_funct
3721 {
3722    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3723    {
3724       using default_ops::eval_abs;
3725       eval_abs(result, arg);
3726    }
3727 };
3728 template <class Backend>
3729 struct conj_funct
3730 {
3731    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3732    {
3733       using default_ops::eval_conj;
3734       eval_conj(result, arg);
3735    }
3736    //
3737    // To allow for mixed complex/scalar arithmetic where conj is called on the scalar type (as in Eigen)
3738    // we provide an overload that will promote the arg to the distination type:
3739    //
3740    template <class Other>
3741    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_constructible<Other, Backend>::value>::type operator()(Other& result, const Backend& arg) const
3742    {
3743       using default_ops::eval_conj;
3744       Other t(arg);
3745       eval_conj(result, t);
3746    }
3747 };
3748 template <class Backend>
3749 struct proj_funct
3750 {
3751    BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3752    {
3753       using default_ops::eval_proj;
3754       eval_proj(result, arg);
3755    }
3756 };
3757 
3758 } // namespace detail
3759 
3760 template <class tag, class A1, class A2, class A3, class A4>
3761 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,
3762                                     detail::expression<
3763                                         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
3764 abs(const detail::expression<tag, A1, A2, A3, A4>& arg)
3765 {
3766    return detail::expression<
3767        detail::function, detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3768        detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3769 }
3770 template <class Backend>
3771 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex,
3772                              detail::expression<
3773                                  detail::function, detail::abs_funct<Backend>, number<Backend, et_on> > >::type
3774 abs(const number<Backend, et_on>& arg)
3775 {
3776    return detail::expression<
3777        detail::function, detail::abs_funct<Backend>, number<Backend, et_on> >(
3778        detail::abs_funct<Backend>(), arg);
3779 }
3780 template <class Backend>
3781 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, number<Backend, et_off> >::type
3782 abs(const number<Backend, et_off>& arg)
3783 {
3784    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3785    number<Backend, et_off>                                                    result;
3786    using default_ops::eval_abs;
3787    eval_abs(result.backend(), arg.backend());
3788    return result;
3789 }
3790 
3791 template <class tag, class A1, class A2, class A3, class A4>
3792 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3793     detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3794 conj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3795 {
3796    return detail::expression<
3797        detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3798        detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3799 }
3800 template <class Backend>
3801 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3802     detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >
3803 conj(const number<Backend, et_on>& arg)
3804 {
3805    return detail::expression<
3806        detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >(
3807        detail::conj_funct<Backend>(), arg);
3808 }
3809 template <class Backend>
3810 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3811 conj(const number<Backend, et_off>& arg)
3812 {
3813    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3814    number<Backend, et_off>                                                    result;
3815    using default_ops::eval_conj;
3816    eval_conj(result.backend(), arg.backend());
3817    return result;
3818 }
3819 
3820 template <class tag, class A1, class A2, class A3, class A4>
3821 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3822     detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3823 proj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3824 {
3825    return detail::expression<
3826        detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3827        detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3828 }
3829 template <class Backend>
3830 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3831     detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >
3832 proj(const number<Backend, et_on>& arg)
3833 {
3834    return detail::expression<
3835        detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >(
3836        detail::proj_funct<Backend>(), arg);
3837 }
3838 template <class Backend>
3839 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3840 proj(const number<Backend, et_off>& arg)
3841 {
3842    detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3843    number<Backend, et_off>                                                    result;
3844    using default_ops::eval_proj;
3845    eval_proj(result.backend(), arg.backend());
3846    return result;
3847 }
3848 
3849 UNARY_OP_FUNCTOR(fabs, number_kind_floating_point)
3850 UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point)
3851 UNARY_OP_FUNCTOR(floor, number_kind_floating_point)
3852 UNARY_OP_FUNCTOR(ceil, number_kind_floating_point)
3853 UNARY_OP_FUNCTOR(trunc, number_kind_floating_point)
3854 UNARY_OP_FUNCTOR(round, number_kind_floating_point)
3855 UNARY_OP_FUNCTOR(exp, number_kind_floating_point)
3856 UNARY_OP_FUNCTOR(exp2, number_kind_floating_point)
3857 UNARY_OP_FUNCTOR(log, number_kind_floating_point)
3858 UNARY_OP_FUNCTOR(log10, number_kind_floating_point)
3859 UNARY_OP_FUNCTOR(cos, number_kind_floating_point)
3860 UNARY_OP_FUNCTOR(sin, number_kind_floating_point)
3861 UNARY_OP_FUNCTOR(tan, number_kind_floating_point)
3862 UNARY_OP_FUNCTOR(asin, number_kind_floating_point)
3863 UNARY_OP_FUNCTOR(acos, number_kind_floating_point)
3864 UNARY_OP_FUNCTOR(atan, number_kind_floating_point)
3865 UNARY_OP_FUNCTOR(cosh, number_kind_floating_point)
3866 UNARY_OP_FUNCTOR(sinh, number_kind_floating_point)
3867 UNARY_OP_FUNCTOR(tanh, number_kind_floating_point)
3868 UNARY_OP_FUNCTOR(log2, number_kind_floating_point)
3869 UNARY_OP_FUNCTOR(nearbyint, number_kind_floating_point)
3870 UNARY_OP_FUNCTOR(rint, number_kind_floating_point)
3871 
3872 HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point)
3873 //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point)
3874 HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point)
3875 //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point)
3876 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point)
3877 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point)
3878 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long long, number_kind_floating_point)
3879 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*, number_kind_floating_point)
3880 BINARY_OP_FUNCTOR(pow, number_kind_floating_point)
3881 BINARY_OP_FUNCTOR(fmod, number_kind_floating_point)
3882 BINARY_OP_FUNCTOR(fmax, number_kind_floating_point)
3883 BINARY_OP_FUNCTOR(fmin, number_kind_floating_point)
3884 BINARY_OP_FUNCTOR(atan2, number_kind_floating_point)
3885 BINARY_OP_FUNCTOR(fdim, number_kind_floating_point)
3886 BINARY_OP_FUNCTOR(hypot, number_kind_floating_point)
3887 BINARY_OP_FUNCTOR(remainder, number_kind_floating_point)
3888 
3889 UNARY_OP_FUNCTOR(logb, number_kind_floating_point)
3890 HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point)
3891 HETERO_BINARY_OP_FUNCTOR(scalbln, short, number_kind_floating_point)
3892 HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point)
3893 HETERO_BINARY_OP_FUNCTOR_B(scalbln, int, number_kind_floating_point)
3894 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point)
3895 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long, number_kind_floating_point)
3896 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long long, number_kind_floating_point)
3897 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long long, number_kind_floating_point)
3898 
3899 //
3900 // Complex functions:
3901 //
3902 UNARY_OP_FUNCTOR(exp, number_kind_complex)
3903 UNARY_OP_FUNCTOR(log, number_kind_complex)
3904 UNARY_OP_FUNCTOR(log10, number_kind_complex)
3905 BINARY_OP_FUNCTOR(pow, number_kind_complex)
3906 UNARY_OP_FUNCTOR(sqrt, number_kind_complex)
3907 UNARY_OP_FUNCTOR(sin, number_kind_complex)
3908 UNARY_OP_FUNCTOR(cos, number_kind_complex)
3909 UNARY_OP_FUNCTOR(tan, number_kind_complex)
3910 UNARY_OP_FUNCTOR(asin, number_kind_complex)
3911 UNARY_OP_FUNCTOR(acos, number_kind_complex)
3912 UNARY_OP_FUNCTOR(atan, number_kind_complex)
3913 UNARY_OP_FUNCTOR(sinh, number_kind_complex)
3914 UNARY_OP_FUNCTOR(cosh, number_kind_complex)
3915 UNARY_OP_FUNCTOR(tanh, number_kind_complex)
3916 UNARY_OP_FUNCTOR(asinh, number_kind_complex)
3917 UNARY_OP_FUNCTOR(acosh, number_kind_complex)
3918 UNARY_OP_FUNCTOR(atanh, number_kind_complex)
3919 
3920 //
3921 // Integer functions:
3922 //
3923 BINARY_OP_FUNCTOR(gcd, number_kind_integer)
3924 BINARY_OP_FUNCTOR(lcm, number_kind_integer)
3925 HETERO_BINARY_OP_FUNCTOR(pow, unsigned, number_kind_integer)
3926 
3927 #undef BINARY_OP_FUNCTOR
3928 #undef UNARY_OP_FUNCTOR
3929 
3930 //
3931 // ilogb:
3932 //
3933 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3934 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == number_kind_floating_point, typename Backend::exponent_type>::type
3935 ilogb(const multiprecision::number<Backend, ExpressionTemplates>& val)
3936 {
3937    using default_ops::eval_ilogb;
3938    return eval_ilogb(val.backend());
3939 }
3940 
3941 template <class tag, class A1, class A2, class A3, class A4>
3942 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
3943 ilogb(const detail::expression<tag, A1, A2, A3, A4>& val)
3944 {
3945    using default_ops::eval_ilogb;
3946    typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type arg(val);
3947    return eval_ilogb(arg.backend());
3948 }
3949 
3950 } //namespace multiprecision
3951 
3952 namespace math {
3953 //
3954 // Overload of Boost.Math functions that find the wrong overload when used with number:
3955 //
3956 namespace detail {
3957 template <class T>
3958 T sinc_pi_imp(T);
3959 template <class T>
3960 T sinhc_pi_imp(T);
3961 } // namespace detail
3962 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3963 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3964 {
3965    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3966    return std::move(detail::sinc_pi_imp(x));
3967 }
3968 
3969 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
3970 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3971 {
3972    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3973    return std::move(detail::sinc_pi_imp(x));
3974 }
3975 
3976 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3977 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3978 {
3979    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3980    return std::move(detail::sinhc_pi_imp(x));
3981 }
3982 
3983 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
3984 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3985 {
3986    boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3987    return std::move(boost::math::sinhc_pi(x));
3988 }
3989 
3990 using boost::multiprecision::gcd;
3991 using boost::multiprecision::lcm;
3992 
3993 #ifdef BOOST_MSVC
3994 #pragma warning(pop)
3995 #endif
3996 } // namespace math
3997 
3998 namespace integer {
3999 
4000 using boost::multiprecision::gcd;
4001 using boost::multiprecision::lcm;
4002 
4003 } // namespace integer
4004 
4005 } // namespace boost
4006 
4007 //
4008 // This has to come last of all:
4009 //
4010 #include <boost/multiprecision/detail/no_et_ops.hpp>
4011 #include <boost/multiprecision/detail/et_ops.hpp>
4012 //
4013 // min/max overloads:
4014 //
4015 #include <boost/multiprecision/detail/min_max.hpp>
4016 
4017 #endif