/////////////////////////////////////////////////////////////////////////////// // 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 #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 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 enable_if_c >::value && !is_convertible::value >::type eval_add(T& result, V const& v) { T t; t = v; eval_add(result, t); } template inline typename enable_if_c >::value && is_convertible::value >::type eval_add(T& result, V const& v) { T t(v); eval_add(result, t); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_subtract(T& result, V const& v) { T t; t = v; eval_subtract(result, t); } template inline typename enable_if_c >::value && is_convertible::value>::type eval_subtract(T& result, V const& v) { T t(v); eval_subtract(result, t); } template inline typename enable_if_c >::value && !is_convertible::value>::type eval_multiply(T& result, V const& v) { T t; t = v; eval_multiply(result, t); } template inline typename enable_if_c >::value && is_convertible::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_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); } } 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); } 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 = 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 typename disable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x) { if((void*)&x == (void*)&t) { T z; z = x; eval_multiply_add(t, u, v, z); } else { eval_multiply(t, u, v); eval_add(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); } } 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); } template inline void eval_divide_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { T 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 enable_if_c >::value && !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 typename enable_if_c >::value && is_convertible::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 void eval_bitwise_and_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { eval_bitwise_and(t, u); } else { 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; } 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(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; } T n; eval_divide(result, a, b); if(eval_get_sign(a) < 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 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."); int c = eval_fpclassify(a); if(c == (int)FP_NAN || c == (int)FP_INFINITE) { result = boost::math::policies::raise_rounding_error("boost::multiprecision::trunc<%1%>(%1%)", 0, number(a), number(a), boost::math::policies::policy<>()).backend(); return; } if(eval_get_sign(a) < 0) eval_ceil(result, a); else eval_floor(result, a); } 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) || (c == (int)FP_INFINITE)) { result = boost::math::policies::raise_rounding_error("boost::multiprecision::round<%1%>(%1%)", 0, number(a), number(a), boost::math::policies::policy<>()).backend(); return; } 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 == 0) { r = ui_type(1); 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) { 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; B result; eval_frexp(result, val, &e); return e - 1; } template inline void eval_logb(B& result, const B& val) { typedef typename boost::mpl::if_c::value, long long, 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)); } // // These functions are implemented in separate files, but expanded inline here, // DO NOT CHANGE THE ORDER OF THESE INCLUDES: // #include #include #include } } // namespace multiprecision namespace math{ // // 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)(value_type(arg)); } template inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { int v = (fpclassify)(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)(value_type(arg)); } template inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return (fpclassify)(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)(value_type(arg)); } template inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return (fpclassify)(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)(value_type(arg)); } template inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) { return (fpclassify)(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)(value_type(arg)); } } // namespace math namespace multiprecision{ 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 long long 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 long long lltrunc(const detail::expression& v) { return lltrunc(v, boost::math::policies::policy<>()); } template inline long long 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 long long 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 long long 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 long long llround(const detail::expression& v) { return llround(v, boost::math::policies::policy<>()); } template inline long long 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 long long llround(const number& v) { return llround(v, boost::math::policies::policy<>()); } #endif 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; } 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(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) 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, long long, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*, number_kind_floating_point) BINARY_OP_FUNCTOR(pow, number_kind_floating_point) BINARY_OP_FUNCTOR(fmod, number_kind_floating_point) BINARY_OP_FUNCTOR(atan2, 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_B(scalbn, int, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point) HETERO_BINARY_OP_FUNCTOR_B(scalbn, long long, 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)); } #ifdef BOOST_MSVC #pragma warning(pop) #endif } // namespace math } // namespace boost // // This has to come last of all: // #include #include #endif