/////////////////////////////////////////////////////////////////////////////// // Copyright 2011 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_MATH_BIG_NUM_DEF_OPS #define BOOST_MATH_BIG_NUM_DEF_OPS #include // BOOST_TRY #include #include #include #include #include #include #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW #include #endif #ifndef INSTRUMENT_BACKEND #ifndef BOOST_MP_INSTRUMENT #define INSTRUMENT_BACKEND(x) #else #define INSTRUMENT_BACKEND(x) \ std::cout << BOOST_STRINGIZE(x) << " = " << x.str(0, std::ios_base::scientific) << std::endl; #endif #endif namespace boost { namespace multiprecision { namespace detail { template struct is_backend; template void generic_interconvert(To& to, const From& from, const std::integral_constant& /*to_type*/, const std::integral_constant& /*from_type*/); template void generic_interconvert(To& to, const From& from, const std::integral_constant& /*to_type*/, const std::integral_constant& /*from_type*/); template void generic_interconvert(To& to, const From& from, const std::integral_constant& /*to_type*/, const std::integral_constant& /*from_type*/); template void generic_interconvert(To& to, const From& from, const std::integral_constant& /*to_type*/, const std::integral_constant& /*from_type*/); template void generic_interconvert(To& to, const From& from, const std::integral_constant& /*to_type*/, const std::integral_constant& /*from_type*/); } // namespace detail namespace default_ops { #ifdef BOOST_MSVC // warning C4127: conditional expression is constant // warning C4146: unary minus operator applied to unsigned type, result still unsigned #pragma warning(push) #pragma warning(disable : 4127 4146) #endif // // Default versions of mixed arithmetic, these just construct a temporary // from the arithmetic value and then do the arithmetic on that, two versions // of each depending on whether the backend can be directly constructed from type V. // // Note that we have to provide *all* the template parameters to class number when used in // enable_if as MSVC-10 won't compile the code if we rely on a computed-default parameter. // Since the result of the test doesn't depend on whether expression templates are on or off // we just use et_on everywhere. We could use a BOOST_WORKAROUND but that just obfuscates the // code even more.... // template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible::value>::type eval_add(T& result, V const& v) { T t; t = v; eval_add(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value>::type eval_add(T& result, V const& v) { T t(v); eval_add(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible::value>::type eval_subtract(T& result, V const& v) { T t; t = v; eval_subtract(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value>::type eval_subtract(T& result, V const& v) { T t(v); eval_subtract(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible::value>::type eval_multiply(T& result, V const& v) { T t; t = v; eval_multiply(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value>::type eval_multiply(T& result, V const& v) { T t(v); eval_multiply(result, t); } template BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value)>::type eval_multiply_add(T& t, const U& u, const V& v) { T z; eval_multiply(z, u, v); eval_add(t, z); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v) { eval_multiply_add(t, v, u); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value)>::type eval_multiply_subtract(T& t, const U& u, const V& v) { T z; eval_multiply(z, u, v); eval_subtract(t, z); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v) { eval_multiply_subtract(t, v, u); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_divide(T& result, V const& v) { T t; t = v; eval_divide(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_divide(T& result, V const& v) { T t(v); eval_divide(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_modulus(T& result, V const& v) { T t; t = v; eval_modulus(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_modulus(T& result, V const& v) { T t(v); eval_modulus(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_bitwise_and(T& result, V const& v) { T t; t = v; eval_bitwise_and(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_bitwise_and(T& result, V const& v) { T t(v); eval_bitwise_and(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_bitwise_or(T& result, V const& v) { T t; t = v; eval_bitwise_or(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_bitwise_or(T& result, V const& v) { T t(v); eval_bitwise_or(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_bitwise_xor(T& result, V const& v) { T t; t = v; eval_bitwise_xor(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_bitwise_xor(T& result, V const& v) { T t(v); eval_bitwise_xor(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_complement(T& result, V const& v) { T t; t = v; eval_complement(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_complement(T& result, V const& v) { T t(v); eval_complement(result, t); } // // Default versions of 3-arg arithmetic functions, these mostly just forward to the 2 arg versions: // template BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR void eval_add_default(T& t, const T& u, const T& v) { if (&t == &v) { eval_add(t, u); } else if (&t == &u) { eval_add(t, v); } else { t = u; eval_add(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_add(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) { T vv(v); eval_add(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_add_default(T& t, const U& u, const T& v) { eval_add(t, v, u); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_add_default(T& t, const U& u, const V& v) { BOOST_IF_CONSTEXPR(std::is_same::value) { if ((void*)&t == (void*)&v) { eval_add(t, u); } else { t = u; eval_add(t, v); } } else { t = u; eval_add(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v) { eval_add_default(t, u, v); } template void BOOST_MP_CXX14_CONSTEXPR eval_subtract(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract_default(T& t, const T& u, const T& v) { if ((&t == &v) && is_signed_number::value) { eval_subtract(t, u); t.negate(); } else if (&t == &u) { eval_subtract(t, v); } else { t = u; eval_subtract(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_subtract(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) { T vv(v); eval_subtract(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && is_signed_number::value>::type eval_subtract_default(T& t, const U& u, const T& v) { eval_subtract(t, v, u); t.negate(); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value && is_unsigned_number::value>::type eval_subtract_default(T& t, const U& u, const T& v) { T temp; temp = u; eval_subtract(t, temp, v); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value && is_unsigned_number::value>::type eval_subtract_default(T& t, const U& u, const T& v) { T temp(u); eval_subtract(t, temp, v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract_default(T& t, const U& u, const V& v) { BOOST_IF_CONSTEXPR(std::is_same::value) { if ((void*)&t == (void*)&v) { eval_subtract(t, u); t.negate(); } else { t = u; eval_subtract(t, v); } } else { t = u; eval_subtract(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(T& t, const U& u, const V& v) { eval_subtract_default(t, u, v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_default(T& t, const T& u, const T& v) { if (&t == &v) { eval_multiply(t, u); } else if (&t == &u) { eval_multiply(t, v); } else { t = u; eval_multiply(t, v); } } #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_multiply(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) { T vv(v); eval_multiply(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_multiply_default(T& t, const U& u, const T& v) { eval_multiply(t, v, u); } #endif template inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_default(T& t, const U& u, const V& v) { BOOST_IF_CONSTEXPR(std::is_same::value) { if ((void*)&t == (void*)&v) { eval_multiply(t, u); } else { t = number::canonical_value(u); eval_multiply(t, v); } } else { t = number::canonical_value(u); eval_multiply(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v) { eval_multiply_default(t, u, v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_add(T& t, const T& u, const T& v, const T& x) { if ((void*)&x == (void*)&t) { T z; z = number::canonical_value(x); eval_multiply_add(t, u, v, z); } else { eval_multiply(t, u, v); eval_add(t, x); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_same::value, T>::type make_T(const U& u) { T t; t = number::canonical_value(u); return t; } template inline BOOST_MP_CXX14_CONSTEXPR const T& make_T(const T& t) { return t; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value)>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x) { eval_multiply_add(t, make_T(u), make_T(v), make_T(x)); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x) { eval_multiply_add(t, v, u, x); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value)>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x) { if ((void*)&x == (void*)&t) { T z; z = x; eval_multiply_subtract(t, u, v, z); } else { eval_multiply(t, u, v); eval_subtract(t, x); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value && std::is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x) { eval_multiply_subtract(t, v, u, x); } template BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR void eval_divide_default(T& t, const T& u, const T& v) { if (&t == &u) eval_divide(t, v); else if (&t == &v) { T temp; eval_divide(temp, u, v); temp.swap(t); } else { t = u; eval_divide(t, v); } } #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_divide(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) { T vv(v); eval_divide(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) { T uu; uu = u; eval_divide(t, uu, v); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) { T uu(u); eval_divide(t, uu, v); } #endif template inline BOOST_MP_CXX14_CONSTEXPR void eval_divide_default(T& t, const U& u, const V& v) { BOOST_IF_CONSTEXPR(std::is_same::value) { if ((void*)&t == (void*)&v) { T temp; temp = u; eval_divide(temp, v); t = temp; } else { t = u; eval_divide(t, v); } } else { t = u; eval_divide(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v) { eval_divide_default(t, u, v); } template BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus_default(T& t, const T& u, const T& v) { if (&t == &u) eval_modulus(t, v); else if (&t == &v) { T temp; eval_modulus(temp, u, v); temp.swap(t); } else { t = u; eval_modulus(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_modulus(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) { T vv(v); eval_modulus(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) { T uu; uu = u; eval_modulus(t, uu, v); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) { T uu(u); eval_modulus(t, uu, v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus_default(T& t, const U& u, const V& v) { BOOST_IF_CONSTEXPR(std::is_same::value) { if ((void*)&t == (void*)&v) { T temp(u); eval_modulus(temp, v); t = temp; } else { t = u; eval_modulus(t, v); } } else { t = u; eval_modulus(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v) { eval_modulus_default(t, u, v); } template BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and_default(T& t, const T& u, const T& v) { if (&t == &v) { eval_bitwise_and(t, u); } else if (&t == &u) { eval_bitwise_and(t, v); } else { t = u; eval_bitwise_and(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_bitwise_and(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) { T vv(v); eval_bitwise_and(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v) { eval_bitwise_and(t, v, u); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value || std::is_same::value>::type eval_bitwise_and_default(T& t, const U& u, const V& v) { t = u; eval_bitwise_and(t, v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v) { eval_bitwise_and_default(t, u, v); } template BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or_default(T& t, const T& u, const T& v) { if (&t == &v) { eval_bitwise_or(t, u); } else if (&t == &u) { eval_bitwise_or(t, v); } else { t = u; eval_bitwise_or(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_bitwise_or(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) { T vv(v); eval_bitwise_or(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v) { eval_bitwise_or(t, v, u); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or_default(T& t, const U& u, const V& v) { BOOST_IF_CONSTEXPR(std::is_same::value) { if ((void*)&t == (void*)&v) { eval_bitwise_or(t, u); } else { t = u; eval_bitwise_or(t, v); } } else { t = u; eval_bitwise_or(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v) { eval_bitwise_or_default(t, u, v); } template BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v); template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor_default(T& t, const T& u, const T& v) { if (&t == &v) { eval_bitwise_xor(t, u); } else if (&t == &u) { eval_bitwise_xor(t, v); } else { t = u; eval_bitwise_xor(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !std::is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_bitwise_xor(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && std::is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) { T vv(v); eval_bitwise_xor(t, u, vv); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v) { eval_bitwise_xor(t, v, u); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor_default(T& t, const U& u, const V& v) { BOOST_IF_CONSTEXPR(std::is_same::value) { if ((void*)&t == (void*)&v) { eval_bitwise_xor(t, u); } else { t = u; eval_bitwise_xor(t, v); } } else { t = u; eval_bitwise_xor(t, v); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v) { eval_bitwise_xor_default(t, u, v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_increment(T& val) { using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type; eval_add(val, static_cast(1u)); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_decrement(T& val) { using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type; eval_subtract(val, static_cast(1u)); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_left_shift(T& result, const U& arg, const V val) { result = arg; eval_left_shift(result, val); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_right_shift(T& result, const U& arg, const V val) { result = arg; eval_right_shift(result, val); } template inline BOOST_MP_CXX14_CONSTEXPR bool eval_is_zero(const T& val) { using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type; return val.compare(static_cast(0)) == 0; } template inline BOOST_MP_CXX14_CONSTEXPR int eval_get_sign(const T& val) { using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type; return val.compare(static_cast(0)); } template inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant&) { result = v1; T t; t = v2; eval_divide(result, t); } template inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant&) { using component_number_type = typename component_type >::type; component_number_type x(v1), y(v2); assign_components(result, x.backend(), y.backend()); } template inline BOOST_MP_CXX14_CONSTEXPR void assign_components(T& result, const V& v1, const U& v2) { return assign_components_imp(result, v1, v2, typename number_category::type()); } #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW template inline void assign_from_string_view(Result& result, const std::basic_string_view& view) { // since most (all?) backends require a const char* to construct from, we just // convert to that: std::string s(view); result = s.c_str(); } template inline void assign_from_string_view(Result& result, const std::basic_string_view& view_x, const std::basic_string_view& view_y) { // since most (all?) backends require a const char* to construct from, we just // convert to that: std::string x(view_x), y(view_y); assign_components(result, x.c_str(), y.c_str()); } #endif template struct has_enough_bits { template struct type : public std::integral_constant::value && (std::numeric_limits::digits >= b)> {}; }; template struct terminal { BOOST_MP_CXX14_CONSTEXPR terminal(const R& v) : value(v) {} BOOST_MP_CXX14_CONSTEXPR terminal() {} BOOST_MP_CXX14_CONSTEXPR terminal& operator=(R val) { value = val; return *this; } R value; BOOST_MP_CXX14_CONSTEXPR operator R() const { return value; } }; template ::value)> struct find_index_of_type { static constexpr int value = std::is_same::type>::value ? i : find_index_of_type::value; }; template struct find_index_of_type { static constexpr int value = -1; }; template struct calculate_next_larger_type { // Find which list we're looking through: using list_type = typename std::conditional< boost::multiprecision::detail::is_signed::value && boost::multiprecision::detail::is_integral::value, typename B::signed_types, typename std::conditional< boost::multiprecision::detail::is_unsigned::value, typename B::unsigned_types, typename B::float_types>::type>::type; static constexpr int start = find_index_of_type::value; static constexpr int index_of_type = boost::multiprecision::detail::find_index_of_large_enough_type::digits>::value; using type = typename boost::multiprecision::detail::dereference_tuple >::type; }; template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, bool>::type check_in_range(const T& t) { // Can t fit in an R? if ((t > 0) && std::numeric_limits::is_specialized && std::numeric_limits::is_bounded && (t > (std::numeric_limits::max)())) return true; else return false; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value>::type eval_convert_to(R* result, const B& backend) { using next_type = typename calculate_next_larger_type::type; next_type n = next_type(); eval_convert_to(&n, backend); BOOST_IF_CONSTEXPR(!boost::multiprecision::detail::is_unsigned::value && std::numeric_limits::is_specialized && std::numeric_limits::is_bounded) { if(n > (next_type)(std::numeric_limits::max)()) { *result = (std::numeric_limits::max)(); return; } } BOOST_IF_CONSTEXPR(std::numeric_limits::is_specialized&& std::numeric_limits::is_bounded) { if (n < (next_type)(std::numeric_limits::min)()) { *result = (std::numeric_limits::min)(); return; } } *result = static_cast(n); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !boost::multiprecision::detail::is_integral::value>::type eval_convert_to(R* result, const B& backend) { using next_type = typename calculate_next_larger_type::type; next_type n = next_type(); eval_convert_to(&n, backend); BOOST_IF_CONSTEXPR(std::numeric_limits::is_specialized && std::numeric_limits::is_bounded) { if ((n > (next_type)(std::numeric_limits::max)() || (n < (next_type) - (std::numeric_limits::max)()))) { *result = n > 0 ? (std::numeric_limits::max)() : -(std::numeric_limits::max)(); } else *result = static_cast(n); } else *result = static_cast(n); } template inline void last_chance_eval_convert_to(terminal* result, const B& backend, const std::integral_constant&) { // // We ran out of types to try for the conversion, try // a lexical_cast and hope for the best: // BOOST_IF_CONSTEXPR (std::numeric_limits::is_integer && !std::numeric_limits::is_signed) if (eval_get_sign(backend) < 0) BOOST_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour")); BOOST_TRY { result->value = boost::lexical_cast(backend.str(0, std::ios_base::fmtflags(0))); } BOOST_CATCH (const bad_lexical_cast&) { if (eval_get_sign(backend) < 0) { BOOST_IF_CONSTEXPR(std::numeric_limits::is_integer && !std::numeric_limits::is_signed) *result = (std::numeric_limits::max)(); // we should never get here, exception above will be raised. else BOOST_IF_CONSTEXPR(std::numeric_limits::is_integer) *result = (std::numeric_limits::min)(); else *result = -(std::numeric_limits::max)(); } else *result = (std::numeric_limits::max)(); } BOOST_CATCH_END } template inline void last_chance_eval_convert_to(terminal* result, const B& backend, const std::integral_constant&) { // // Last chance conversion to an unsigned integer. // We ran out of types to try for the conversion, try // a lexical_cast and hope for the best: // if (eval_get_sign(backend) < 0) BOOST_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour")); BOOST_TRY { B t(backend); R mask = ~static_cast(0u); eval_bitwise_and(t, mask); result->value = boost::lexical_cast(t.str(0, std::ios_base::fmtflags(0))); } BOOST_CATCH (const bad_lexical_cast&) { // We should never really get here... *result = (std::numeric_limits::max)(); } BOOST_CATCH_END } template inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal* result, const B& backend) { using tag_type = std::integral_constant::value && number_category::value == number_kind_integer>; last_chance_eval_convert_to(result, backend, tag_type()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal >* result, const B2& backend) { // // We ran out of types to try for the conversion, try // a generic conversion and hope for the best: // boost::multiprecision::detail::generic_interconvert(result->value.backend(), backend, number_category(), number_category()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::string* result, const B& backend) { *result = backend.str(0, std::ios_base::fmtflags(0)); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex* result, const B& backend) { using scalar_type = typename scalar_result_from_possible_complex >::type; scalar_type re, im; eval_real(re.backend(), backend); eval_imag(im.backend(), backend); *result = std::complex(re.template convert_to(), im.template convert_to()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex* result, const B& backend) { using scalar_type = typename scalar_result_from_possible_complex >::type; scalar_type re, im; eval_real(re.backend(), backend); eval_imag(im.backend(), backend); *result = std::complex(re.template convert_to(), im.template convert_to()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex* result, const B& backend) { using scalar_type = typename scalar_result_from_possible_complex >::type; scalar_type re, im; eval_real(re.backend(), backend); eval_imag(im.backend(), backend); *result = std::complex(re.template convert_to(), im.template convert_to()); } // // Functions: // template inline BOOST_MP_CXX14_CONSTEXPR void eval_abs(T& result, const U& arg) { using type_list = typename U::signed_types ; using front = typename std::tuple_element<0, type_list>::type; result = arg; if (arg.compare(front(0)) < 0) result.negate(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_fabs(T& result, const U& arg) { static_assert(number_category::value == number_kind_floating_point, "The fabs function is only valid for floating point types."); using type_list = typename U::signed_types ; using front = typename std::tuple_element<0, type_list>::type; result = arg; if (arg.compare(front(0)) < 0) result.negate(); } template inline BOOST_MP_CXX14_CONSTEXPR int eval_fpclassify(const Backend& arg) { static_assert(number_category::value == number_kind_floating_point, "The fpclassify function is only valid for floating point types."); return eval_is_zero(arg) ? FP_ZERO : FP_NORMAL; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_fmod(T& result, const T& a, const T& b) { static_assert(number_category::value == number_kind_floating_point, "The fmod function is only valid for floating point types."); if ((&result == &a) || (&result == &b)) { T temp; eval_fmod(temp, a, b); result = temp; return; } switch (eval_fpclassify(a)) { case FP_ZERO: result = a; return; case FP_INFINITE: case FP_NAN: result = std::numeric_limits >::quiet_NaN().backend(); errno = EDOM; return; } switch (eval_fpclassify(b)) { case FP_ZERO: case FP_NAN: result = std::numeric_limits >::quiet_NaN().backend(); errno = EDOM; return; } T n; eval_divide(result, a, b); if (eval_get_sign(result) < 0) eval_ceil(n, result); else eval_floor(n, result); eval_multiply(n, b); eval_subtract(result, a, n); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, void>::type eval_fmod(T& result, const T& x, const A& a) { using canonical_type = typename boost::multiprecision::detail::canonical::type ; using cast_type = typename std::conditional::value, T, canonical_type>::type; cast_type c; c = a; eval_fmod(result, x, c); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, void>::type eval_fmod(T& result, const A& x, const T& a) { using canonical_type = typename boost::multiprecision::detail::canonical::type ; using cast_type = typename std::conditional::value, T, canonical_type>::type; cast_type c; c = x; eval_fmod(result, c, a); } template BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a); template inline BOOST_MP_CXX14_CONSTEXPR void eval_remquo(T& result, const T& a, const T& b, int* pi) { static_assert(number_category::value == number_kind_floating_point, "The remquo function is only valid for floating point types."); if ((&result == &a) || (&result == &b)) { T temp; eval_remquo(temp, a, b, pi); result = temp; return; } T n; eval_divide(result, a, b); eval_round(n, result); eval_convert_to(pi, n); eval_multiply(n, b); eval_subtract(result, a, n); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, void>::type eval_remquo(T& result, const T& x, const A& a, int* pi) { using canonical_type = typename boost::multiprecision::detail::canonical::type ; using cast_type = typename std::conditional::value, T, canonical_type>::type; cast_type c = cast_type(); c = a; eval_remquo(result, x, c, pi); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, void>::type eval_remquo(T& result, const A& x, const T& a, int* pi) { using canonical_type = typename boost::multiprecision::detail::canonical::type ; using cast_type = typename std::conditional::value, T, canonical_type>::type; cast_type c = cast_type(); c = x; eval_remquo(result, c, a, pi); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_remainder(T& result, const U& a, const V& b) { int i(0); eval_remquo(result, a, b, &i); } template BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const B& a, const B& b); template BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const T& a, const U& b); template BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const B& a, const B& b); template BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const T& a, const U& b); template inline BOOST_MP_CXX14_CONSTEXPR void eval_fdim(T& result, const T& a, const T& b) { using ui_type = typename boost::multiprecision::detail::canonical::type; const ui_type zero = 0u; switch (eval_fpclassify(b)) { case FP_NAN: case FP_INFINITE: result = zero; return; } switch (eval_fpclassify(a)) { case FP_NAN: result = zero; return; case FP_INFINITE: result = a; return; } if (eval_gt(a, b)) { eval_subtract(result, a, b); } else result = zero; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value>::type eval_fdim(T& result, const T& a, const A& b) { using ui_type = typename boost::multiprecision::detail::canonical::type; using arithmetic_type = typename boost::multiprecision::detail::canonical::type ; const ui_type zero = 0u; arithmetic_type canonical_b = b; switch ((::boost::math::fpclassify)(b)) { case FP_NAN: case FP_INFINITE: result = zero; return; } switch (eval_fpclassify(a)) { case FP_NAN: result = zero; return; case FP_INFINITE: result = a; return; } if (eval_gt(a, canonical_b)) { eval_subtract(result, a, canonical_b); } else result = zero; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value>::type eval_fdim(T& result, const A& a, const T& b) { using ui_type = typename boost::multiprecision::detail::canonical::type; using arithmetic_type = typename boost::multiprecision::detail::canonical::type ; const ui_type zero = 0u; arithmetic_type canonical_a = a; switch (eval_fpclassify(b)) { case FP_NAN: case FP_INFINITE: result = zero; return; } switch ((::boost::math::fpclassify)(a)) { case FP_NAN: result = zero; return; case FP_INFINITE: result = std::numeric_limits >::infinity().backend(); return; } if (eval_gt(canonical_a, b)) { eval_subtract(result, canonical_a, b); } else result = zero; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_trunc(T& result, const T& a) { static_assert(number_category::value == number_kind_floating_point, "The trunc function is only valid for floating point types."); switch (eval_fpclassify(a)) { case FP_NAN: errno = EDOM; // fallthrough... case FP_ZERO: case FP_INFINITE: result = a; return; } if (eval_get_sign(a) < 0) eval_ceil(result, a); else eval_floor(result, a); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_modf(T& result, T const& arg, T* pipart) { using ui_type = typename boost::multiprecision::detail::canonical::type; int c = eval_fpclassify(arg); if (c == (int)FP_NAN) { if (pipart) *pipart = arg; result = arg; return; } else if (c == (int)FP_INFINITE) { if (pipart) *pipart = arg; result = ui_type(0u); return; } if (pipart) { eval_trunc(*pipart, arg); eval_subtract(result, arg, *pipart); } else { T ipart; eval_trunc(ipart, arg); eval_subtract(result, arg, ipart); } } template inline BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a) { static_assert(number_category::value == number_kind_floating_point, "The round function is only valid for floating point types."); using fp_type = typename boost::multiprecision::detail::canonical::type; int c = eval_fpclassify(a); if (c == (int)FP_NAN) { result = a; errno = EDOM; return; } if ((c == FP_ZERO) || (c == (int)FP_INFINITE)) { result = a; } else if (eval_get_sign(a) < 0) { eval_subtract(result, a, fp_type(0.5f)); eval_ceil(result, result); } else { eval_add(result, a, fp_type(0.5f)); eval_floor(result, result); } } template BOOST_MP_CXX14_CONSTEXPR void eval_lcm(B& result, const B& a, const B& b); template BOOST_MP_CXX14_CONSTEXPR void eval_gcd(B& result, const B& a, const B& b); template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value >::type eval_gcd(T& result, const T& a, const Arithmetic& b) { using si_type = typename boost::multiprecision::detail::canonical::type; using default_ops::eval_gcd; T t; t = static_cast(b); eval_gcd(result, a, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value >::type eval_gcd(T& result, const Arithmetic& a, const T& b) { eval_gcd(result, b, a); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value >::type eval_lcm(T& result, const T& a, const Arithmetic& b) { using si_type = typename boost::multiprecision::detail::canonical::type; using default_ops::eval_lcm; T t; t = static_cast(b); eval_lcm(result, a, t); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value >::type eval_lcm(T& result, const Arithmetic& a, const T& b) { eval_lcm(result, b, a); } template inline BOOST_MP_CXX14_CONSTEXPR unsigned eval_lsb(const T& val) { using ui_type = typename boost::multiprecision::detail::canonical::type; int c = eval_get_sign(val); if (c == 0) { BOOST_THROW_EXCEPTION(std::domain_error("No bits were set in the operand.")); } if (c < 0) { BOOST_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined.")); } unsigned result = 0; T mask, t; mask = ui_type(1); do { eval_bitwise_and(t, mask, val); ++result; eval_left_shift(mask, 1); } while (eval_is_zero(t)); return --result; } template inline BOOST_MP_CXX14_CONSTEXPR int eval_msb(const T& val) { int c = eval_get_sign(val); if (c == 0) { BOOST_THROW_EXCEPTION(std::domain_error("No bits were set in the operand.")); } if (c < 0) { BOOST_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined.")); } // // This implementation is really really rubbish - it does // a linear scan for the most-significant-bit. We should really // do a binary search, but as none of our backends actually needs // this implementation, we'll leave it for now. In fact for most // backends it's likely that there will always be a more efficient // native implementation possible. // unsigned result = 0; T t(val); while (!eval_is_zero(t)) { eval_right_shift(t, 1); ++result; } return --result; } template inline BOOST_MP_CXX14_CONSTEXPR bool eval_bit_test(const T& val, unsigned index) { using ui_type = typename boost::multiprecision::detail::canonical::type; T mask, t; mask = ui_type(1); eval_left_shift(mask, index); eval_bitwise_and(t, mask, val); return !eval_is_zero(t); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_set(T& val, unsigned index) { using ui_type = typename boost::multiprecision::detail::canonical::type; T mask; mask = ui_type(1); eval_left_shift(mask, index); eval_bitwise_or(val, mask); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_flip(T& val, unsigned index) { using ui_type = typename boost::multiprecision::detail::canonical::type; T mask; mask = ui_type(1); eval_left_shift(mask, index); eval_bitwise_xor(val, mask); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_unset(T& val, unsigned index) { using ui_type = typename boost::multiprecision::detail::canonical::type; T mask, t; mask = ui_type(1); eval_left_shift(mask, index); eval_bitwise_and(t, mask, val); if (!eval_is_zero(t)) eval_bitwise_xor(val, mask); } template void BOOST_MP_CXX14_CONSTEXPR eval_integer_sqrt(B& s, B& r, const B& x) { // // This is slow bit-by-bit integer square root, see for example // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29 // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented // at some point. // using ui_type = typename boost::multiprecision::detail::canonical::type; s = ui_type(0u); if (eval_get_sign(x) == 0) { r = ui_type(0u); return; } int g = eval_msb(x); if (g <= 1) { s = ui_type(1); eval_subtract(r, x, s); return; } B t; r = x; g /= 2; int org_g = g; eval_bit_set(s, g); eval_bit_set(t, 2 * g); eval_subtract(r, x, t); --g; if (eval_get_sign(r) == 0) return; int msbr = eval_msb(r); do { if (msbr >= org_g + g + 1) { t = s; eval_left_shift(t, g + 1); eval_bit_set(t, 2 * g); if (t.compare(r) <= 0) { BOOST_ASSERT(g >= 0); eval_bit_set(s, g); eval_subtract(r, t); if (eval_get_sign(r) == 0) return; msbr = eval_msb(r); } } --g; } while (g >= 0); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_conj(B& result, const B& val) { result = val; // assume non-complex result. } template inline BOOST_MP_CXX14_CONSTEXPR void eval_proj(B& result, const B& val) { result = val; // assume non-complex result. } // // These have to implemented by the backend, declared here so that our macro generated code compiles OK. // template typename std::enable_if::type eval_floor(); template typename std::enable_if::type eval_ceil(); template typename std::enable_if::type eval_trunc(); template typename std::enable_if::type eval_sqrt(); template typename std::enable_if::type eval_ldexp(); template typename std::enable_if::type eval_frexp(); // TODO implement default versions of these: template typename std::enable_if::type eval_asinh(); template typename std::enable_if::type eval_acosh(); template typename std::enable_if::type eval_atanh(); // // eval_logb and eval_scalbn simply assume base 2 and forward to // eval_ldexp and eval_frexp: // template inline BOOST_MP_CXX14_CONSTEXPR typename B::exponent_type eval_ilogb(const B& val) { static_assert(!std::numeric_limits >::is_specialized || (std::numeric_limits >::radix == 2), "The default implementation of ilogb requires a base 2 number type"); typename B::exponent_type e(0); switch (eval_fpclassify(val)) { case FP_NAN: #ifdef FP_ILOGBNAN return FP_ILOGBNAN > 0 ? (std::numeric_limits::max)() : (std::numeric_limits::min)(); #else return (std::numeric_limits::max)(); #endif case FP_INFINITE: return (std::numeric_limits::max)(); case FP_ZERO: return (std::numeric_limits::min)(); } B result; eval_frexp(result, val, &e); return e - 1; } template BOOST_MP_CXX14_CONSTEXPR int eval_signbit(const T& val); template inline BOOST_MP_CXX14_CONSTEXPR void eval_logb(B& result, const B& val) { switch (eval_fpclassify(val)) { case FP_NAN: result = val; errno = EDOM; return; case FP_ZERO: result = std::numeric_limits >::infinity().backend(); result.negate(); errno = ERANGE; return; case FP_INFINITE: result = val; if (eval_signbit(val)) result.negate(); return; } using max_t = typename std::conditional::value, boost::long_long_type, std::intmax_t>::type; result = static_cast(eval_ilogb(val)); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbn(B& result, const B& val, A e) { static_assert(!std::numeric_limits >::is_specialized || (std::numeric_limits >::radix == 2), "The default implementation of scalbn requires a base 2 number type"); eval_ldexp(result, val, static_cast(e)); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbln(B& result, const B& val, A e) { eval_scalbn(result, val, e); } template inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant const&, const std::integral_constant&) { return eval_fpclassify(val) == FP_NAN; } template inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant const&, const std::integral_constant&) { return (boost::math::isnan)(val); } template inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T&, std::integral_constant const&, const std::integral_constant&) { return false; } template inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val) { return is_arg_nan(val, std::integral_constant::value>(), std::is_floating_point()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_fmax(T& result, const U& a, const V& b) { if (is_arg_nan(a)) result = number::canonical_value(b); else if (is_arg_nan(b)) result = number::canonical_value(a); else if (eval_lt(number::canonical_value(a), number::canonical_value(b))) result = number::canonical_value(b); else result = number::canonical_value(a); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_fmin(T& result, const U& a, const V& b) { if (is_arg_nan(a)) result = number::canonical_value(b); else if (is_arg_nan(b)) result = number::canonical_value(a); else if (eval_lt(number::canonical_value(a), number::canonical_value(b))) result = number::canonical_value(a); else result = number::canonical_value(b); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_hypot(R& result, const T& a, const U& b) { // // Normalize x and y, so that both are positive and x >= y: // R x, y; x = number::canonical_value(a); y = number::canonical_value(b); if (eval_get_sign(x) < 0) x.negate(); if (eval_get_sign(y) < 0) y.negate(); // Special case, see C99 Annex F. // The order of the if's is important: do not change! int c1 = eval_fpclassify(x); int c2 = eval_fpclassify(y); if (c1 == FP_ZERO) { result = y; return; } if (c2 == FP_ZERO) { result = x; return; } if (c1 == FP_INFINITE) { result = x; return; } if ((c2 == FP_INFINITE) || (c2 == FP_NAN)) { result = y; return; } if (c1 == FP_NAN) { result = x; return; } if (eval_gt(y, x)) x.swap(y); eval_multiply(result, x, std::numeric_limits >::epsilon().backend()); if (eval_gt(result, y)) { result = x; return; } R rat; eval_divide(rat, y, x); eval_multiply(result, rat, rat); eval_increment(result); eval_sqrt(rat, result); eval_multiply(result, rat, x); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_nearbyint(R& result, const T& a) { eval_round(result, a); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_rint(R& result, const T& a) { eval_nearbyint(result, a); } template inline BOOST_MP_CXX14_CONSTEXPR int eval_signbit(const T& val) { return eval_get_sign(val) < 0 ? 1 : 0; } // // Real and imaginary parts: // template inline BOOST_MP_CXX14_CONSTEXPR void eval_real(To& to, const From& from) { to = from; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_imag(To& to, const From&) { using ui_type = typename std::tuple_element<0, typename To::unsigned_types>::type; to = ui_type(0); } } // namespace default_ops namespace default_ops_adl { template inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real_imp(To& to, const From& from) { using to_component_type = typename component_type >::type; typename to_component_type::backend_type to_component; to_component = from; eval_set_real(to, to_component); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag_imp(To& to, const From& from) { using to_component_type = typename component_type >::type; typename to_component_type::backend_type to_component; to_component = from; eval_set_imag(to, to_component); } } // namespace default_ops_adl namespace default_ops { template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_complex>::type eval_set_real(To& to, const From& from) { default_ops_adl::eval_set_real_imp(to, from); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value != number_kind_complex>::type eval_set_real(To& to, const From& from) { to = from; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag(To& to, const From& from) { default_ops_adl::eval_set_imag_imp(to, from); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real(T& to, const T& from) { to = from; } template void BOOST_MP_CXX14_CONSTEXPR eval_set_imag(T&, const T&) { static_assert(sizeof(T) == INT_MAX, "eval_set_imag needs to be specialised for each specific backend"); } // // These functions are implemented in separate files, but expanded inline here, // DO NOT CHANGE THE ORDER OF THESE INCLUDES: // #include #include #include } // namespace default_ops // // Default versions of floating point classification routines: // template inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { using multiprecision::default_ops::eval_fpclassify; return eval_fpclassify(arg.backend()); } template inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { int v = fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg); return (v != (int)FP_INFINITE) && (v != (int)FP_NAN); } template inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_NAN; } template inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return isnan BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_INFINITE; } template inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return isinf BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_NORMAL; } template inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } // Default versions of sign manipulation functions, if individual backends can do better than this // (for example with signed zero), then they should overload these functions further: template inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return arg.sign(); } template inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return sign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { using default_ops::eval_signbit; return eval_signbit(arg.backend()); } template inline BOOST_MP_CXX14_CONSTEXPR int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return -arg; } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; return changesign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::number& b) { return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? (boost::multiprecision::changesign)(a) : a; } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::detail::expression& b) { return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number(b)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::number& b) { return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number(a), b); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::detail::expression& b) { using value_type = typename multiprecision::detail::expression::result_type; return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b)); } // // real and imag: // template inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex >::type real(const multiprecision::number& a) { using default_ops::eval_real; using result_type = typename scalar_result_from_possible_complex >::type; boost::multiprecision::detail::scoped_default_precision precision_guard(a); result_type result; eval_real(result.backend(), a.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex >::type imag(const multiprecision::number& a) { using default_ops::eval_imag; using result_type = typename scalar_result_from_possible_complex >::type; boost::multiprecision::detail::scoped_default_precision precision_guard(a); result_type result; eval_imag(result.backend(), a.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex::result_type>::type real(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return real(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex::result_type>::type imag(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return imag(value_type(arg)); } // // Complex number functions, these are overloaded at the Backend level, we just provide the // expression template versions here, plus overloads for non-complex types: // template inline BOOST_MP_CXX14_CONSTEXPR typename boost::lazy_enable_if_c::value == number_kind_complex, component_type > >::type abs(const number& v) { return std::move(boost::math::hypot(real(v), imag(v))); } template inline BOOST_MP_CXX14_CONSTEXPR typename boost::lazy_enable_if_c::result_type>::value == number_kind_complex, component_type::result_type> >::type abs(const detail::expression& v) { using number_type = typename detail::expression::result_type; return std::move(abs(static_cast(v))); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_complex, typename scalar_result_from_possible_complex >::type>::type arg(const number& v) { return std::move(atan2(imag(v), real(v))); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, typename scalar_result_from_possible_complex >::type>::type arg(const number&) { return 0; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_complex || number_category::result_type>::value == number_kind_floating_point, typename scalar_result_from_possible_complex::result_type>::type>::type arg(const detail::expression& v) { using number_type = typename detail::expression::result_type; return std::move(arg(static_cast(v))); } template inline BOOST_MP_CXX14_CONSTEXPR typename boost::lazy_enable_if_c::value == number_kind_complex, component_type > >::type norm(const number& v) { typename component_type >::type a(real(v)), b(imag(v)); return std::move(a * a + b * b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value != number_kind_complex, typename scalar_result_from_possible_complex >::type>::type norm(const number& v) { return v * v; } template inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex::result_type>::type norm(const detail::expression& v) { using number_type = typename detail::expression::result_type; return std::move(norm(static_cast(v))); } template BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar >::type polar(number const& r, number const& theta) { return typename complex_result_from_scalar >::type(number(r * cos(theta)), number(r * sin(theta))); } template BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type, number >::value, typename complex_result_from_scalar >::type>::type polar(detail::expression const& r, number const& theta) { return typename complex_result_from_scalar >::type(number(r * cos(theta)), number(r * sin(theta))); } template BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type, number >::value, typename complex_result_from_scalar >::type>::type polar(number const& r, detail::expression const& theta) { return typename complex_result_from_scalar >::type(number(r * cos(theta)), number(r * sin(theta))); } template BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type, typename detail::expression::result_type>::value, typename complex_result_from_scalar::result_type>::type>::type polar(detail::expression const& r, detail::expression const& theta) { using scalar_type = typename detail::expression::result_type; return typename complex_result_from_scalar::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta))); } // // We also allow the first argument to polar to be an arithmetic type (probably a literal): // template BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, typename complex_result_from_scalar >::type>::type polar(Scalar const& r, number const& theta) { return typename complex_result_from_scalar >::type(number(r * cos(theta)), number(r * sin(theta))); } template BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, typename complex_result_from_scalar::result_type>::type>::type polar(Scalar const& r, detail::expression const& theta) { using scalar_type = typename detail::expression::result_type; return typename complex_result_from_scalar::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta))); } // // Single argument overloads: // template BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar >::type polar(number const& r) { return typename complex_result_from_scalar >::type(r); } template BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar::result_type>::type polar(detail::expression const& r) { return typename complex_result_from_scalar::result_type>::type(r); } } // namespace multiprecision namespace math { // // Import Math functions here, so they can be found by Boost.Math: // using boost::multiprecision::changesign; using boost::multiprecision::copysign; using boost::multiprecision::fpclassify; using boost::multiprecision::isfinite; using boost::multiprecision::isinf; using boost::multiprecision::isnan; using boost::multiprecision::isnormal; using boost::multiprecision::sign; using boost::multiprecision::signbit; } // namespace math namespace multiprecision { using c99_error_policy = ::boost::math::policies::policy< ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>, ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>, ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>, ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>, ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error> >; template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value != number_kind_complex, multiprecision::number >::type asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::asinh(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value != number_kind_complex, typename multiprecision::detail::expression::result_type>::type asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return asinh(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value != number_kind_complex, multiprecision::number >::type acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::acosh(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value != number_kind_complex, typename multiprecision::detail::expression::result_type>::type acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return acosh(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value != number_kind_complex, multiprecision::number >::type atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::atanh(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value != number_kind_complex, typename multiprecision::detail::expression::result_type>::type atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return atanh(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::cbrt(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return cbrt(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::erf(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return erf(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::erfc(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return erfc(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::expm1(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return expm1(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); multiprecision::number result; result = boost::math::lgamma(arg, c99_error_policy()); if ((boost::multiprecision::isnan)(result) && !(boost::multiprecision::isnan)(arg)) { result = std::numeric_limits >::infinity(); errno = ERANGE; } return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return lgamma(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); if ((arg == 0) && std::numeric_limits >::has_infinity) { errno = ERANGE; return 1 / arg; } return boost::math::tgamma(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return tgamma(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return lround(arg); } template inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { return lround(arg); } #ifndef BOOST_NO_LONG_LONG template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return llround(arg); } template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { return llround(arg); } #endif template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { detail::scoped_default_precision > precision_guard(arg); return boost::math::log1p(arg, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(arg); return log1p(value_type(arg)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::number& b) { detail::scoped_default_precision > precision_guard(a, b); return boost::math::nextafter(a, b, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::detail::expression& b) { detail::scoped_default_precision > precision_guard(a, b); return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number(b)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::number& b) { detail::scoped_default_precision > precision_guard(a, b); return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number(a), b); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::detail::expression& b) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(a, b); return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::number& b) { detail::scoped_default_precision > precision_guard(a, b); return boost::math::nextafter(a, b, c99_error_policy()); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::detail::expression& b) { detail::scoped_default_precision > precision_guard(a, b); return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number(b)); } template inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::number& b) { detail::scoped_default_precision > precision_guard(a, b); return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number(a), b); } template inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression::result_type nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::detail::expression& b) { using value_type = typename multiprecision::detail::expression::result_type; detail::scoped_default_precision precision_guard(a, b); return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b)); } template inline BOOST_MP_CXX14_CONSTEXPR number& add(number& result, const number& a, const number& b) { static_assert((std::is_convertible::value), "No conversion to the target of a mixed precision addition exists"); static_assert((std::is_convertible::value), "No conversion to the target of a mixed precision addition exists"); using default_ops::eval_add; eval_add(result.backend(), a.backend(), b.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR number& subtract(number& result, const number& a, const number& b) { static_assert((std::is_convertible::value), "No conversion to the target of a mixed precision addition exists"); static_assert((std::is_convertible::value), "No conversion to the target of a mixed precision addition exists"); using default_ops::eval_subtract; eval_subtract(result.backend(), a.backend(), b.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR number& multiply(number& result, const number& a, const number& b) { static_assert((std::is_convertible::value), "No conversion to the target of a mixed precision addition exists"); static_assert((std::is_convertible::value), "No conversion to the target of a mixed precision addition exists"); using default_ops::eval_multiply; eval_multiply(result.backend(), a.backend(), b.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, number&>::type add(number& result, const I& a, const I& b) { using default_ops::eval_add; using canonical_type = typename detail::canonical::type; eval_add(result.backend(), static_cast(a), static_cast(b)); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, number&>::type subtract(number& result, const I& a, const I& b) { using default_ops::eval_subtract; using canonical_type = typename detail::canonical::type; eval_subtract(result.backend(), static_cast(a), static_cast(b)); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value, number&>::type multiply(number& result, const I& a, const I& b) { using default_ops::eval_multiply; using canonical_type = typename detail::canonical::type; eval_multiply(result.backend(), static_cast(a), static_cast(b)); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression::result_type trunc(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; return std::move(trunc(number_type(v), pol)); } template inline BOOST_MP_CXX14_CONSTEXPR number trunc(const number& v, const Policy&) { using default_ops::eval_trunc; detail::scoped_default_precision > precision_guard(v); number result; eval_trunc(result.backend(), v.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; number_type r(trunc(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, number_type(v), 0, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression& v) { return itrunc(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number& v, const Policy& pol) { number r(trunc(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, v, 0, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number& v) { return itrunc(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; number_type r(trunc(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, number_type(v), 0L, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression& v) { return ltrunc(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number& v, const Policy& pol) { number r(trunc(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, v, 0L, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number& v) { return ltrunc(v, boost::math::policies::policy<>()); } #ifndef BOOST_NO_LONG_LONG template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; number_type r(trunc(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, number_type(v), 0LL, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const detail::expression& v) { return lltrunc(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const number& v, const Policy& pol) { number r(trunc(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, v, 0LL, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type lltrunc(const number& v) { return lltrunc(v, boost::math::policies::policy<>()); } #endif template inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression::result_type round(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; return std::move(round(static_cast(v), pol)); } template inline BOOST_MP_CXX14_CONSTEXPR number round(const number& v, const Policy&) { using default_ops::eval_round; detail::scoped_default_precision > precision_guard(v); number result; eval_round(result.backend(), v.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; number_type r(round(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression& v) { return iround(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR int iround(const number& v, const Policy& pol) { number r(round(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR int iround(const number& v) { return iround(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; number_type r(round(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, number_type(v), 0L, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression& v) { return lround(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR long lround(const number& v, const Policy& pol) { number r(round(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, v, 0L, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR long lround(const number& v) { return lround(v, boost::math::policies::policy<>()); } #ifndef BOOST_NO_LONG_LONG template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const detail::expression& v, const Policy& pol) { using number_type = typename detail::expression::result_type; number_type r(round(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0LL, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const detail::expression& v) { return llround(v, boost::math::policies::policy<>()); } template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const number& v, const Policy& pol) { number r(round(v, pol)); if ((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0LL, pol); return r.template convert_to(); } template inline BOOST_MP_CXX14_CONSTEXPR boost::long_long_type llround(const number& v) { return llround(v, boost::math::policies::policy<>()); } #endif // // frexp does not return an expression template since we require the // integer argument to be evaluated even if the returned value is // not assigned to anything... // template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, number >::type frexp(const number& v, short* pint) { using default_ops::eval_frexp; detail::scoped_default_precision > precision_guard(v); number result; eval_frexp(result.backend(), v.backend(), pint); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, short* pint) { using number_type = typename detail::expression::result_type; return std::move(frexp(static_cast(v), pint)); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, number >::type frexp(const number& v, int* pint) { using default_ops::eval_frexp; detail::scoped_default_precision > precision_guard(v); number result; eval_frexp(result.backend(), v.backend(), pint); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, int* pint) { using number_type = typename detail::expression::result_type; return std::move(frexp(static_cast(v), pint)); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, number >::type frexp(const number& v, long* pint) { using default_ops::eval_frexp; detail::scoped_default_precision > precision_guard(v); number result; eval_frexp(result.backend(), v.backend(), pint); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, long* pint) { using number_type = typename detail::expression::result_type; return std::move(frexp(static_cast(v), pint)); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, number >::type frexp(const number& v, boost::long_long_type* pint) { using default_ops::eval_frexp; detail::scoped_default_precision > precision_guard(v); number result; eval_frexp(result.backend(), v.backend(), pint); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, boost::long_long_type* pint) { using number_type = typename detail::expression::result_type; return std::move(frexp(static_cast(v), pint)); } // // modf does not return an expression template since we require the // second argument to be evaluated even if the returned value is // not assigned to anything... // template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, number >::type modf(const number& v, number* pipart) { using default_ops::eval_modf; detail::scoped_default_precision > precision_guard(v); number result; eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : 0); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, number >::type modf(const detail::expression& v, number* pipart) { using default_ops::eval_modf; detail::scoped_default_precision > precision_guard(v); number result, arg(v); eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : 0); return result; } // // Integer square root: // template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, number >::type sqrt(const number& x) { using default_ops::eval_integer_sqrt; number s, r; eval_integer_sqrt(s.backend(), r.backend(), x.backend()); return s; } // // fma: // namespace default_ops { struct fma_func { template BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, const V& c) const { eval_multiply_add(result, a, b, c); } }; } // namespace default_ops template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value) && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value), detail::expression, U, V> >::type fma(const number& a, const U& b, const V& c) { return detail::expression, U, V>( default_ops::fma_func(), a, b, c); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category::result_type>::value == number_kind_floating_point) && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value) && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value), detail::expression, U, V> >::type fma(const detail::expression& a, const U& b, const V& c) { return detail::expression, U, V>( default_ops::fma_func(), a, b, c); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value) && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value), number >::type fma(const number& a, const U& b, const V& c) { using default_ops::eval_multiply_add; detail::scoped_default_precision > precision_guard(a, b, c); number result; eval_multiply_add(result.backend(), number::canonical_value(a), number::canonical_value(b), number::canonical_value(c)); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && boost::multiprecision::detail::is_arithmetic::value && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value), detail::expression, V> >::type fma(const U& a, const number& b, const V& c) { return detail::expression, V>( default_ops::fma_func(), a, b, c); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category::result_type>::value == number_kind_floating_point) && boost::multiprecision::detail::is_arithmetic::value && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value), detail::expression, V> >::type fma(const U& a, const detail::expression& b, const V& c) { return detail::expression, V>( default_ops::fma_func(), a, b, c); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && boost::multiprecision::detail::is_arithmetic::value && (is_number::value || is_number_expression::value || boost::multiprecision::detail::is_arithmetic::value), number >::type fma(const U& a, const number& b, const V& c) { using default_ops::eval_multiply_add; detail::scoped_default_precision > precision_guard(a, b, c); number result; eval_multiply_add(result.backend(), number::canonical_value(a), number::canonical_value(b), number::canonical_value(c)); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && boost::multiprecision::detail::is_arithmetic::value && boost::multiprecision::detail::is_arithmetic::value, detail::expression > >::type fma(const U& a, const V& b, const number& c) { return detail::expression >( default_ops::fma_func(), a, b, c); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category::result_type>::value == number_kind_floating_point) && boost::multiprecision::detail::is_arithmetic::value && boost::multiprecision::detail::is_arithmetic::value, detail::expression > >::type fma(const U& a, const V& b, const detail::expression& c) { return detail::expression >( default_ops::fma_func(), a, b, c); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && boost::multiprecision::detail::is_arithmetic::value && boost::multiprecision::detail::is_arithmetic::value, number >::type fma(const U& a, const V& b, const number& c) { using default_ops::eval_multiply_add; detail::scoped_default_precision > precision_guard(a, b, c); number result; eval_multiply_add(result.backend(), number::canonical_value(a), number::canonical_value(b), number::canonical_value(c)); return result; } namespace default_ops { struct remquo_func { template BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, int* pi) const { eval_remquo(result, a, b, pi); } }; } // namespace default_ops template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< number_category >::value == number_kind_floating_point, detail::expression, U, int*> >::type remquo(const number& a, const U& b, int* pi) { return detail::expression, U, int*>( default_ops::remquo_func(), a, b, pi); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< number_category::result_type>::value == number_kind_floating_point, detail::expression, U, int*> >::type remquo(const detail::expression& a, const U& b, int* pi) { return detail::expression, U, int*>( default_ops::remquo_func(), a, b, pi); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && !is_number::value && !is_number_expression::value, detail::expression, int*> >::type remquo(const U& a, const number& b, int* pi) { return detail::expression, int*>( default_ops::remquo_func(), a, b, pi); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category::result_type>::value == number_kind_floating_point) && !is_number::value && !is_number_expression::value, detail::expression, int*> >::type remquo(const U& a, const detail::expression& b, int* pi) { return detail::expression, int*>( default_ops::remquo_func(), a, b, pi); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< number_category >::value == number_kind_floating_point, number >::type remquo(const number& a, const U& b, int* pi) { using default_ops::eval_remquo; detail::scoped_default_precision > precision_guard(a, b); number result; eval_remquo(result.backend(), a.backend(), number::canonical_value(b), pi); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< (number_category >::value == number_kind_floating_point) && !is_number::value && !is_number_expression::value, number >::type remquo(const U& a, const number& b, int* pi) { using default_ops::eval_remquo; detail::scoped_default_precision > precision_guard(a, b); number result; eval_remquo(result.backend(), number::canonical_value(a), b.backend(), pi); return result; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, number >::type sqrt(const number& x, number& r) { using default_ops::eval_integer_sqrt; detail::scoped_default_precision > precision_guard(x, r); number s; eval_integer_sqrt(s.backend(), r.backend(), x.backend()); return s; } // clang-format off #define UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == category, number > ::type \ func(number&& arg) \ { \ detail::scoped_default_precision > precision_guard(arg); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func)(result.backend(), arg.backend()); \ return result; \ } \ #define BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == category, number >::type func(number&& arg, const number& a) \ { \ detail::scoped_default_precision > precision_guard(arg, a); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \ return result; \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == category, number >::type func(const number& arg, number&& a) \ { \ detail::scoped_default_precision > precision_guard(arg, a); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \ return result; \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == category, number >::type func(number&& arg, number&& a) \ { \ detail::scoped_default_precision > precision_guard(arg, a); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \ return result; \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category::value == category) && (std::is_convertible::result_type, number >::value), \ number > ::type \ func(number&& arg, const detail::expression& a) \ { \ return detail::expression, \ number, detail::expression > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category::value == category) && (std::is_convertible::result_type, number >::value), \ number > ::type \ func(const detail::expression& arg, number&& a) \ { \ return detail::expression, \ detail::expression, number > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type >::value && (number_category::value == category), \ number >::type \ func(number&& arg, const Arithmetic& a) \ { \ return detail::expression, \ number, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type >::value && (number_category::value == category), \ number > ::type \ func(const Arithmetic& arg, number&& a) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \ Arithmetic, number > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \ } \ #define UNARY_OP_FUNCTOR(func, category) \ namespace detail { \ template \ struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \ { \ BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result, arg); \ } \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ Backend temp; \ BOOST_JOIN(eval_, func) \ (temp, arg); \ result = std::move(temp); \ } \ }; \ } \ \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value == category, \ detail::expression >::type>, \ detail::expression > > ::type \ func(const detail::expression& arg) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type>, \ detail::expression > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type > (), arg); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == category, \ detail::expression, number > > ::type \ func(const number& arg) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \ number > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ boost::multiprecision::number_category::value == category, \ number >::type \ func(const number& arg) \ { \ detail::scoped_default_precision > precision_guard(arg); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func)(result.backend(), arg.backend()); \ return result; \ }\ UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\ #define BINARY_OP_FUNCTOR(func, category) \ namespace detail { \ template \ struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \ { \ BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Backend& a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result, arg, a); \ } \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Arithmetic& a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result, arg, number::canonical_value(a)); \ } \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Arithmetic& arg, const Backend& a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result, number::canonical_value(arg), a); \ } \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Backend& a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ Backend r; \ BOOST_JOIN(eval_, func) \ (r, arg, a); \ result = std::move(r); \ } \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Arithmetic& a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ Backend r; \ BOOST_JOIN(eval_, func) \ (r, arg, number::canonical_value(a)); \ result = std::move(r); \ } \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Arithmetic& arg, const Backend& a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ Backend r; \ BOOST_JOIN(eval_, func) \ (r, number::canonical_value(arg), a); \ result = std::move(r); \ } \ }; \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == category, detail::expression, number, number > > ::type \ func(const number& arg, const number& a) \ { \ return detail::expression, \ number, number > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category::value == category) && (std::is_convertible::result_type, number >::value), \ detail::expression, number, detail::expression > > ::type \ func(const number& arg, const detail::expression& a) \ { \ return detail::expression, \ number, detail::expression > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category::value == category) && (std::is_convertible::result_type, number >::value), \ detail::expression, detail::expression, number > > ::type \ func(const detail::expression& arg, const number& a) \ { \ return detail::expression, \ detail::expression, number > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category >::value == category) && (number_category >::value == category), \ detail::expression >::type>, \ detail::expression, detail::expression > > ::type \ func(const detail::expression& arg, const detail::expression& a) \ { \ return detail::expression >::type>, \ detail::expression, detail::expression > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) >::type>(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type >::value && (number_category::value == category), \ detail::expression, \ number, Arithmetic> > ::type \ func(const number& arg, const Arithmetic& a) \ { \ return detail::expression, \ number, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))(), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type::result_type>::value && (number_category >::value == category), \ detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type>, \ detail::expression, Arithmetic> > ::type \ func(const detail::expression& arg, const Arithmetic& a) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type>, \ detail::expression, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type > (), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type >::value && (number_category::value == category), \ detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \ Arithmetic, number > > ::type \ func(const Arithmetic& arg, const number& a) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \ Arithmetic, number > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type::result_type>::value && (number_category >::value == category), \ detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type>, \ Arithmetic, detail::expression > > ::type \ func(const Arithmetic& arg, const detail::expression& a) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type>, \ Arithmetic, detail::expression > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type > (), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category::value == category), number >::type \ func(const number& arg, const number& a) \ { \ detail::scoped_default_precision > precision_guard(arg, a); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \ return result; \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type >::value && (number_category::value == category), \ number >::type \ func(const number& arg, const Arithmetic& a) \ { \ detail::scoped_default_precision > precision_guard(arg); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result.backend(), arg.backend(), number::canonical_value(a)); \ return result; \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ is_compatible_arithmetic_type >::value && (number_category::value == category), \ number >::type \ func(const Arithmetic& a, const number& arg) \ { \ detail::scoped_default_precision > precision_guard(arg); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result.backend(), number::canonical_value(a), arg.backend()); \ return result; \ }\ BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category) #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category) \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ (number_category >::value == category), \ detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type>, \ detail::expression, Arg2> > ::type \ func(const detail::expression& arg, Arg2 const& a) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type>, \ detail::expression, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type >::type > (), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ (number_category::value == category), \ detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \ number, Arg2> > ::type \ func(const number& arg, Arg2 const& a) \ { \ return detail::expression< \ detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \ number, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \ } \ template \ inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \ (number_category::value == category), \ number >::type \ func(const number& arg, Arg2 const& a) \ { \ detail::scoped_default_precision > precision_guard(arg, a); \ number result; \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result.backend(), arg.backend(), a); \ return result; \ } #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category) \ namespace detail { \ template \ struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \ { \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, Backend const& arg, Arg a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ BOOST_JOIN(eval_, func) \ (result, arg, a); \ } \ template \ BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, Backend const& arg, Arg a) const \ { \ using default_ops::BOOST_JOIN(eval_, func); \ Backend temp; \ BOOST_JOIN(eval_, func) \ (temp, arg, a); \ result = std::move(temp); \ } \ }; \ } \ \ HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category) // clang-format on namespace detail { template struct abs_funct { BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const { using default_ops::eval_abs; eval_abs(result, arg); } }; template struct conj_funct { BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const { using default_ops::eval_conj; eval_conj(result, arg); } }; template struct proj_funct { BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const { using default_ops::eval_proj; eval_proj(result, arg); } }; } // namespace detail template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value != number_kind_complex, detail::expression< detail::function, detail::abs_funct >::type>, detail::expression > >::type abs(const detail::expression& arg) { return detail::expression< detail::function, detail::abs_funct >::type>, detail::expression >( detail::abs_funct >::type>(), arg); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value != number_kind_complex, detail::expression< detail::function, detail::abs_funct, number > >::type abs(const number& arg) { return detail::expression< detail::function, detail::abs_funct, number >( detail::abs_funct(), arg); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value != number_kind_complex, number >::type abs(const number& arg) { detail::scoped_default_precision > precision_guard(arg); number result; using default_ops::eval_abs; eval_abs(result.backend(), arg.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR detail::expression< detail::function, detail::conj_funct >::type>, detail::expression > conj(const detail::expression& arg) { return detail::expression< detail::function, detail::conj_funct >::type>, detail::expression >( detail::conj_funct >::type>(), arg); } template inline BOOST_MP_CXX14_CONSTEXPR detail::expression< detail::function, detail::conj_funct, number > conj(const number& arg) { return detail::expression< detail::function, detail::conj_funct, number >( detail::conj_funct(), arg); } template inline BOOST_MP_CXX14_CONSTEXPR number conj(const number& arg) { detail::scoped_default_precision > precision_guard(arg); number result; using default_ops::eval_conj; eval_conj(result.backend(), arg.backend()); return result; } template inline BOOST_MP_CXX14_CONSTEXPR detail::expression< detail::function, detail::proj_funct >::type>, detail::expression > proj(const detail::expression& arg) { return detail::expression< detail::function, detail::proj_funct >::type>, detail::expression >( detail::proj_funct >::type>(), arg); } template inline BOOST_MP_CXX14_CONSTEXPR detail::expression< detail::function, detail::proj_funct, number > proj(const number& arg) { return detail::expression< detail::function, detail::proj_funct, number >( detail::proj_funct(), arg); } template inline BOOST_MP_CXX14_CONSTEXPR number proj(const number& arg) { detail::scoped_default_precision > precision_guard(arg); number result; using default_ops::eval_proj; eval_proj(result.backend(), arg.backend()); return result; } UNARY_OP_FUNCTOR(fabs, number_kind_floating_point) UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point) UNARY_OP_FUNCTOR(floor, number_kind_floating_point) UNARY_OP_FUNCTOR(ceil, number_kind_floating_point) UNARY_OP_FUNCTOR(trunc, number_kind_floating_point) UNARY_OP_FUNCTOR(round, number_kind_floating_point) UNARY_OP_FUNCTOR(exp, number_kind_floating_point) UNARY_OP_FUNCTOR(exp2, number_kind_floating_point) UNARY_OP_FUNCTOR(log, number_kind_floating_point) UNARY_OP_FUNCTOR(log10, number_kind_floating_point) UNARY_OP_FUNCTOR(cos, number_kind_floating_point) UNARY_OP_FUNCTOR(sin, number_kind_floating_point) UNARY_OP_FUNCTOR(tan, number_kind_floating_point) UNARY_OP_FUNCTOR(asin, number_kind_floating_point) UNARY_OP_FUNCTOR(acos, number_kind_floating_point) UNARY_OP_FUNCTOR(atan, number_kind_floating_point) UNARY_OP_FUNCTOR(cosh, number_kind_floating_point) UNARY_OP_FUNCTOR(sinh, number_kind_floating_point) UNARY_OP_FUNCTOR(tanh, number_kind_floating_point) UNARY_OP_FUNCTOR(log2, number_kind_floating_point) UNARY_OP_FUNCTOR(nearbyint, number_kind_floating_point) UNARY_OP_FUNCTOR(rint, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point) //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point) //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point) //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(ldexp, boost::long_long_type, number_kind_floating_point) //HETERO_BINARY_OP_FUNCTOR_B(frexp, boost::long_long_type*, number_kind_floating_point) BINARY_OP_FUNCTOR(pow, number_kind_floating_point) BINARY_OP_FUNCTOR(fmod, number_kind_floating_point) BINARY_OP_FUNCTOR(fmax, number_kind_floating_point) BINARY_OP_FUNCTOR(fmin, number_kind_floating_point) BINARY_OP_FUNCTOR(atan2, number_kind_floating_point) BINARY_OP_FUNCTOR(fdim, number_kind_floating_point) BINARY_OP_FUNCTOR(hypot, number_kind_floating_point) BINARY_OP_FUNCTOR(remainder, number_kind_floating_point) UNARY_OP_FUNCTOR(logb, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR(scalbln, short, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbln, int, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbln, long, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbn, boost::long_long_type, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbln, boost::long_long_type, number_kind_floating_point) // // Complex functions: // UNARY_OP_FUNCTOR(exp, number_kind_complex) UNARY_OP_FUNCTOR(log, number_kind_complex) UNARY_OP_FUNCTOR(log10, number_kind_complex) BINARY_OP_FUNCTOR(pow, number_kind_complex) UNARY_OP_FUNCTOR(sqrt, number_kind_complex) UNARY_OP_FUNCTOR(sin, number_kind_complex) UNARY_OP_FUNCTOR(cos, number_kind_complex) UNARY_OP_FUNCTOR(tan, number_kind_complex) UNARY_OP_FUNCTOR(asin, number_kind_complex) UNARY_OP_FUNCTOR(acos, number_kind_complex) UNARY_OP_FUNCTOR(atan, number_kind_complex) UNARY_OP_FUNCTOR(sinh, number_kind_complex) UNARY_OP_FUNCTOR(cosh, number_kind_complex) UNARY_OP_FUNCTOR(tanh, number_kind_complex) UNARY_OP_FUNCTOR(asinh, number_kind_complex) UNARY_OP_FUNCTOR(acosh, number_kind_complex) UNARY_OP_FUNCTOR(atanh, number_kind_complex) // // Integer functions: // BINARY_OP_FUNCTOR(gcd, number_kind_integer) BINARY_OP_FUNCTOR(lcm, number_kind_integer) HETERO_BINARY_OP_FUNCTOR(pow, unsigned, number_kind_integer) #undef BINARY_OP_FUNCTOR #undef UNARY_OP_FUNCTOR // // ilogb: // template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_floating_point, typename Backend::exponent_type>::type ilogb(const multiprecision::number& val) { using default_ops::eval_ilogb; return eval_ilogb(val.backend()); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value == number_kind_floating_point, typename multiprecision::detail::expression::result_type::backend_type::exponent_type>::type ilogb(const detail::expression& val) { using default_ops::eval_ilogb; typename multiprecision::detail::expression::result_type arg(val); return eval_ilogb(arg.backend()); } } //namespace multiprecision namespace math { // // Overload of Boost.Math functions that find the wrong overload when used with number: // namespace detail { template T sinc_pi_imp(T); template T sinhc_pi_imp(T); } // namespace detail template inline multiprecision::number sinc_pi(const multiprecision::number& x) { boost::multiprecision::detail::scoped_default_precision > precision_guard(x); return std::move(detail::sinc_pi_imp(x)); } template inline multiprecision::number sinc_pi(const multiprecision::number& x, const Policy&) { boost::multiprecision::detail::scoped_default_precision > precision_guard(x); return std::move(detail::sinc_pi_imp(x)); } template inline multiprecision::number sinhc_pi(const multiprecision::number& x) { boost::multiprecision::detail::scoped_default_precision > precision_guard(x); return std::move(detail::sinhc_pi_imp(x)); } template inline multiprecision::number sinhc_pi(const multiprecision::number& x, const Policy&) { boost::multiprecision::detail::scoped_default_precision > precision_guard(x); return std::move(boost::math::sinhc_pi(x)); } using boost::multiprecision::gcd; using boost::multiprecision::lcm; #ifdef BOOST_MSVC #pragma warning(pop) #endif } // namespace math namespace integer { using boost::multiprecision::gcd; using boost::multiprecision::lcm; } // namespace integer } // namespace boost // // This has to come last of all: // #include #include // // min/max overloads: // #include #endif