/////////////////////////////////////////////////////////////////////////////// // 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 #include #include #include #include #include #include #include #include #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 mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); template void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); template void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); template void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); template void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); } namespace default_ops{ #ifdef BOOST_MSVC // warning C4127: conditional expression is constant #pragma warning(push) #pragma warning(disable:4127) #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 typename disable_if_c::value >::type eval_add(T& result, V const& v) { T t; t = v; eval_add(result, t); } template inline typename enable_if_c::value >::type eval_add(T& result, V const& v) { T t(v); eval_add(result, t); } template inline typename disable_if_c::value>::type eval_subtract(T& result, V const& v) { T t; t = v; eval_subtract(result, t); } template inline typename enable_if_c::value>::type eval_subtract(T& result, V const& v) { T t(v); eval_subtract(result, t); } template inline typename disable_if_c::value>::type eval_multiply(T& result, V const& v) { T t; t = v; eval_multiply(result, t); } template inline typename enable_if_c::value>::type eval_multiply(T& result, V const& v) { T t(v); eval_multiply(result, t); } template void eval_multiply(T& t, const U& u, const V& v); template inline typename disable_if_c::value && 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 typename enable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v) { eval_multiply_add(t, v, u); } template inline typename disable_if_c::value && 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 typename enable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v) { eval_multiply_subtract(t, v, u); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide(T& result, V const& v) { T t; t = v; eval_divide(result, t); } template inline typename enable_if_c >::value && is_convertible::value>::type eval_divide(T& result, V const& v) { T t(v); eval_divide(result, t); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus(T& result, V const& v) { T t; t = v; eval_modulus(result, t); } template inline typename enable_if_c >::value&& is_convertible::value>::type eval_modulus(T& result, V const& v) { T t(v); eval_modulus(result, t); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_and(T& result, V const& v) { T t; t = v; eval_bitwise_and(result, t); } template inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_and(T& result, V const& v) { T t(v); eval_bitwise_and(result, t); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_or(T& result, V const& v) { T t; t = v; eval_bitwise_or(result, t); } template inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_or(T& result, V const& v) { T t(v); eval_bitwise_or(result, t); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_xor(T& result, V const& v) { T t; t = v; eval_bitwise_xor(result, t); } template inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_xor(T& result, V const& v) { T t(v); eval_bitwise_xor(result, t); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_complement(T& result, V const& v) { T t; t = v; eval_complement(result, t); } template inline typename enable_if_c >::value && 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 void eval_add(T& t, const U& u, const V& v); template inline 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 typename enable_if_c >::value>::type eval_add_default(T& t, const U& u, const T& v) { eval_add(t, v, u); } template inline void eval_add_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { eval_add(t, u); } else { t = u; eval_add(t, v); } } template inline void eval_add(T& t, const U& u, const V& v) { eval_add_default(t, u, v); } template void eval_subtract(T& t, const U& u, const V& v); template inline 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 typename enable_if_c >::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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 void eval_subtract_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { eval_subtract(t, u); t.negate(); } else { t = u; eval_subtract(t, v); } } template inline void eval_subtract(T& t, const U& u, const V& v) { eval_subtract_default(t, u, v); } template inline 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 typename enable_if_c >::value>::type eval_multiply_default(T& t, const U& u, const T& v) { eval_multiply(t, v, u); } #endif template inline void eval_multiply_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { eval_multiply(t, u); } else { t = number::canonical_value(u); eval_multiply(t, v); } } template inline void eval_multiply(T& t, const U& u, const V& v) { eval_multiply_default(t, u, v); } template inline 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 typename boost::disable_if_c::value, T>::type make_T(const U& u) { T t; t = number::canonical_value(u); return BOOST_MP_MOVE(t); } template inline const T& make_T(const T& t) { return t; } template inline typename disable_if_c::value && 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 typename enable_if_c::value && 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 typename disable_if_c::value && 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 typename enable_if_c::value && 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 void eval_divide(T& t, const U& u, const V& v); template inline 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 void eval_divide_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { T temp; temp = u; eval_divide(temp, v); t = temp; } else { t = u; eval_divide(t, v); } } template inline void eval_divide(T& t, const U& u, const V& v) { eval_divide_default(t, u, v); } template void eval_modulus(T& t, const U& u, const V& v); template inline 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 void eval_modulus_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { T temp(u); eval_modulus(temp, v); t = temp; } else { t = u; eval_modulus(t, v); } } template inline void eval_modulus(T& t, const U& u, const V& v) { eval_modulus_default(t, u, v); } template void eval_bitwise_and(T& t, const U& u, const V& v); template inline 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 typename disable_if_c::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 typename enable_if_c::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 typename enable_if_c >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v) { eval_bitwise_and(t, v, u); } template inline typename disable_if_c::value || 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 void eval_bitwise_and(T& t, const U& u, const V& v) { eval_bitwise_and_default(t, u, v); } template void eval_bitwise_or(T& t, const U& u, const V& v); template inline 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 typename enable_if_c >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v) { eval_bitwise_or(t, v, u); } template inline void eval_bitwise_or_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { eval_bitwise_or(t, u); } else { t = u; eval_bitwise_or(t, v); } } template inline void eval_bitwise_or(T& t, const U& u, const V& v) { eval_bitwise_or_default(t, u, v); } template void eval_bitwise_xor(T& t, const U& u, const V& v); template inline 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 typename enable_if_c >::value && !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 typename enable_if_c >::value && 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 typename enable_if_c >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v) { eval_bitwise_xor(t, v, u); } template inline void eval_bitwise_xor_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { eval_bitwise_xor(t, u); } else { t = u; eval_bitwise_xor(t, v); } } template inline void eval_bitwise_xor(T& t, const U& u, const V& v) { eval_bitwise_xor_default(t, u, v); } template inline void eval_increment(T& val) { typedef typename mpl::front::type ui_type; eval_add(val, static_cast(1u)); } template inline void eval_decrement(T& val) { typedef typename mpl::front::type ui_type; eval_subtract(val, static_cast(1u)); } template inline void eval_left_shift(T& result, const T& arg, const V val) { result = arg; eval_left_shift(result, val); } template inline void eval_right_shift(T& result, const T& arg, const V val) { result = arg; eval_right_shift(result, val); } template inline bool eval_is_zero(const T& val) { typedef typename mpl::front::type ui_type; return val.compare(static_cast(0)) == 0; } template inline int eval_get_sign(const T& val) { typedef typename mpl::front::type ui_type; return val.compare(static_cast(0)); } template inline void assign_components_imp(T& result, const V& v1, const V& v2, const mpl::int_&) { result = v1; T t; t = v2; eval_divide(result, t); } template inline void assign_components(T& result, const V& v1, const V& v2) { return assign_components_imp(result, v1, v2, typename number_category::type()); } template struct has_enough_bits { template struct type : public mpl::and_ >, mpl::bool_::digits >= b> >{}; }; template struct terminal { terminal(const R& v) : value(v){} terminal(){} terminal& operator = (R val) { value = val; return *this; } R value; operator R()const { return value; } }; template struct calculate_next_larger_type { // Find which list we're looking through: typedef typename mpl::if_< is_signed, typename B::signed_types, typename mpl::if_< is_unsigned, typename B::unsigned_types, typename B::float_types >::type >::type list_type; // A predicate to find a type with enough bits: typedef typename has_enough_bits::digits>::template type pred_type; // See if the last type is in the list, if so we have to start after this: typedef typename mpl::find_if< list_type, is_same >::type start_last; // Where we're starting from, either the start of the sequence or the last type found: typedef typename mpl::if_::type>, typename mpl::begin::type, start_last>::type start_seq; // The range we're searching: typedef mpl::iterator_range::type> range; // Find the next type: typedef typename mpl::find_if< range, pred_type >::type iter_type; // Either the next type, or a "terminal" to indicate we've run out of types to search: typedef typename mpl::eval_if< is_same::type, iter_type>, mpl::identity >, mpl::deref >::type type; }; template inline bool check_in_range(const T& t) { // Can t fit in an R? if(std::numeric_limits::is_specialized && std::numeric_limits::is_bounded && (t > (std::numeric_limits::max)())) return true; return false; } template inline bool check_in_range(const terminal&) { return false; } template inline void eval_convert_to(R* result, const B& backend) { typedef typename calculate_next_larger_type::type next_type; next_type n; eval_convert_to(&n, backend); if(check_in_range(n)) { *result = (std::numeric_limits::max)(); } else *result = static_cast(n); } template inline void eval_convert_to(terminal* result, const B& backend) { // // We ran out of types to try for the conversion, try // a lexical_cast and hope for the best: // result->value = boost::lexical_cast(backend.str(0, std::ios_base::fmtflags(0))); } template inline 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 void eval_convert_to(std::string* result, const B& backend) { *result = backend.str(0, std::ios_base::fmtflags(0)); } // // Functions: // template void eval_abs(T& result, const T& arg) { typedef typename T::signed_types type_list; typedef typename mpl::front::type front; result = arg; if(arg.compare(front(0)) < 0) result.negate(); } template void eval_fabs(T& result, const T& arg) { BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The fabs function is only valid for floating point types."); typedef typename T::signed_types type_list; typedef typename mpl::front::type front; result = arg; if(arg.compare(front(0)) < 0) result.negate(); } template inline int eval_fpclassify(const Backend& arg) { BOOST_STATIC_ASSERT_MSG(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 void eval_fmod(T& result, const T& a, const T& b) { BOOST_STATIC_ASSERT_MSG(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 typename enable_if, void>::type eval_fmod(T& result, const T& x, const A& a) { typedef typename boost::multiprecision::detail::canonical::type canonical_type; typedef typename mpl::if_, T, canonical_type>::type cast_type; cast_type c; c = a; eval_fmod(result, x, c); } template inline typename enable_if, void>::type eval_fmod(T& result, const A& x, const T& a) { typedef typename boost::multiprecision::detail::canonical::type canonical_type; typedef typename mpl::if_, T, canonical_type>::type cast_type; cast_type c; c = x; eval_fmod(result, c, a); } template void eval_round(T& result, const T& a); template inline void eval_remquo(T& result, const T& a, const T& b, int* pi) { BOOST_STATIC_ASSERT_MSG(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 typename enable_if, void>::type eval_remquo(T& result, const T& x, const A& a, int* pi) { typedef typename boost::multiprecision::detail::canonical::type canonical_type; typedef typename mpl::if_, T, canonical_type>::type cast_type; cast_type c; c = a; eval_remquo(result, x, c, pi); } template inline typename enable_if, void>::type eval_remquo(T& result, const A& x, const T& a, int* pi) { typedef typename boost::multiprecision::detail::canonical::type canonical_type; typedef typename mpl::if_, T, canonical_type>::type cast_type; cast_type c; c = x; eval_remquo(result, c, a, pi); } template inline void eval_remainder(T& result, const U& a, const V& b) { int i; eval_remquo(result, a, b, &i); } template bool eval_gt(const B& a, const B& b); template bool eval_gt(const T& a, const U& b); template bool eval_lt(const B& a, const B& b); template bool eval_lt(const T& a, const U& b); template inline void eval_fdim(T& result, const T& a, const T& b) { typedef typename boost::multiprecision::detail::canonical::type ui_type; static 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 typename boost::enable_if_c::value>::type eval_fdim(T& result, const T& a, const A& b) { typedef typename boost::multiprecision::detail::canonical::type ui_type; typedef typename boost::multiprecision::detail::canonical::type arithmetic_type; static 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 typename boost::enable_if_c::value>::type eval_fdim(T& result, const A& a, const T& b) { typedef typename boost::multiprecision::detail::canonical::type ui_type; typedef typename boost::multiprecision::detail::canonical::type arithmetic_type; static 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 void eval_trunc(T& result, const T& a) { BOOST_STATIC_ASSERT_MSG(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 void eval_modf(T& result, T const& arg, T* pipart) { typedef typename boost::multiprecision::detail::canonical::type ui_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 void eval_round(T& result, const T& a) { BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The round function is only valid for floating point types."); typedef typename boost::multiprecision::detail::canonical::type fp_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 void eval_lcm(B& result, const B& a, const B& b); template void eval_gcd(B& result, const B& a, const B& b); template inline typename enable_if >::type eval_gcd(T& result, const T& a, const Arithmetic& b) { typedef typename boost::multiprecision::detail::canonical::type si_type; using default_ops::eval_gcd; T t; t = static_cast(b); eval_gcd(result, a, t); } template inline typename enable_if >::type eval_gcd(T& result, const Arithmetic& a, const T& b) { eval_gcd(result, b, a); } template inline typename enable_if >::type eval_lcm(T& result, const T& a, const Arithmetic& b) { typedef typename boost::multiprecision::detail::canonical::type si_type; using default_ops::eval_lcm; T t; t = static_cast(b); eval_lcm(result, a, t); } template inline typename enable_if >::type eval_lcm(T& result, const Arithmetic& a, const T& b) { eval_lcm(result, b, a); } template inline unsigned eval_lsb(const T& val) { typedef typename boost::multiprecision::detail::canonical::type ui_type; int c = eval_get_sign(val); if(c == 0) { BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); } if(c < 0) { BOOST_THROW_EXCEPTION(std::range_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 int eval_msb(const T& val) { int c = eval_get_sign(val); if(c == 0) { BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); } if(c < 0) { BOOST_THROW_EXCEPTION(std::range_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 bool eval_bit_test(const T& val, unsigned index) { typedef typename boost::multiprecision::detail::canonical::type ui_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 void eval_bit_set(T& val, unsigned index) { typedef typename boost::multiprecision::detail::canonical::type ui_type; T mask; mask = ui_type(1); eval_left_shift(mask, index); eval_bitwise_or(val, mask); } template inline void eval_bit_flip(T& val, unsigned index) { typedef typename boost::multiprecision::detail::canonical::type ui_type; T mask; mask = ui_type(1); eval_left_shift(mask, index); eval_bitwise_xor(val, mask); } template inline void eval_bit_unset(T& val, unsigned index) { typedef typename boost::multiprecision::detail::canonical::type ui_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 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. // typedef typename boost::multiprecision::detail::canonical::type ui_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); } // // These have to implemented by the backend, declared here so that our macro generated code compiles OK. // template typename enable_if_c::type eval_floor(); template typename enable_if_c::type eval_ceil(); template typename enable_if_c::type eval_trunc(); template typename enable_if_c::type eval_sqrt(); template typename enable_if_c::type eval_ldexp(); template typename enable_if_c::type eval_frexp(); // // eval_logb and eval_scalbn simply assume base 2 and forward to // eval_ldexp and eval_frexp: // template inline typename B::exponent_type eval_ilogb(const B& val) { BOOST_STATIC_ASSERT_MSG(!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; 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 int eval_signbit(const T& val); template inline 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; } typedef typename boost::mpl::if_c::value, boost::long_long_type, boost::intmax_t>::type max_t; result = static_cast(eval_ilogb(val)); } template inline void eval_scalbn(B& result, const B& val, A e) { BOOST_STATIC_ASSERT_MSG(!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 void eval_scalbln(B& result, const B& val, A e) { eval_scalbn(result, val, e); } template inline bool is_arg_nan(const T& val, mpl::true_ const&, const mpl::false_&) { return eval_fpclassify(val) == FP_NAN; } template inline bool is_arg_nan(const T& val, mpl::false_ const&, const mpl::true_&) { return (boost::math::isnan)(val); } template inline bool is_arg_nan(const T&, mpl::false_ const&, const mpl::false_&) { return false; } template inline bool is_arg_nan(const T& val) { return is_arg_nan(val, mpl::bool_::value>(), is_floating_point()); } template inline 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 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 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 void eval_nearbyint(R& result, const T& a) { eval_round(result, a); } template inline void eval_rint(R& result, const T& a) { eval_nearbyint(result, a); } template inline int eval_signbit(const T& val) { return eval_get_sign(val) < 0 ? 1 : 0; } // // These functions are implemented in separate files, but expanded inline here, // DO NOT CHANGE THE ORDER OF THESE INCLUDES: // #include #include #include } // // Default versions of floating point classification routines: // template inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { using multiprecision::default_ops::eval_fpclassify; return eval_fpclassify(arg.backend()); } template inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline 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 bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_NAN; } template inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return isnan BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_INFINITE; } template inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return isinf BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == (int)FP_NORMAL; } template inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_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 int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return arg.sign(); } template inline int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return sign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { using default_ops::eval_signbit; return eval_signbit(arg.backend()); } template inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline multiprecision::number changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return -arg; } template inline typename multiprecision::detail::expression::result_type changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return changesign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)); } template inline 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 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 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 typename multiprecision::detail::expression::result_type copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::detail::expression& b) { typedef typename multiprecision::detail::expression::result_type value_type; return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b)); } } // namespace multiprecision namespace math { // // Import Math functions here, so they can be found by Boost.Math: // using boost::multiprecision::signbit; using boost::multiprecision::sign; using boost::multiprecision::copysign; using boost::multiprecision::changesign; using boost::multiprecision::fpclassify; using boost::multiprecision::isinf; using boost::multiprecision::isnan; using boost::multiprecision::isnormal; using boost::multiprecision::isfinite; } namespace multiprecision{ typedef ::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> > c99_error_policy; template inline multiprecision::number asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::asinh(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return asinh(value_type(arg)); } template inline multiprecision::number acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::acosh(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return acosh(value_type(arg)); } template inline multiprecision::number atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::atanh(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return atanh(value_type(arg)); } template inline multiprecision::number cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::cbrt(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return cbrt(value_type(arg)); } template inline multiprecision::number erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::erf(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return erf(value_type(arg)); } template inline multiprecision::number erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::erfc(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return erfc(value_type(arg)); } template inline multiprecision::number expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::expm1(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return expm1(value_type(arg)); } template inline multiprecision::number lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& 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 typename multiprecision::detail::expression::result_type lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return lgamma(value_type(arg)); } template inline multiprecision::number tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { if((arg == 0) && std::numeric_limits >::has_infinity) { errno = ERANGE; return 1 / arg; } return boost::math::tgamma(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return tgamma(value_type(arg)); } template inline long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return lround(arg); } template inline long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { return lround(arg); } #ifndef BOOST_NO_LONG_LONG template inline boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return llround(arg); } template inline boost::long_long_type llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { return llround(arg); } #endif template inline multiprecision::number log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return boost::math::log1p(arg, c99_error_policy()); } template inline typename multiprecision::detail::expression::result_type log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) { typedef typename multiprecision::detail::expression::result_type value_type; return log1p(value_type(arg)); } template inline multiprecision::number nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::number& b) { return boost::math::nextafter(a, b, c99_error_policy()); } template inline multiprecision::number nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::detail::expression& b) { return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number(b)); } template inline multiprecision::number nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::number& b) { return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number(a), b); } template inline typename multiprecision::detail::expression::result_type nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::detail::expression& b) { typedef typename multiprecision::detail::expression::result_type value_type; return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b)); } template inline multiprecision::number nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::number& b) { return boost::math::nextafter(a, b, c99_error_policy()); } template inline multiprecision::number nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& a, const multiprecision::detail::expression& b) { return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number(b)); } template inline multiprecision::number nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::number& b) { return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number(a), b); } template inline typename multiprecision::detail::expression::result_type nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& a, const multiprecision::detail::expression& b) { typedef typename multiprecision::detail::expression::result_type value_type; return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b)); } template inline number& add(number& result, const number& a, const number& b) { BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); BOOST_STATIC_ASSERT_MSG((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 number& subtract(number& result, const number& a, const number& b) { BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); BOOST_STATIC_ASSERT_MSG((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 number& multiply(number& result, const number& a, const number& b) { BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); BOOST_STATIC_ASSERT_MSG((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 typename enable_if_c::value, number&>::type add(number& result, const I& a, const I& b) { using default_ops::eval_add; typedef typename detail::canonical::type canonical_type; eval_add(result.backend(), static_cast(a), static_cast(b)); return result; } template inline typename enable_if_c::value, number&>::type subtract(number& result, const I& a, const I& b) { using default_ops::eval_subtract; typedef typename detail::canonical::type canonical_type; eval_subtract(result.backend(), static_cast(a), static_cast(b)); return result; } template inline typename enable_if_c::value, number&>::type multiply(number& result, const I& a, const I& b) { using default_ops::eval_multiply; typedef typename detail::canonical::type canonical_type; eval_multiply(result.backend(), static_cast(a), static_cast(b)); return result; } template inline typename detail::expression::result_type trunc(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_type; return BOOST_MP_MOVE(trunc(number_type(v), pol)); } template inline number trunc(const number& v, const Policy&) { using default_ops::eval_trunc; number result; eval_trunc(result.backend(), v.backend()); return BOOST_MP_MOVE(result); } template inline int itrunc(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_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 int itrunc(const detail::expression& v) { return itrunc(v, boost::math::policies::policy<>()); } template inline 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 int itrunc(const number& v) { return itrunc(v, boost::math::policies::policy<>()); } template inline long ltrunc(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_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 long ltrunc(const detail::expression& v) { return ltrunc(v, boost::math::policies::policy<>()); } template inline 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 long ltrunc(const number& v) { return ltrunc(v, boost::math::policies::policy<>()); } #ifndef BOOST_NO_LONG_LONG template inline boost::long_long_type lltrunc(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_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::long_long_type lltrunc(const detail::expression& v) { return lltrunc(v, boost::math::policies::policy<>()); } template inline 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::long_long_type lltrunc(const number& v) { return lltrunc(v, boost::math::policies::policy<>()); } #endif template inline typename detail::expression::result_type round(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_type; return BOOST_MP_MOVE(round(static_cast(v), pol)); } template inline number round(const number& v, const Policy&) { using default_ops::eval_round; number result; eval_round(result.backend(), v.backend()); return BOOST_MP_MOVE(result); } template inline int iround(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_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 int iround(const detail::expression& v) { return iround(v, boost::math::policies::policy<>()); } template inline 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 int iround(const number& v) { return iround(v, boost::math::policies::policy<>()); } template inline long lround(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_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 long lround(const detail::expression& v) { return lround(v, boost::math::policies::policy<>()); } template inline 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 long lround(const number& v) { return lround(v, boost::math::policies::policy<>()); } #ifndef BOOST_NO_LONG_LONG template inline boost::long_long_type llround(const detail::expression& v, const Policy& pol) { typedef typename detail::expression::result_type number_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::long_long_type llround(const detail::expression& v) { return llround(v, boost::math::policies::policy<>()); } template inline 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::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 typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, short* pint) { using default_ops::eval_frexp; number result; eval_frexp(result.backend(), v.backend(), pint); return BOOST_MP_MOVE(result); } template inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, short* pint) { typedef typename detail::expression::result_type number_type; return BOOST_MP_MOVE(frexp(static_cast(v), pint)); } template inline typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, int* pint) { using default_ops::eval_frexp; number result; eval_frexp(result.backend(), v.backend(), pint); return BOOST_MP_MOVE(result); } template inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, int* pint) { typedef typename detail::expression::result_type number_type; return BOOST_MP_MOVE(frexp(static_cast(v), pint)); } template inline typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, long* pint) { using default_ops::eval_frexp; number result; eval_frexp(result.backend(), v.backend(), pint); return BOOST_MP_MOVE(result); } template inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, long* pint) { typedef typename detail::expression::result_type number_type; return BOOST_MP_MOVE(frexp(static_cast(v), pint)); } template inline typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, boost::long_long_type* pint) { using default_ops::eval_frexp; number result; eval_frexp(result.backend(), v.backend(), pint); return BOOST_MP_MOVE(result); } template inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type frexp(const detail::expression& v, boost::long_long_type* pint) { typedef typename detail::expression::result_type number_type; return BOOST_MP_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 typename enable_if_c::value == number_kind_floating_point, number >::type modf(const number& v, number* pipart) { using default_ops::eval_modf; number result; eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : 0); return BOOST_MP_MOVE(result); } template inline typename enable_if_c::value == number_kind_floating_point, number >::type modf(const detail::expression& v, number* pipart) { using default_ops::eval_modf; number result, arg(v); eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : 0); return BOOST_MP_MOVE(result); } // // Integer square root: // template inline typename enable_if_c::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 void operator()(B& result, const T& a, const U& b, const V& c)const { eval_multiply_add(result, a, b, c); } }; } template inline typename enable_if< mpl::and_< mpl::bool_ >::value == number_kind_floating_point>, mpl::or_< is_number, is_number_expression, is_arithmetic >, mpl::or_< is_number, is_number_expression, is_arithmetic > >, 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 typename enable_if< mpl::and_< mpl::bool_::result_type >::value == number_kind_floating_point>, mpl::or_< is_number, is_number_expression, is_arithmetic >, mpl::or_< is_number, is_number_expression, is_arithmetic > >, 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 typename enable_if< mpl::and_< mpl::bool_ >::value == number_kind_floating_point>, mpl::or_< is_number, is_number_expression, is_arithmetic >, mpl::or_< is_number, is_number_expression, is_arithmetic > >, number >::type fma(const number& a, const U& b, const V& c) { using default_ops::eval_multiply_add; number result; eval_multiply_add(result.backend(), number::canonical_value(a), number::canonical_value(b), number::canonical_value(c)); return BOOST_MP_MOVE(result); } template inline typename enable_if< mpl::and_< mpl::bool_ >::value == number_kind_floating_point>, is_arithmetic, mpl::or_< is_number, is_number_expression, is_arithmetic > >, 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 typename enable_if< mpl::and_< mpl::bool_::result_type >::value == number_kind_floating_point>, is_arithmetic, mpl::or_< is_number, is_number_expression, is_arithmetic > >, 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 typename enable_if< mpl::and_< mpl::bool_ >::value == number_kind_floating_point>, is_arithmetic, mpl::or_< is_number, is_number_expression, is_arithmetic > >, number >::type fma(const U& a, const number& b, const V& c) { using default_ops::eval_multiply_add; number result; eval_multiply_add(result.backend(), number::canonical_value(a), number::canonical_value(b), number::canonical_value(c)); return BOOST_MP_MOVE(result); } template inline typename enable_if< mpl::and_< mpl::bool_ >::value == number_kind_floating_point>, is_arithmetic, is_arithmetic >, 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 typename enable_if< mpl::and_< mpl::bool_::result_type >::value == number_kind_floating_point>, is_arithmetic, is_arithmetic >, 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 typename enable_if< mpl::and_< mpl::bool_ >::value == number_kind_floating_point>, is_arithmetic, is_arithmetic >, number >::type fma(const U& a, const V& b, const number& c) { using default_ops::eval_multiply_add; number result; eval_multiply_add(result.backend(), number::canonical_value(a), number::canonical_value(b), number::canonical_value(c)); return BOOST_MP_MOVE(result); } namespace default_ops { struct remquo_func { template void operator()(B& result, const T& a, const U& b, int* pi)const { eval_remquo(result, a, b, pi); } }; } template inline typename enable_if_c< 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 typename enable_if_c< 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 typename enable_if_c< (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 typename enable_if_c< (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 typename enable_if_c< number_category >::value == number_kind_floating_point, number >::type remquo(const number& a, const U& b, int* pi) { using default_ops::eval_remquo; number result; eval_remquo(result.backend(), a.backend(), number::canonical_value(b), pi); return BOOST_MP_MOVE(result); } template inline typename enable_if_c< (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; number result; eval_remquo(result.backend(), number::canonical_value(a), b.backend(), pi); return BOOST_MP_MOVE(result); } template inline typename enable_if_c::value == number_kind_integer, number >::type sqrt(const number& x, number& r) { using default_ops::eval_integer_sqrt; number s; eval_integer_sqrt(s.backend(), r.backend(), x.backend()); return s; } #define UNARY_OP_FUNCTOR(func, category)\ namespace detail{\ template \ struct BOOST_JOIN(func, _funct)\ {\ void operator()(Backend& result, const Backend& arg)const\ {\ using default_ops::BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result, arg);\ }\ };\ \ }\ \ template \ inline typename enable_if_c >::value == category,\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression > \ >::type \ func(const detail::expression& arg)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression \ > (\ detail::BOOST_JOIN(func, _funct) >::type>() \ , arg \ );\ }\ template \ inline typename enable_if_c::value == category,\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number > \ >::type \ func(const number& arg)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg \ );\ }\ template \ inline typename boost::enable_if_c<\ boost::multiprecision::number_category::value == category,\ number >::type \ func(const number& arg)\ {\ number result;\ using default_ops::BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result.backend(), arg.backend());\ return BOOST_MP_MOVE(result);\ } #define BINARY_OP_FUNCTOR(func, category)\ namespace detail{\ template \ struct BOOST_JOIN(func, _funct)\ {\ 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 \ void operator()(Backend& result, const Backend& arg, const Arithmetic& a)const\ {\ using default_ops:: BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result, arg, a);\ }\ template \ void operator()(Backend& result, const Arithmetic& arg, const Backend& a)const\ {\ using default_ops:: BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result, arg, a);\ }\ };\ \ }\ template \ inline typename enable_if_c::value == category,\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , number > \ >::type \ func(const number& arg, const number& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ (number_category::value == category) && (number_category >::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , detail::expression > \ >::type \ func(const number& arg, const detail::expression& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , detail::expression \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ (number_category::value == category) && (number_category >::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , detail::expression \ , number > \ >::type \ func(const detail::expression& arg, const number& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , detail::expression \ , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ (number_category >::value == category) && (number_category >::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression \ , detail::expression > \ >::type \ func(const detail::expression& arg, const detail::expression& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression \ , detail::expression \ >(\ detail::BOOST_JOIN(func, _funct) >::type>() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ is_arithmetic::value && (number_category::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , Arithmetic\ > \ >::type \ func(const number& arg, const Arithmetic& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , Arithmetic\ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ is_arithmetic::value && (number_category >::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression \ , Arithmetic\ > \ >::type \ func(const detail::expression& arg, const Arithmetic& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression \ , Arithmetic\ >(\ detail::BOOST_JOIN(func, _funct) >::type>() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ is_arithmetic::value && (number_category::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , Arithmetic \ , number \ > \ >::type \ func(const Arithmetic& arg, const number& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , Arithmetic \ , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ is_arithmetic::value && (number_category >::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , Arithmetic \ , detail::expression \ > \ >::type \ func(const Arithmetic& arg, const detail::expression& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , Arithmetic \ , detail::expression \ >(\ detail::BOOST_JOIN(func, _funct) >::type>() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<(number_category::value == category),\ number >::type \ func(const number& arg, const number& a)\ {\ number result;\ using default_ops:: BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a.backend());\ return BOOST_MP_MOVE(result);\ }\ template \ inline typename enable_if_c<\ is_arithmetic::value && (number_category::value == category),\ number \ >::type \ func(const number& arg, const Arithmetic& a)\ {\ typedef typename detail::canonical::type canonical_type;\ number result;\ using default_ops:: BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), static_cast(a));\ return BOOST_MP_MOVE(result);\ }\ template \ inline typename enable_if_c<\ is_arithmetic::value && (number_category::value == category),\ number \ >::type \ func(const Arithmetic& a, const number& arg)\ {\ typedef typename detail::canonical::type canonical_type;\ number result;\ using default_ops:: BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result.backend(), static_cast(a), arg.backend());\ return BOOST_MP_MOVE(result);\ }\ #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)\ template \ inline typename enable_if_c<\ (number_category >::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression \ , Arg2> \ >::type \ func(const detail::expression& arg, Arg2 const& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::expression \ , Arg2\ >(\ detail::BOOST_JOIN(func, _funct) >::type>() \ , arg, a \ );\ }\ template \ inline typename enable_if_c<\ (number_category::value == category),\ detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , Arg2> \ >::type \ func(const number& arg, Arg2 const& a)\ {\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , number \ , Arg2\ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ a\ );\ }\ template \ inline typename enable_if_c<\ (number_category::value == category),\ number >::type \ func(const number& arg, Arg2 const& a)\ {\ number result;\ using default_ops:: BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a);\ return BOOST_MP_MOVE(result);\ }\ #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)\ namespace detail{\ template \ struct BOOST_JOIN(func, _funct)\ {\ template \ void operator()(Backend& result, Backend const& arg, Arg a)const\ {\ using default_ops:: BOOST_JOIN(eval_,func);\ BOOST_JOIN(eval_,func)(result, arg, a);\ }\ };\ \ }\ \ HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category) namespace detail{ template struct abs_funct { void operator()(Backend& result, const Backend& arg)const { using default_ops::eval_abs; eval_abs(result, arg); } }; } template inline detail::expression< detail::function , detail::abs_funct >::type> , detail::expression > abs(const detail::expression& arg) { return detail::expression< detail::function , detail::abs_funct >::type> , detail::expression > ( detail::abs_funct >::type>() , arg ); } template inline detail::expression< detail::function , detail::abs_funct , number > abs(const number& arg) { return detail::expression< detail::function , detail::abs_funct , number >( detail::abs_funct() , arg ); } template inline number abs(const number& arg) { number result; using default_ops::eval_abs; eval_abs(result.backend(), arg.backend()); return BOOST_MP_MOVE(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) // // Integer functions: // BINARY_OP_FUNCTOR(gcd, number_kind_integer) BINARY_OP_FUNCTOR(lcm, number_kind_integer) HETERO_BINARY_OP_FUNCTOR_B(pow, unsigned, number_kind_integer) #undef BINARY_OP_FUNCTOR #undef UNARY_OP_FUNCTOR // // ilogb: // template inline typename enable_if_c::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 typename enable_if_c >::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); } template inline multiprecision::number sinc_pi(const multiprecision::number& x) { return BOOST_MP_MOVE(detail::sinc_pi_imp(x)); } template inline multiprecision::number sinc_pi(const multiprecision::number& x, const Policy&) { return BOOST_MP_MOVE(detail::sinc_pi_imp(x)); } template inline multiprecision::number sinhc_pi(const multiprecision::number& x) { return BOOST_MP_MOVE(detail::sinhc_pi_imp(x)); } template inline multiprecision::number sinhc_pi(const multiprecision::number& x, const Policy&) { return BOOST_MP_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 boost // // This has to come last of all: // #include #include // // min/max overloads: // #include #endif