diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2016-10-06 10:41:18 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2016-10-06 10:43:11 +0900 |
commit | f763a99a501650eff2c60288aa6f10ef916d769e (patch) | |
tree | 02af7e13f9a38c888ebf340fe764cbe7dae99da9 /boost/multiprecision | |
parent | 5cde13f21d36c7224b0e13d11c4b49379ae5210d (diff) | |
download | boost-f763a99a501650eff2c60288aa6f10ef916d769e.tar.gz boost-f763a99a501650eff2c60288aa6f10ef916d769e.tar.bz2 boost-f763a99a501650eff2c60288aa6f10ef916d769e.zip |
Imported Upstream version 1.62.0upstream/1.62.0
Change-Id: I9d4c1ddb7b7d8f0069217ecc582700f9fda6dd4c
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'boost/multiprecision')
30 files changed, 1496 insertions, 255 deletions
diff --git a/boost/multiprecision/cpp_bin_float.hpp b/boost/multiprecision/cpp_bin_float.hpp index 92b73c5715..453a406f28 100644 --- a/boost/multiprecision/cpp_bin_float.hpp +++ b/boost/multiprecision/cpp_bin_float.hpp @@ -122,7 +122,7 @@ public: { case FP_ZERO: m_data = limb_type(0); - m_sign = false; + m_sign = f.sign(); m_exponent = exponent_zero; break; case FP_NAN: @@ -164,7 +164,7 @@ public: { case FP_ZERO: m_data = limb_type(0); - m_sign = false; + m_sign = ((boost::math::signbit)(f) > 0); m_exponent = exponent_zero; return *this; case FP_NAN: @@ -232,7 +232,7 @@ public: { case FP_ZERO: m_data = limb_type(0); - m_sign = false; + m_sign = ((boost::math::signbit)(f) > 0); m_exponent = exponent_zero; return *this; case FP_NAN: @@ -279,12 +279,12 @@ public: { m_data = limb_type(0u); m_exponent = exponent_zero; - m_sign = false; + m_sign = ((boost::math::signbit)(f) > 0); } else if(eval_get_sign(m_data) == 0) { m_exponent = exponent_zero; - m_sign = false; + m_sign = ((boost::math::signbit)(f) > 0); } return *this; } @@ -335,14 +335,14 @@ public: void negate() { - if((m_exponent != exponent_zero) && (m_exponent != exponent_nan)) + if(m_exponent != exponent_nan) m_sign = !m_sign; } int compare(const cpp_bin_float &o) const BOOST_NOEXCEPT { if(m_sign != o.m_sign) - return m_sign ? -1 : 1; + return (m_exponent == exponent_zero) && (m_exponent == o.m_exponent) ? 0 : m_sign ? -1 : 1; int result; if(m_exponent == exponent_nan) return -1; @@ -476,26 +476,38 @@ inline void copy_and_round(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, // Underflow: res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero; res.bits() = static_cast<limb_type>(0u); - res.sign() = false; } } template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE> inline void do_eval_add(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &a, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &b) { + if(a.exponent() < b.exponent()) + { + bool s = a.sign(); + do_eval_add(res, b, a); + if(res.sign() != s) + res.negate(); + return; + } + using default_ops::eval_add; using default_ops::eval_bit_test; + typedef typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type exponent_type; + typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type dt; // Special cases first: switch(a.exponent()) { case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero: + { + bool s = a.sign(); res = b; - if(res.sign()) - res.negate(); + res.sign() = s; return; + } case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: if(b.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan) res = b; @@ -520,32 +532,22 @@ inline void do_eval_add(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, Mi res = b; return; // result is a NaN. } - - typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type e_diff = a.exponent() - b.exponent(); + + BOOST_STATIC_ASSERT(boost::integer_traits<exponent_type>::const_max - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent); + bool s = a.sign(); - if(e_diff >= 0) + dt = a.bits(); + if(a.exponent() > (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + b.exponent()) { - dt = a.bits(); - if(e_diff < (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - { - eval_left_shift(dt, e_diff); - res.exponent() = a.exponent() - e_diff; - eval_add(dt, b.bits()); - } - else - res.exponent() = a.exponent(); + res.exponent() = a.exponent(); } else { - dt= b.bits(); - if(-e_diff < (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - { - eval_left_shift(dt, -e_diff); - res.exponent() = b.exponent() + e_diff; - eval_add(dt, a.bits()); - } - else - res.exponent() = b.exponent(); + exponent_type e_diff = a.exponent() - b.exponent(); + BOOST_ASSERT(e_diff >= 0); + eval_left_shift(dt, e_diff); + res.exponent() = a.exponent() - e_diff; + eval_add(dt, b.bits()); } copy_and_round(res, dt); @@ -570,8 +572,9 @@ inline void do_eval_subtract(cpp_bin_float<Digits, DigitBase, Allocator, Exponen res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); else { + bool s = a.sign(); res = b; - if(!res.sign()) + if(res.sign() == s) res.negate(); } return; @@ -592,7 +595,7 @@ inline void do_eval_subtract(cpp_bin_float<Digits, DigitBase, Allocator, Exponen return; case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity; - res.sign() = true; + res.sign() = !a.sign(); res.bits() = static_cast<limb_type>(0u); return; // result is a NaN. case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan: @@ -600,13 +603,13 @@ inline void do_eval_subtract(cpp_bin_float<Digits, DigitBase, Allocator, Exponen return; // result is still a NaN. } - typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type e_diff = a.exponent() - b.exponent(); bool s = a.sign(); - if((e_diff > 0) || ((e_diff == 0) && a.bits().compare(b.bits()) >= 0)) + if((a.exponent() > b.exponent()) || ((a.exponent() == b.exponent()) && a.bits().compare(b.bits()) >= 0)) { dt = a.bits(); - if(e_diff <= (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) + if(a.exponent() <= (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + b.exponent()) { + typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type e_diff = a.exponent() - b.exponent(); eval_left_shift(dt, e_diff); res.exponent() = a.exponent() - e_diff; eval_subtract(dt, b.bits()); @@ -617,8 +620,9 @@ inline void do_eval_subtract(cpp_bin_float<Digits, DigitBase, Allocator, Exponen else { dt = b.bits(); - if(-e_diff <= (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) + if(b.exponent() <= a.exponent() + (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) { + typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type e_diff = a.exponent() - b.exponent(); eval_left_shift(dt, -e_diff); res.exponent() = b.exponent() + e_diff; eval_subtract(dt, a.bits()); @@ -674,11 +678,19 @@ inline void eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, switch(a.exponent()) { case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero: + { if(b.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan) res = b; + else if(b.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity) + res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); else + { + bool s = a.sign() != b.sign(); res = a; + res.sign() = s; + } return; + } case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: switch(b.exponent()) { @@ -689,7 +701,9 @@ inline void eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, res = b; break; default: + bool s = a.sign() != b.sign(); res = a; + res.sign() = s; break; } return; @@ -699,7 +713,9 @@ inline void eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, } if(b.exponent() > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent) { + bool s = a.sign() != b.sign(); res = b; + res.sign() = s; return; } if((a.exponent() > 0) && (b.exponent() > 0)) @@ -707,8 +723,9 @@ inline void eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, if(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent + 2 - a.exponent() < b.exponent()) { // We will certainly overflow: + bool s = a.sign() != b.sign(); res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity; - res.sign() = a.sign() != b.sign(); + res.sign() = s; res.bits() = static_cast<limb_type>(0u); return; } @@ -719,7 +736,7 @@ inline void eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, { // We will certainly underflow: res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero; - res.sign() = false; + res.sign() = a.sign() != b.sign(); res.bits() = static_cast<limb_type>(0u); return; } @@ -749,8 +766,12 @@ inline typename enable_if_c<is_unsigned<U>::value>::type eval_multiply(cpp_bin_f switch(a.exponent()) { case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero: + { + bool s = a.sign(); res = a; + res.sign() = s; return; + } case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: if(b == 0) res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); @@ -811,6 +832,7 @@ inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, Mi switch(u.exponent()) { case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero: + { switch(v.exponent()) { case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero: @@ -818,9 +840,13 @@ inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, Mi res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); return; } + bool s = u.sign() != v.sign(); res = u; + res.sign() = s; return; + } case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: + { switch(v.exponent()) { case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: @@ -828,8 +854,11 @@ inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, Mi res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); return; } + bool s = u.sign() != v.sign(); res = u; + res.sign() = s; return; + } case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan: res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); return; @@ -846,7 +875,7 @@ inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, Mi case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero; res.bits() = limb_type(0); - res.sign() = false; + res.sign() = u.sign() != v.sign(); return; case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan: res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); @@ -869,6 +898,29 @@ inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, Mi // // We can set the exponent and sign of the result up front: // + if((v.exponent() < 0) && (u.exponent() > 0)) + { + // Check for overflow: + if(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent + v.exponent() < u.exponent() - 1) + { + res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity; + res.sign() = u.sign() != v.sign(); + res.bits() = static_cast<limb_type>(0u); + return; + } + } + else if((v.exponent() > 0) && (u.exponent() < 0)) + { + // Check for underflow: + if(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent + v.exponent() > u.exponent()) + { + // We will certainly underflow: + res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero; + res.sign() = u.sign() != v.sign(); + res.bits() = static_cast<limb_type>(0u); + return; + } + } res.exponent() = u.exponent() - v.exponent() - 1; res.sign() = u.sign() != v.sign(); // @@ -949,13 +1001,17 @@ inline typename enable_if_c<is_unsigned<U>::value>::type eval_divide(cpp_bin_flo switch(u.exponent()) { case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero: + { if(v == 0) { res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); return; } + bool s = u.sign() != (v < 0); res = u; + res.sign() = s; return; + } case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: res = u; return; @@ -1074,10 +1130,15 @@ inline bool eval_is_zero(const cpp_bin_float<Digits, DigitBase, Allocator, Expon template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE> inline bool eval_eq(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &a, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &b) { - return (a.exponent() == b.exponent()) - && (a.sign() == b.sign()) - && (a.bits().compare(b.bits()) == 0) - && (a.exponent() != cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan); + if(a.exponent() == b.exponent()) + { + if(a.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero) + return true; + return (a.sign() == b.sign()) + && (a.bits().compare(b.bits()) == 0) + && (a.exponent() != cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan); + } + return false; } template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE> @@ -1160,22 +1221,25 @@ inline typename boost::enable_if_c<boost::is_float<Float>::value>::type eval_con // // Perform rounding first, then afterwards extract the digits: // - cpp_bin_float<std::numeric_limits<Float>::digits, digit_base_2, void, Exponent, MinE, MaxE> arg(original_arg); + typedef cpp_bin_float<std::numeric_limits<Float>::digits, digit_base_2, void, Exponent, MinE, MaxE> conv_type; + conv_type arg(original_arg); switch(arg.exponent()) { - case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero: + case conv_type::exponent_zero: *res = 0; + if(arg.sign()) + *res = -*res; return; - case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan: + case conv_type::exponent_nan: *res = std::numeric_limits<Float>::quiet_NaN(); return; - case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: + case conv_type::exponent_infinity: *res = (std::numeric_limits<Float>::infinity)(); if(arg.sign()) *res = -*res; return; } - typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type e = arg.exponent(); + typename conv_type::exponent_type e = arg.exponent(); e -= cpp_bin_float<std::numeric_limits<Float>::digits, digit_base_2, void, Exponent, MinE, MaxE>::bit_count - 1; *res = std::ldexp(static_cast<Float>(*arg.bits().limbs()), e); for(unsigned i = 1; i < arg.bits().size(); ++i) @@ -1314,7 +1378,10 @@ inline void eval_sqrt(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE res = arg; return; case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity: - res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); + if(arg.sign()) + res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend(); + else + res = arg; return; } if(arg.sign()) @@ -1423,6 +1490,16 @@ inline void eval_ceil(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE eval_left_shift(res.bits(), shift); } +template<unsigned D1, backends::digit_base_type B1, class A1, class E1, E1 M1, E1 M2> +inline std::size_t hash_value(const cpp_bin_float<D1, B1, A1, E1, M1, M2>& val) +{ + std::size_t result = hash_value(val.bits()); + boost::hash_combine(result, val.exponent()); + boost::hash_combine(result, val.sign()); + return result; +} + + } // namespace backends #ifdef BOOST_NO_SFINAE_EXPR @@ -1459,7 +1536,31 @@ typedef number<backends::cpp_bin_float<53, backends::digit_base_2, void, boost:: typedef number<backends::cpp_bin_float<64, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_double_extended; typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_quad; -}} // namespaces +} // namespace multiprecision + +namespace math { + + template<unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Exponent, Exponent MinE, Exponent MaxE, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates> + inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates>& arg) + { + return arg.backend().sign(); + } + + template<unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Exponent, Exponent MinE, Exponent MaxE, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates> + inline boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> + copysign BOOST_PREVENT_MACRO_SUBSTITUTION( + const boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates>& a, + const boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates>& b) + { + boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> res(a); + res.backend().sign() = b.backend().sign(); + return res; + } + + +} // namespace math + +} // namespace boost #include <boost/multiprecision/cpp_bin_float/io.hpp> #include <boost/multiprecision/cpp_bin_float/transcendental.hpp> diff --git a/boost/multiprecision/cpp_bin_float/io.hpp b/boost/multiprecision/cpp_bin_float/io.hpp index 88d5ddd053..630d651d9d 100644 --- a/boost/multiprecision/cpp_bin_float/io.hpp +++ b/boost/multiprecision/cpp_bin_float/io.hpp @@ -8,6 +8,12 @@ namespace boost{ namespace multiprecision{ namespace cpp_bf_io_detail{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + + // // Multiplies a by b and shifts the result so it fits inside max_bits bits, // returns by how much the result was shifted. @@ -670,7 +676,7 @@ std::string cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::s switch(exponent()) { case exponent_zero: - s = "0"; + s = sign() ? "-0" : f & std::ios_base::showpos ? "+0" : "0"; boost::multiprecision::detail::format_float_string(s, 0, dig, f, true); break; case exponent_nan: @@ -684,6 +690,10 @@ std::string cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::s return s; } +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + }}} // namespaces #endif diff --git a/boost/multiprecision/cpp_dec_float.hpp b/boost/multiprecision/cpp_dec_float.hpp index 057095e2b4..ee14becf5d 100644 --- a/boost/multiprecision/cpp_dec_float.hpp +++ b/boost/multiprecision/cpp_dec_float.hpp @@ -25,6 +25,7 @@ #include <boost/array.hpp> #endif #include <boost/cstdint.hpp> +#include <boost/functional/hash_fwd.hpp> #include <boost/multiprecision/number.hpp> #include <boost/multiprecision/detail/big_lanczos.hpp> #include <boost/multiprecision/detail/dynamic_array.hpp> @@ -257,6 +258,17 @@ public: cpp_dec_float(const double mantissa, const ExponentType exponent); + std::size_t hash()const + { + std::size_t result = 0; + for(int i = 0; i < prec_elem; ++i) + boost::hash_combine(result, data[i]); + boost::hash_combine(result, exp); + boost::hash_combine(result, neg); + boost::hash_combine(result, fpclass); + return result; + } + // Specific special values. static const cpp_dec_float& nan() { @@ -948,6 +960,18 @@ cpp_dec_float<Digits10, ExponentType, Allocator>& cpp_dec_float<Digits10, Expone template <unsigned Digits10, class ExponentType, class Allocator> cpp_dec_float<Digits10, ExponentType, Allocator>& cpp_dec_float<Digits10, ExponentType, Allocator>::operator/=(const cpp_dec_float<Digits10, ExponentType, Allocator>& v) { + if(iszero()) + { + if((v.isnan)()) + { + return *this = v; + } + else if(v.iszero()) + { + return *this = nan(); + } + } + const bool u_and_v_are_finite_and_identical = ( (isfinite)() && (fpclass == v.fpclass) && (exp == v.exp) @@ -966,14 +990,6 @@ cpp_dec_float<Digits10, ExponentType, Allocator>& cpp_dec_float<Digits10, Expone } else { - if(iszero()) - { - if((v.isnan)() || v.iszero()) - { - return *this = v; - } - return *this; - } cpp_dec_float t(v); t.calculate_inv(); return operator*=(t); @@ -2957,6 +2973,12 @@ inline int eval_get_sign(const cpp_dec_float<Digits10, ExponentType, Allocator>& return val.iszero() ? 0 : val.isneg() ? -1 : 1; } +template <unsigned Digits10, class ExponentType, class Allocator> +inline std::size_t hash_value(const cpp_dec_float<Digits10, ExponentType, Allocator>& val) +{ + return val.hash(); +} + } // namespace backends using boost::multiprecision::backends::cpp_dec_float; diff --git a/boost/multiprecision/cpp_int.hpp b/boost/multiprecision/cpp_int.hpp index b8681677e2..c348020d40 100644 --- a/boost/multiprecision/cpp_int.hpp +++ b/boost/multiprecision/cpp_int.hpp @@ -34,9 +34,10 @@ namespace backends{ #ifdef BOOST_MSVC -// warning C4127: conditional expression is constant #pragma warning(push) -#pragma warning(disable:4127 4351 4293 4996 4307 4702 6285) +#pragma warning(disable:4307) // integral constant overflow (oveflow is in a branch not taken when it would overflow) +#pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4702) // Unreachable code (reachability depends on template params) #endif template <unsigned MinBits = 0, unsigned MaxBits = 0, boost::multiprecision::cpp_integer_type SignType = signed_magnitude, cpp_int_check_type Checked = unchecked, class Allocator = typename mpl::if_c<MinBits && (MinBits == MaxBits), void, std::allocator<limb_type> >::type > @@ -226,7 +227,7 @@ public: : m_data(i), m_limbs(1), m_sign(false), m_internal(true) { } BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_limb_type i)BOOST_NOEXCEPT : m_data(i), m_limbs(1), m_sign(i < 0), m_internal(true) { } -#if defined(BOOST_LITTLE_ENDIAN) +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(double_limb_type i)BOOST_NOEXCEPT : m_data(i), m_limbs(i > max_limb_value ? 2 : 1), m_sign(false), m_internal(true) { } BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_double_limb_type i)BOOST_NOEXCEPT @@ -444,7 +445,7 @@ public: : m_wrapper(i), m_limbs(1), m_sign(false) {} BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_limb_type i)BOOST_NOEXCEPT : m_wrapper(limb_type(i < 0 ? static_cast<limb_type>(-static_cast<signed_double_limb_type>(i)) : i)), m_limbs(1), m_sign(i < 0) {} -#if defined(BOOST_LITTLE_ENDIAN) +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(double_limb_type i)BOOST_NOEXCEPT : m_wrapper(i), m_limbs(i > max_limb_value ? 2 : 1), m_sign(false) {} BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_double_limb_type i)BOOST_NOEXCEPT @@ -595,7 +596,7 @@ public: : m_wrapper(i), m_limbs(1) {} BOOST_MP_FORCEINLINE cpp_int_base(signed_limb_type i)BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) : m_wrapper(limb_type(i < 0 ? static_cast<limb_type>(-static_cast<signed_double_limb_type>(i)) : i)), m_limbs(1) { if(i < 0) negate(); } -#ifdef BOOST_LITTLE_ENDIAN +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(double_limb_type i)BOOST_NOEXCEPT : m_wrapper(i), m_limbs(i > max_limb_value ? 2 : 1) {} BOOST_MP_FORCEINLINE cpp_int_base(signed_double_limb_type i)BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) @@ -773,10 +774,10 @@ public: // template <class SI> BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(SI i, typename boost::enable_if_c<is_signed<SI>::value && (Checked == unchecked) >::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<cpp_int_base>().check_in_range(std::declval<SI>()))) - : m_data(i < 0 ? static_cast<local_limb_type>(static_cast<typename make_unsigned<SI>::type>(boost::multiprecision::detail::unsigned_abs(i)) & limb_mask) : static_cast<local_limb_type>(i)& limb_mask), m_sign(i < 0) {} + : m_data(i < 0 ? static_cast<local_limb_type>(static_cast<typename make_unsigned<SI>::type>(boost::multiprecision::detail::unsigned_abs(i)) & limb_mask) : static_cast<local_limb_type>(i & limb_mask)), m_sign(i < 0) {} template <class SI> BOOST_MP_FORCEINLINE cpp_int_base(SI i, typename boost::enable_if_c<is_signed<SI>::value && (Checked == checked) >::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<cpp_int_base>().check_in_range(std::declval<SI>()))) - : m_data(i < 0 ? (static_cast<local_limb_type>(static_cast<typename make_unsigned<SI>::type>(boost::multiprecision::detail::unsigned_abs(i)) & limb_mask)) : static_cast<local_limb_type>(i)& limb_mask), m_sign(i < 0) + : m_data(i < 0 ? (static_cast<local_limb_type>(static_cast<typename make_unsigned<SI>::type>(boost::multiprecision::detail::unsigned_abs(i)) & limb_mask)) : static_cast<local_limb_type>(i & limb_mask)), m_sign(i < 0) { check_in_range(i); } template <class UI> BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(UI i, typename boost::enable_if_c<is_unsigned<UI>::value && (Checked == unchecked)>::type const* = 0) BOOST_NOEXCEPT @@ -914,6 +915,20 @@ public: // // Direct construction: // +#ifdef __MSVC_RUNTIME_CHECKS + template <class SI> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(SI i, typename boost::enable_if_c<is_signed<SI>::value && (Checked == unchecked) >::type const* = 0) BOOST_NOEXCEPT + : m_data(i < 0 ? (1 + ~static_cast<local_limb_type>(-i & limb_mask)) & limb_mask : static_cast<local_limb_type>(i & limb_mask)) {} + template <class SI> + BOOST_MP_FORCEINLINE cpp_int_base(SI i, typename boost::enable_if_c<is_signed<SI>::value && (Checked == checked) >::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<cpp_int_base>().check_in_range(std::declval<SI>()))) + : m_data(i < 0 ? 1 + ~static_cast<local_limb_type>(-i & limb_mask) : static_cast<local_limb_type>(i & limb_mask)) { check_in_range(i); } + template <class UI> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(UI i, typename boost::enable_if_c<is_unsigned<UI>::value && (Checked == unchecked) >::type const* = 0) BOOST_NOEXCEPT + : m_data(static_cast<local_limb_type>(i & limb_mask)) {} + template <class UI> + BOOST_MP_FORCEINLINE cpp_int_base(UI i, typename boost::enable_if_c<is_unsigned<UI>::value && (Checked == checked) >::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<cpp_int_base>().check_in_range(std::declval<UI>()))) + : m_data(static_cast<local_limb_type>(i & limb_mask)) { check_in_range(i); } +#else template <class SI> BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(SI i, typename boost::enable_if_c<is_signed<SI>::value && (Checked == unchecked) >::type const* = 0) BOOST_NOEXCEPT : m_data(i < 0 ? (1 + ~static_cast<local_limb_type>(-i)) & limb_mask : static_cast<local_limb_type>(i) & limb_mask) {} @@ -926,6 +941,7 @@ public: template <class UI> BOOST_MP_FORCEINLINE cpp_int_base(UI i, typename boost::enable_if_c<is_unsigned<UI>::value && (Checked == checked) >::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<cpp_int_base>().check_in_range(std::declval<UI>()))) : m_data(static_cast<local_limb_type>(i)) { check_in_range(i); } +#endif template <class F> BOOST_MP_FORCEINLINE cpp_int_base(F i, typename boost::enable_if<is_floating_point<F> >::type const* = 0) BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) : m_data(static_cast<local_limb_type>(std::fabs(i)) & limb_mask) @@ -999,7 +1015,7 @@ public: template <class Arg, class Base> struct is_allowed_cpp_int_base_conversion : public mpl::if_c< is_same<Arg, limb_type>::value || is_same<Arg, signed_limb_type>::value -#ifdef BOOST_LITTLE_ENDIAN +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) || is_same<Arg, double_limb_type>::value || is_same<Arg, signed_double_limb_type>::value #endif #if defined(BOOST_MP_USER_DEFINED_LITERALS) @@ -1207,7 +1223,11 @@ private: BOOST_STATIC_ASSERT(sizeof(i) == 2 * sizeof(limb_type)); BOOST_STATIC_ASSERT(base_type::internal_limb_count >= 2); typename base_type::limb_pointer p = this->limbs(); +#ifdef __MSVC_RUNTIME_CHECKS + *p = static_cast<limb_type>(i & ~static_cast<limb_type>(0)); +#else *p = static_cast<limb_type>(i); +#endif p[1] = static_cast<limb_type>(i >> base_type::limb_bits); this->resize(p[1] ? 2 : 1, p[1] ? 2 : 1); this->sign(false); @@ -1222,7 +1242,11 @@ private: s = true; ui = static_cast<double_limb_type>(boost::multiprecision::detail::unsigned_abs(i)); typename base_type::limb_pointer p = this->limbs(); +#ifdef __MSVC_RUNTIME_CHECKS + *p = static_cast<limb_type>(ui & ~static_cast<limb_type>(0)); +#else *p = static_cast<limb_type>(ui); +#endif p[1] = static_cast<limb_type>(ui >> base_type::limb_bits); this->resize(p[1] ? 2 : 1, p[1] ? 2 : 1); this->sign(s); @@ -1368,7 +1392,7 @@ private: } } // - // Exception guarentee: create the result in stack variable "result" + // Exception guarantee: create the result in stack variable "result" // then do a swap at the end. In the event of a throw, *this will // be left unchanged. // @@ -1923,6 +1947,10 @@ struct is_explicitly_convertible<cpp_int_backend<MinBits, MaxBits, SignType, Che } #endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }} // namespaces // diff --git a/boost/multiprecision/cpp_int/add.hpp b/boost/multiprecision/cpp_int/add.hpp index 372998d672..22b8c186dc 100644 --- a/boost/multiprecision/cpp_int/add.hpp +++ b/boost/multiprecision/cpp_int/add.hpp @@ -10,6 +10,11 @@ namespace boost{ namespace multiprecision{ namespace backends{ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + // // This is the key addition routine where all the argument types are non-trivial cpp_int's: // @@ -44,7 +49,11 @@ inline void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BO while(pr != pr_end) { carry += static_cast<double_limb_type>(*pa) + static_cast<double_limb_type>(*pb); +#ifdef __MSVC_RUNTIME_CHECKS + *pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); +#else *pr = static_cast<limb_type>(carry); +#endif carry >>= CppInt1::limb_bits; ++pr, ++pa, ++pb; } @@ -63,7 +72,11 @@ inline void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BO break; } carry += static_cast<double_limb_type>(*pa); +#ifdef __MSVC_RUNTIME_CHECKS + *pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); +#else *pr = static_cast<limb_type>(carry); +#endif carry >>= CppInt1::limb_bits; ++pr, ++pa; } @@ -95,7 +108,11 @@ inline void add_unsigned(CppInt1& result, const CppInt2& a, const limb_type& o) for(; carry && (i < result.size()); ++i) { carry += static_cast<double_limb_type>(pa[i]); +#ifdef __MSVC_RUNTIME_CHECKS + pr[i] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); +#else pr[i] = static_cast<limb_type>(carry); +#endif carry >>= CppInt1::limb_bits; } // Just copy any remaining digits: @@ -524,6 +541,10 @@ BOOST_MP_FORCEINLINE typename enable_if_c< result.normalize(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }}} // namespaces #endif diff --git a/boost/multiprecision/cpp_int/bitwise.hpp b/boost/multiprecision/cpp_int/bitwise.hpp index e39be3d12c..748d088056 100644 --- a/boost/multiprecision/cpp_int/bitwise.hpp +++ b/boost/multiprecision/cpp_int/bitwise.hpp @@ -351,7 +351,6 @@ inline void left_shift_limb(Int& result, double_limb_type s) ++rs; // Most significant limb will overflow when shifted rs += offset; result.resize(rs, rs); - bool truncated = result.size() != rs; typename Int::limb_pointer pr = result.limbs(); diff --git a/boost/multiprecision/cpp_int/divide.hpp b/boost/multiprecision/cpp_int/divide.hpp index 5fe6ce6ad8..2f83d1ba71 100644 --- a/boost/multiprecision/cpp_int/divide.hpp +++ b/boost/multiprecision/cpp_int/divide.hpp @@ -227,12 +227,20 @@ void divide_unsigned_helper( for(unsigned i = 0; i < y.size(); ++i) { carry += static_cast<double_limb_type>(py[i]) * static_cast<double_limb_type>(guess); +#ifdef __MSVC_RUNTIME_CHECKS + pt[i + shift] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); +#else pt[i + shift] = static_cast<limb_type>(carry); +#endif carry >>= CppInt1::limb_bits; } if(carry && !truncated_t) { +#ifdef __MSVC_RUNTIME_CHECKS + pt[t.size() - 1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); +#else pt[t.size() - 1] = static_cast<limb_type>(carry); +#endif } else if(!truncated_t) { diff --git a/boost/multiprecision/cpp_int/import_export.hpp b/boost/multiprecision/cpp_int/import_export.hpp index 3a2473b0b2..0fe3249ddc 100644 --- a/boost/multiprecision/cpp_int/import_export.hpp +++ b/boost/multiprecision/cpp_int/import_export.hpp @@ -20,7 +20,7 @@ namespace boost { limb_type mask = chunk_bits >= sizeof(limb_type) * CHAR_BIT ? ~static_cast<limb_type>(0u) : (static_cast<limb_type>(1u) << chunk_bits) - 1; - limb_type value = (static_cast<limb_type>(bits) & mask) << shift; + limb_type value = static_cast<limb_type>(bits & mask) << shift; if(value) { if(val.size() == limb) @@ -132,7 +132,7 @@ namespace boost { if(byte_len % sizeof(limb_type)) ++limb_len; cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend(); - result.resize(limb_len, limb_len); // checked types may throw here if they're not large enough to hold the data! + result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data! result.limbs()[result.size() - 1] = 0u; std::memcpy(result.limbs(), i, std::min(byte_len, result.size() * sizeof(limb_type))); result.normalize(); // In case data has leading zeros. @@ -149,7 +149,7 @@ namespace boost { if(byte_len % sizeof(result.limbs()[0])) ++limb_len; result.limbs()[0] = 0u; - result.resize(limb_len, limb_len); // checked types may throw here if they're not large enough to hold the data! + result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data! std::memcpy(result.limbs(), i, std::min(byte_len, result.size() * sizeof(result.limbs()[0]))); result.normalize(); // In case data has leading zeros. return val; @@ -221,7 +221,7 @@ namespace boost { ++out; return out; } - unsigned bitcount = msb(val) + 1; + unsigned bitcount = boost::multiprecision::backends::eval_msb_imp(val.backend()) + 1; unsigned chunks = bitcount / chunk_size; if(bitcount % chunk_size) ++chunks; diff --git a/boost/multiprecision/cpp_int/limits.hpp b/boost/multiprecision/cpp_int/limits.hpp index 36a38d5a3b..518bb9f4e0 100644 --- a/boost/multiprecision/cpp_int/limits.hpp +++ b/boost/multiprecision/cpp_int/limits.hpp @@ -12,6 +12,11 @@ namespace std{ namespace detail{ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4307) +#endif + template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates> inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> get_min(const boost::mpl::true_&, const boost::mpl::true_&) @@ -210,6 +215,9 @@ template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::round_style; #endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif } // namespace std diff --git a/boost/multiprecision/cpp_int/misc.hpp b/boost/multiprecision/cpp_int/misc.hpp index a124710c28..0412ff144e 100644 --- a/boost/multiprecision/cpp_int/misc.hpp +++ b/boost/multiprecision/cpp_int/misc.hpp @@ -10,12 +10,15 @@ #include <boost/multiprecision/detail/bitscan.hpp> // lsb etc #include <boost/integer/common_factor_rt.hpp> // gcd/lcm +#include <boost/functional/hash_fwd.hpp> #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable:4702) +#pragma warning(disable:4127) // conditional expression is constant #endif + namespace boost{ namespace multiprecision{ namespace backends{ template <class R, class CppInt> @@ -146,6 +149,16 @@ inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBit // template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type +eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a) +{ + // + // Find the index of the most significant bit that is non-zero: + // + return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a) { using default_ops::eval_get_sign; @@ -157,11 +170,7 @@ inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBit { BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); } - - // - // Find the index of the most significant bit that is non-zero: - // - return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]); + return eval_msb_imp(a); } template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> @@ -262,7 +271,8 @@ inline typename enable_if_c<is_integral<U>::value>::type eval_qr( cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) { using default_ops::eval_qr; - cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(y); + cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t; + t = y; eval_qr(x, t, q, r); } @@ -317,7 +327,11 @@ inline double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type break; } v -= u; +#ifdef __MSVC_RUNTIME_CHECKS + while((v & 1u) == 0) +#else while((static_cast<unsigned>(v) & 1u) == 0) +#endif v >>= 1; } while(true); return u; @@ -527,21 +541,33 @@ template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignTy inline typename enable_if_c< is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value + && boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value >::type eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) { typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type; if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)()))) { - conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type()); - *result = (std::numeric_limits<R>::max)(); + if(val.isneg()) + { + if(static_cast<common_type>(*val.limbs()) > -static_cast<common_type>((std::numeric_limits<R>::min)())) + conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type()); + *result = (std::numeric_limits<R>::min)(); + } + else + { + conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type()); + *result = (std::numeric_limits<R>::max)(); + } } else - *result = static_cast<R>(*val.limbs()); - if(val.isneg()) { - check_is_negative(mpl::bool_<boost::is_signed<R>::value || boost::is_floating_point<R>::value>()); - *result = negate_integer(*result, mpl::bool_<boost::is_signed<R>::value || boost::is_floating_point<R>::value>()); + *result = static_cast<R>(*val.limbs()); + if(val.isneg()) + { + check_is_negative(mpl::bool_<is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point)>()); + *result = negate_integer(*result, mpl::bool_<is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point)>()); + } } } @@ -549,6 +575,7 @@ template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignTy inline typename enable_if_c< is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value + && boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value >::type eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) { @@ -583,6 +610,16 @@ inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type +eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a) +{ + // + // Find the index of the least significant bit within that limb: + // + return boost::multiprecision::detail::find_msb(*a.limbs()); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a) { using default_ops::eval_get_sign; @@ -594,10 +631,19 @@ inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits { BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); } - // - // Find the index of the least significant bit within that limb: - // - return boost::multiprecision::detail::find_msb(*a.limbs()); + return eval_msb_imp(a); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +inline std::size_t hash_value(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT +{ + std::size_t result = 0; + for(unsigned i = 0; i < val.size(); ++i) + { + boost::hash_combine(result, val.limbs()[i]); + } + boost::hash_combine(result, val.sign()); + return result; } #ifdef BOOST_MSVC diff --git a/boost/multiprecision/cpp_int/multiply.hpp b/boost/multiprecision/cpp_int/multiply.hpp index 226bc9d192..88264c47be 100644 --- a/boost/multiprecision/cpp_int/multiply.hpp +++ b/boost/multiprecision/cpp_int/multiply.hpp @@ -10,7 +10,12 @@ namespace boost{ namespace multiprecision{ namespace backends{ -template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + + template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type eval_multiply( cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, @@ -31,7 +36,11 @@ inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBit while(p != pe) { carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val); +#ifdef __MSVC_RUNTIME_CHECKS + *p = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); +#else *p = static_cast<limb_type>(carry); +#endif carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits; ++p, ++pa; } @@ -139,7 +148,11 @@ inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBit carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]); BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j])); carry += pr[i + j]; +#ifdef __MSVC_RUNTIME_CHECKS + pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); +#else pr[i + j] = static_cast<limb_type>(carry); +#endif carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits; BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value)); } @@ -184,7 +197,12 @@ BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<Mi } else { +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val); +#else + cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t; + t = val; +#endif eval_multiply(result, a, t); } } @@ -240,7 +258,12 @@ inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBit result.negate(); return; } +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val); +#else + cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t; + t = val; +#endif eval_multiply(result, a, t); } @@ -348,6 +371,16 @@ BOOST_MP_FORCEINLINE typename enable_if_c< limb_type* pr = result.limbs(); double_limb_type carry = w * y; +#ifdef __MSVC_RUNTIME_CHECKS + pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + carry >>= limb_bits; + carry += w * z + x * y; + pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + carry >>= limb_bits; + carry += x * z; + pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + pr[3] = static_cast<limb_type>(carry >> limb_bits); +#else pr[0] = static_cast<limb_type>(carry); carry >>= limb_bits; carry += w * z + x * y; @@ -356,7 +389,7 @@ BOOST_MP_FORCEINLINE typename enable_if_c< carry += x * z; pr[2] = static_cast<limb_type>(carry); pr[3] = static_cast<limb_type>(carry >> limb_bits); - +#endif result.sign(s); result.normalize(); } @@ -382,6 +415,20 @@ BOOST_MP_FORCEINLINE typename enable_if_c< limb_type* pr = result.limbs(); double_limb_type carry = w * y; +#ifdef __MSVC_RUNTIME_CHECKS + pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + carry >>= limb_bits; + carry += w * z; + pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + carry >>= limb_bits; + pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + carry = x * y + pr[1]; + pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + carry >>= limb_bits; + carry += pr[2] + x * z; + pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0)); + pr[3] = static_cast<limb_type>(carry >> limb_bits); +#else pr[0] = static_cast<limb_type>(carry); carry >>= limb_bits; carry += w * z; @@ -394,7 +441,7 @@ BOOST_MP_FORCEINLINE typename enable_if_c< carry += pr[2] + x * z; pr[2] = static_cast<limb_type>(carry); pr[3] = static_cast<limb_type>(carry >> limb_bits); - +#endif result.sign(false); result.normalize(); } @@ -434,6 +481,10 @@ BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned<UI>::value && (sizeof(UI) result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }}} // namespaces #endif diff --git a/boost/multiprecision/debug_adaptor.hpp b/boost/multiprecision/debug_adaptor.hpp index a6ed903c44..1b69ba4aa6 100644 --- a/boost/multiprecision/debug_adaptor.hpp +++ b/boost/multiprecision/debug_adaptor.hpp @@ -13,7 +13,12 @@ namespace boost{ namespace multiprecision{ namespace backends{ -template <class Backend> +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + + template <class Backend> struct debug_adaptor { typedef typename Backend::signed_types signed_types; @@ -120,6 +125,22 @@ public: if(tag::value) update_view(); } + static unsigned default_precision() BOOST_NOEXCEPT + { + return Backend::default_precision(); + } + static void default_precision(unsigned v) BOOST_NOEXCEPT + { + Backend::default_precision(v); + } + unsigned precision()const BOOST_NOEXCEPT + { + return value().precision(); + } + void precision(unsigned digits10) BOOST_NOEXCEPT + { + value().precision(digits10); + } }; template <class Backend> @@ -434,6 +455,13 @@ NON_MEMBER_OP3(fmod, "fmod"); NON_MEMBER_OP3(pow, "pow"); NON_MEMBER_OP3(atan2, "atan2"); +template <class Backend> +std::size_t hash_value(const debug_adaptor<Backend>& val) +{ + return hash_value(val.value()); +} + + } // namespace backends using backends::debug_adaptor; @@ -441,6 +469,9 @@ using backends::debug_adaptor; template<class Backend> struct number_category<backends::debug_adaptor<Backend> > : public number_category<Backend> {}; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif }} // namespaces namespace std{ diff --git a/boost/multiprecision/detail/big_lanczos.hpp b/boost/multiprecision/detail/big_lanczos.hpp index 03d3203ec8..0a5a154da1 100644 --- a/boost/multiprecision/detail/big_lanczos.hpp +++ b/boost/multiprecision/detail/big_lanczos.hpp @@ -21,10 +21,10 @@ struct lanczos<multiprecision::number<Backend, ExpressionTemplates>, Policy> { typedef typename boost::math::policies::precision<multiprecision::number<Backend, ExpressionTemplates>, Policy>::type precision_type; typedef typename mpl::if_c< - precision_type::value <= 73, + precision_type::value && (precision_type::value <= 73), lanczos13UDT, typename mpl::if_c< - precision_type::value <= 122, + precision_type::value&& (precision_type::value <= 122), lanczos22UDT, undefined_lanczos >::type diff --git a/boost/multiprecision/detail/default_ops.hpp b/boost/multiprecision/detail/default_ops.hpp index 59d098ba0d..d9fa19479b 100644 --- a/boost/multiprecision/detail/default_ops.hpp +++ b/boost/multiprecision/detail/default_ops.hpp @@ -25,7 +25,25 @@ #endif -namespace boost{ namespace multiprecision{ namespace default_ops{ +namespace boost{ namespace multiprecision{ + + namespace detail { + + template <class To, class From> + void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/); + template <class To, class From> + void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/); + template <class To, class From> + void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/); + template <class To, class From> + void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/); + template <class To, class From> + void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/); + +} + + +namespace default_ops{ #ifdef BOOST_MSVC // warning C4127: conditional expression is constant @@ -309,7 +327,14 @@ inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_si t.negate(); } template <class T, class U> -inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v) +inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v) +{ + T temp; + temp = u; + eval_subtract(t, temp, v); +} +template <class T, class U> +inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v) { T temp(u); eval_subtract(t, temp, v); @@ -351,6 +376,7 @@ inline void eval_multiply_default(T& t, const T& u, const T& v) eval_multiply(t, v); } } +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) template <class T, class U> inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_multiply_default(T& t, const T& u, const U& v) { @@ -369,6 +395,7 @@ inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value>::type e { eval_multiply(t, v, u); } +#endif template <class T, class U, class V> inline void eval_multiply_default(T& t, const U& u, const V& v) { @@ -449,6 +476,7 @@ inline void eval_divide_default(T& t, const T& u, const T& v) eval_divide(t, v); } } +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) template <class T, class U> inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_divide_default(T& t, const T& u, const U& v) { @@ -475,12 +503,14 @@ inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_co T uu(u); eval_divide(t, uu, v); } +#endif template <class T, class U, class V> inline void eval_divide_default(T& t, const U& u, const V& v) { if(is_same<T, V>::value && ((void*)&t == (void*)&v)) { - T temp(u); + T temp; + temp = u; eval_divide(temp, v); t = temp; } @@ -882,6 +912,16 @@ inline void eval_convert_to(terminal<R>* result, const B& backend) result->value = boost::lexical_cast<R>(backend.str(0, std::ios_base::fmtflags(0))); } +template <class B1, class B2, expression_template_option et> +inline void eval_convert_to(terminal<number<B1, et> >* 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<B1>(), number_category<B2>()); +} + template <class B> inline void eval_convert_to(std::string* result, const B& backend) { @@ -974,6 +1014,38 @@ inline void eval_trunc(T& result, const T& a) } template <class T> +inline void eval_modf(T& result, T const& arg, T* pipart) +{ + typedef typename boost::multiprecision::detail::canonical<unsigned, T>::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 <class T> inline void eval_round(T& result, const T& a) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The round function is only valid for floating point types."); @@ -1212,6 +1284,15 @@ inline typename B::exponent_type eval_ilogb(const B& val) { BOOST_STATIC_ASSERT_MSG(!std::numeric_limits<number<B> >::is_specialized || (std::numeric_limits<number<B> >::radix == 2), "The default implementation of ilogb requires a base 2 number type"); typename B::exponent_type e; + switch(eval_fpclassify(val)) + { + case FP_NAN: + return (std::numeric_limits<typename B::exponent_type>::min)(); + case FP_INFINITE: + return (std::numeric_limits<typename B::exponent_type>::max)(); + case FP_ZERO: + return (std::numeric_limits<typename B::exponent_type>::min)(); + } B result; eval_frexp(result, val, &e); return e - 1; @@ -1301,9 +1382,49 @@ inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::deta return (isnormal)(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 <class Backend, multiprecision::expression_template_option ExpressionTemplates> +inline int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg) +{ + return arg.sign(); +} +template <class tag, class A1, class A2, class A3, class A4> +inline int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg) +{ + typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type; + return (sign)(value_type(arg)); +} + +template <class Backend, multiprecision::expression_template_option ExpressionTemplates> +inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg) +{ + return arg.sign() < 0; +} +template <class tag, class A1, class A2, class A3, class A4> +inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg) +{ + typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type; + return (signbit)(value_type(arg)); +} + } // namespace math + namespace multiprecision{ + // + // Import Math functions here, so they can be found via ADL: + // + using boost::math::signbit; + using boost::math::sign; + using boost::math::copysign; + using boost::math::changesign; + using boost::math::fpclassify; + using boost::math::isinf; + using boost::math::isnan; + using boost::math::isnormal; + template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3> inline number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b) { @@ -1626,7 +1747,31 @@ frexp(const detail::expression<tag, A1, A2, A3, A4>& v, boost::long_long_type* p typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type; return BOOST_MP_MOVE(frexp(static_cast<number_type>(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 <class T, expression_template_option ExpressionTemplates> +inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type modf(const number<T, ExpressionTemplates>& v, number<T, ExpressionTemplates>* pipart) +{ + using default_ops::eval_modf; + number<T, ExpressionTemplates> result; + eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : 0); + return BOOST_MP_MOVE(result); +} +template <class T, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4> +inline typename enable_if_c<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type modf(const detail::expression<tag, A1, A2, A3, A4>& v, number<T, ExpressionTemplates>* pipart) +{ + using default_ops::eval_modf; + number<T, ExpressionTemplates> result, arg(v); + eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : 0); + return BOOST_MP_MOVE(result); +} +// +// Integer square root: +// template <class B, expression_template_option ExpressionTemplates> inline typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type sqrt(const number<B, ExpressionTemplates>& x) diff --git a/boost/multiprecision/detail/functions/constants.hpp b/boost/multiprecision/detail/functions/constants.hpp index 3a283c5f2e..e0a2ff5fcf 100644 --- a/boost/multiprecision/detail/functions/constants.hpp +++ b/boost/multiprecision/detail/functions/constants.hpp @@ -241,28 +241,35 @@ typename constant_initializer<T, F>::initializer const constant_initializer<T, F template <class T> const T& get_constant_ln2() { - static T result; - static bool b = false; - if(!b) + static BOOST_MP_THREAD_LOCAL T result; + static BOOST_MP_THREAD_LOCAL bool b = false; + static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value(); + if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value())) { - calc_log2(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value); + calc_log2(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value()); b = true; + digits = boost::multiprecision::detail::digits2<number<T> >::value(); } constant_initializer<T, &get_constant_ln2<T> >::do_nothing(); return result; } +#ifndef BOOST_MP_THREAD_LOCAL +#error 1 +#endif template <class T> const T& get_constant_e() { - static T result; - static bool b = false; - if(!b) + static BOOST_MP_THREAD_LOCAL T result; + static BOOST_MP_THREAD_LOCAL bool b = false; + static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value(); + if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value())) { - calc_e(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value); + calc_e(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value()); b = true; + digits = boost::multiprecision::detail::digits2<number<T> >::value(); } constant_initializer<T, &get_constant_e<T> >::do_nothing(); @@ -273,12 +280,14 @@ const T& get_constant_e() template <class T> const T& get_constant_pi() { - static T result; - static bool b = false; - if(!b) + static BOOST_MP_THREAD_LOCAL T result; + static BOOST_MP_THREAD_LOCAL bool b = false; + static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value(); + if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value())) { - calc_pi(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value); + calc_pi(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value()); b = true; + digits = boost::multiprecision::detail::digits2<number<T> >::value(); } constant_initializer<T, &get_constant_pi<T> >::do_nothing(); diff --git a/boost/multiprecision/detail/functions/pow.hpp b/boost/multiprecision/detail/functions/pow.hpp index e51df69d4a..d5ab032c2f 100644 --- a/boost/multiprecision/detail/functions/pow.hpp +++ b/boost/multiprecision/detail/functions/pow.hpp @@ -103,7 +103,7 @@ void hyp0F0(T& H0F0, const T& x) typedef typename mpl::front<typename T::unsigned_types>::type ui_type; BOOST_ASSERT(&H0F0 != &x); - long tol = boost::multiprecision::detail::digits2<number<T, et_on> >::value; + long tol = boost::multiprecision::detail::digits2<number<T, et_on> >::value(); T t; T x_pow_n_div_n_fact(x); @@ -117,9 +117,9 @@ void hyp0F0(T& H0F0, const T& x) ui_type n; - static const unsigned series_limit = - boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 - ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; + const unsigned series_limit = + boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100 + ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value(); // Series expansion of hyperg_0f0(; ; x). for(n = 2; n < series_limit; ++n) { @@ -158,16 +158,16 @@ void hyp1F0(T& H1F0, const T& a, const T& x) eval_multiply(H1F0, pochham_a, x_pow_n_div_n_fact); eval_add(H1F0, si_type(1)); T lim; - eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); + eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value()); if(eval_get_sign(lim) < 0) lim.negate(); si_type n; T term, part; - static const si_type series_limit = - boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 - ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; + const si_type series_limit = + boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100 + ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value(); // Series expansion of hyperg_1f0(a; ; x). for(n = 2; n < series_limit; n++) { @@ -237,7 +237,14 @@ void eval_exp(T& result, const T& x) // // Use series for exp(x) - 1: // - T lim = std::numeric_limits<number<T, et_on> >::epsilon().backend(); + T lim; + if(std::numeric_limits<number<T, et_on> >::is_specialized) + lim = std::numeric_limits<number<T, et_on> >::epsilon().backend(); + else + { + result = ui_type(1); + eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value()); + } unsigned k = 2; exp_series = xx; result = si_type(1); @@ -286,7 +293,7 @@ void eval_exp(T& result, const T& x) eval_convert_to(&n, result); // The scaling is 2^11 = 2048. - static const si_type p2 = static_cast<si_type>(si_type(1) << 11); + const si_type p2 = static_cast<si_type>(si_type(1) << 11); eval_multiply(exp_series, get_constant_ln2<T>(), static_cast<canonical_exp_type>(n)); eval_subtract(exp_series, xx); @@ -346,7 +353,10 @@ void eval_log(T& result, const T& arg) else eval_subtract(result, t); - eval_multiply(lim, result, std::numeric_limits<number<T, et_on> >::epsilon().backend()); + if(std::numeric_limits<number<T, et_on> >::is_specialized) + eval_multiply(lim, result, std::numeric_limits<number<T, et_on> >::epsilon().backend()); + else + eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value()); if(eval_get_sign(lim) < 0) lim.negate(); INSTRUMENT_BACKEND(lim); @@ -369,14 +379,17 @@ void eval_log(T& result, const T& arg) template <class T> const T& get_constant_log10() { - static T result; - static bool b = false; - if(!b) + static BOOST_MP_THREAD_LOCAL T result; + static BOOST_MP_THREAD_LOCAL bool b = false; + static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value(); + if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value())) { typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type; T ten; ten = ui_type(10u); eval_log(result, ten); + b = true; + digits = boost::multiprecision::detail::digits2<number<T> >::value(); } constant_initializer<T, &get_constant_log10<T> >::do_nothing(); @@ -606,7 +619,7 @@ namespace detail{ ui_type k = 1; T lim(x); - eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); + eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value()); do { diff --git a/boost/multiprecision/detail/functions/trig.hpp b/boost/multiprecision/detail/functions/trig.hpp index be2a9deb77..c84a639418 100644 --- a/boost/multiprecision/detail/functions/trig.hpp +++ b/boost/multiprecision/detail/functions/trig.hpp @@ -38,15 +38,15 @@ void hyp0F1(T& result, const T& b, const T& x) T tol; tol = ui_type(1); - eval_ldexp(tol, tol, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); + eval_ldexp(tol, tol, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value()); eval_multiply(tol, result); if(eval_get_sign(tol) < 0) tol.negate(); T term; - static const int series_limit = - boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 - ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; + const int series_limit = + boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100 + ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value(); // Series expansion of hyperg_0f1(; b; x). for(n = 2; n < series_limit; ++n) { @@ -365,7 +365,7 @@ void hyp2F1(T& result, const T& a, const T& b, const T& c, const T& x) eval_add(result, ui_type(1)); T lim; - eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); + eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value()); if(eval_get_sign(lim) < 0) lim.negate(); @@ -373,9 +373,9 @@ void hyp2F1(T& result, const T& a, const T& b, const T& c, const T& x) ui_type n; T term; - static const unsigned series_limit = - boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 - ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; + const unsigned series_limit = + boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100 + ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value(); // Series expansion of hyperg_2f1(a, b; c; x). for(n = 2; n < series_limit; ++n) { @@ -497,11 +497,16 @@ void eval_asin(T& result, const T& x) result = (guess_type)(std::asin(dd)); - unsigned current_digits = std::numeric_limits<guess_type>::digits - 5; - unsigned target_precision = boost::multiprecision::detail::digits2<number<T, et_on> >::value; + // Newton-Raphson iteration, we should double our precision with each iteration, + // in practice this seems to not quite work in all cases... so terminate when we + // have at least 2/3 of the digits correct on the assumption that the correction + // we've just added will finish the job... + + boost::intmax_t current_precision = eval_ilogb(result); + boost::intmax_t target_precision = current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3; // Newton-Raphson iteration - while(current_digits < target_precision) + while(current_precision > target_precision) { T sine, cosine; eval_sin(sine, result); @@ -509,18 +514,11 @@ void eval_asin(T& result, const T& x) eval_subtract(sine, xx); eval_divide(sine, cosine); eval_subtract(result, sine); - - current_digits *= 2; - /* - T lim; - eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); - if(eval_get_sign(s) < 0) - s.negate(); - if(eval_get_sign(lim) < 0) - lim.negate(); - if(lim.compare(s) >= 0) + current_precision = eval_ilogb(sine); +#ifdef FP_ILOGB0 + if(current_precision == FP_ILOGB0) break; - */ +#endif } if(b_neg) result.negate(); @@ -646,11 +644,16 @@ void eval_atan(T& result, const T& x) eval_convert_to(&d, xx); result = fp_type(std::atan(d)); - // Newton-Raphson iteration - static const boost::int32_t double_digits10_minus_a_few = std::numeric_limits<double>::digits10 - 3; + // Newton-Raphson iteration, we should double our precision with each iteration, + // in practice this seems to not quite work in all cases... so terminate when we + // have at least 2/3 of the digits correct on the assumption that the correction + // we've just added will finish the job... + + boost::intmax_t current_precision = eval_ilogb(result); + boost::intmax_t target_precision = current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3; T s, c, t; - for(boost::int32_t digits = double_digits10_minus_a_few; digits <= std::numeric_limits<number<T, et_on> >::digits10; digits *= 2) + while(current_precision > target_precision) { eval_sin(s, result); eval_cos(c, result); @@ -658,6 +661,11 @@ void eval_atan(T& result, const T& x) eval_subtract(t, s); eval_multiply(s, t, c); eval_add(result, s); + current_precision = eval_ilogb(s); +#ifdef FP_ILOGB0 + if(current_precision == FP_ILOGB0) + break; +#endif } if(b_neg) result.negate(); diff --git a/boost/multiprecision/detail/generic_interconvert.hpp b/boost/multiprecision/detail/generic_interconvert.hpp index d1fa028d30..6a840f8544 100644 --- a/boost/multiprecision/detail/generic_interconvert.hpp +++ b/boost/multiprecision/detail/generic_interconvert.hpp @@ -35,36 +35,37 @@ void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_ using default_ops::eval_right_shift; using default_ops::eval_ldexp; using default_ops::eval_add; + using default_ops::eval_is_zero; // smallest unsigned type handled natively by "From" is likely to be it's limb_type: - typedef typename canonical<unsigned char, From>::type limb_type; + typedef typename canonical<unsigned char, From>::type l_limb_type; // get the corresponding type that we can assign to "To": - typedef typename canonical<limb_type, To>::type to_type; + typedef typename canonical<l_limb_type, To>::type to_type; From t(from); bool is_neg = eval_get_sign(t) < 0; if(is_neg) t.negate(); // Pick off the first limb: - limb_type limb; - limb_type mask = ~static_cast<limb_type>(0); + l_limb_type limb; + l_limb_type mask = static_cast<l_limb_type>(~static_cast<l_limb_type>(0)); From fl; eval_bitwise_and(fl, t, mask); eval_convert_to(&limb, fl); to = static_cast<to_type>(limb); - eval_right_shift(t, std::numeric_limits<limb_type>::digits); + eval_right_shift(t, std::numeric_limits<l_limb_type>::digits); // // Then keep picking off more limbs until "t" is zero: // To l; - unsigned shift = std::numeric_limits<limb_type>::digits; + unsigned shift = std::numeric_limits<l_limb_type>::digits; while(!eval_is_zero(t)) { eval_bitwise_and(fl, t, mask); eval_convert_to(&limb, fl); l = static_cast<to_type>(limb); - eval_right_shift(t, std::numeric_limits<limb_type>::digits); + eval_right_shift(t, std::numeric_limits<l_limb_type>::digits); eval_ldexp(l, l, shift); eval_add(to, l); - shift += std::numeric_limits<limb_type>::digits; + shift += std::numeric_limits<l_limb_type>::digits; } // // Finish off by setting the sign: @@ -310,7 +311,7 @@ typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type num = -num; } int denom_bits = msb(denom); - int shift = std::numeric_limits<To>::digits + denom_bits - msb(num) + 1; + int shift = std::numeric_limits<To>::digits + denom_bits - msb(num); if(shift > 0) num <<= shift; else if(shift < 0) @@ -318,7 +319,7 @@ typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type Integer q, r; divide_qr(num, denom, q, r); int q_bits = msb(q); - if(q_bits == std::numeric_limits<To>::digits) + if(q_bits == std::numeric_limits<To>::digits - 1) { // // Round up if 2 * r > denom: @@ -334,7 +335,7 @@ typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type } else { - BOOST_ASSERT(q_bits == 1 + std::numeric_limits<To>::digits); + BOOST_ASSERT(q_bits == std::numeric_limits<To>::digits); // // We basically already have the rounding info: // diff --git a/boost/multiprecision/detail/number_base.hpp b/boost/multiprecision/detail/number_base.hpp index f229914c79..5911b3a28b 100644 --- a/boost/multiprecision/detail/number_base.hpp +++ b/boost/multiprecision/detail/number_base.hpp @@ -26,16 +26,25 @@ # define BOOST_MP_FORCEINLINE inline #endif -#if (defined(BOOST_GCC) && (BOOST_GCC <= 40700)) || defined(__SUNPRO_CC) +#if (defined(BOOST_GCC) && (BOOST_GCC <= 40700)) || BOOST_WORKAROUND(__SUNPRO_CC, < 0x5140) # define BOOST_MP_NOEXCEPT_IF(x) #else # define BOOST_MP_NOEXCEPT_IF(x) BOOST_NOEXCEPT_IF(x) #endif -#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) || defined(__SUNPRO_CC) +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) || BOOST_WORKAROUND(__SUNPRO_CC, < 0x5140) #define BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS #endif +// +// Thread local storage: +// +#if !defined(BOOST_NO_CXX11_THREAD_LOCAL) && !defined(BOOST_INTEL) +# define BOOST_MP_THREAD_LOCAL thread_local +#else +# define BOOST_MP_THREAD_LOCAL +#endif + #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable:6326) @@ -402,7 +411,11 @@ struct expression<tag, Arg1, void, void, void> return static_cast<T>(static_cast<result_type>(*this)); } # else - template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0> + template <class T +#ifndef __SUNPRO_CC +, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 +#endif +> explicit operator T()const { return static_cast<T>(static_cast<result_type>(*this)); @@ -412,7 +425,9 @@ struct expression<tag, Arg1, void, void, void> result_type r(*this); return static_cast<bool>(r); } - explicit operator void()const {} +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_MP_FORCEINLINE explicit operator void()const {} +#endif # endif #else operator unmentionable_type()const @@ -466,7 +481,11 @@ struct expression<terminal, Arg1, void, void, void> return static_cast<T>(static_cast<result_type>(*this)); } # else - template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0> + template <class T +#ifndef __SUNPRO_CC +, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 +#endif +> explicit operator T()const { return static_cast<T>(static_cast<result_type>(*this)); @@ -476,7 +495,9 @@ struct expression<terminal, Arg1, void, void, void> result_type r(*this); return static_cast<bool>(r); } - explicit operator void()const {} +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_MP_FORCEINLINE explicit operator void()const {} +#endif # endif #else operator unmentionable_type()const @@ -534,7 +555,11 @@ struct expression<tag, Arg1, Arg2, void, void> return static_cast<T>(static_cast<result_type>(*this)); } # else - template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0> + template <class T +#ifndef __SUNPRO_CC +, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 +#endif +> explicit operator T()const { return static_cast<T>(static_cast<result_type>(*this)); @@ -544,7 +569,9 @@ struct expression<tag, Arg1, Arg2, void, void> result_type r(*this); return static_cast<bool>(r); } - explicit operator void()const {} +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_MP_FORCEINLINE explicit operator void()const {} +#endif # endif #else operator unmentionable_type()const @@ -613,7 +640,11 @@ struct expression<tag, Arg1, Arg2, Arg3, void> return static_cast<T>(static_cast<result_type>(*this)); } # else - template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0> + template <class T +#ifndef __SUNPRO_CC +, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 +#endif +> explicit operator T()const { return static_cast<T>(static_cast<result_type>(*this)); @@ -623,7 +654,9 @@ struct expression<tag, Arg1, Arg2, Arg3, void> result_type r(*this); return static_cast<bool>(r); } - explicit operator void()const {} +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_MP_FORCEINLINE explicit operator void()const {} +#endif # endif #else operator unmentionable_type()const @@ -701,7 +734,11 @@ struct expression return static_cast<T>(static_cast<result_type>(*this)); } # else - template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0> + template <class T +#ifndef __SUNPRO_CC +, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 +#endif +> explicit operator T()const { return static_cast<T>(static_cast<result_type>(*this)); @@ -711,7 +748,9 @@ struct expression result_type r(*this); return static_cast<bool>(r); } - explicit operator void()const {} +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_MP_FORCEINLINE explicit operator void()const {} +#endif # endif #else operator unmentionable_type()const @@ -751,7 +790,8 @@ struct digits2 BOOST_STATIC_ASSERT((std::numeric_limits<T>::radix == 2) || (std::numeric_limits<T>::radix == 10)); // If we really have so many digits that this fails, then we're probably going to hit other problems anyway: BOOST_STATIC_ASSERT(LONG_MAX / 1000 > (std::numeric_limits<T>::digits + 1)); - static const long value = std::numeric_limits<T>::radix == 10 ? (((std::numeric_limits<T>::digits + 1) * 1000L) / 301L) : std::numeric_limits<T>::digits; + static const long m_value = std::numeric_limits<T>::radix == 10 ? (((std::numeric_limits<T>::digits + 1) * 1000L) / 301L) : std::numeric_limits<T>::digits; + static inline BOOST_CONSTEXPR long value()BOOST_NOEXCEPT { return m_value; } }; #ifndef BOOST_MP_MIN_EXPONENT_DIGITS diff --git a/boost/multiprecision/detail/ublas_interop.hpp b/boost/multiprecision/detail/ublas_interop.hpp index d1aae4dc6e..cf56dc9fb8 100644 --- a/boost/multiprecision/detail/ublas_interop.hpp +++ b/boost/multiprecision/detail/ublas_interop.hpp @@ -32,6 +32,18 @@ struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplate >::type promote_type; }; +template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class Arithmetic> +struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, Arithmetic> +{ + typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> promote_type; +}; + +template <class Arithmetic, class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1> +struct promote_traits<Arithmetic, boost::multiprecision::number<Backend1, ExpressionTemplates1> > +{ + typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> promote_type; +}; + template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class tag, class Arg1, class Arg2, class Arg3, class Arg4> struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > { diff --git a/boost/multiprecision/float128.hpp b/boost/multiprecision/float128.hpp index 979666a393..035b670228 100644 --- a/boost/multiprecision/float128.hpp +++ b/boost/multiprecision/float128.hpp @@ -8,6 +8,7 @@ #include <boost/config.hpp> #include <boost/scoped_array.hpp> +#include <boost/functional/hash.hpp> #include <boost/multiprecision/number.hpp> #if defined(BOOST_INTEL) && !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD) @@ -489,6 +490,11 @@ inline void eval_atan2(float128_backend& result, const float128_backend& a, cons result.value() = atan2q(a.value(), b.value()); } +inline std::size_t hash_value(const float128_backend& val) +{ + return boost::hash_value(static_cast<double>(val.value())); +} + } // namespace backends }} // namespaces @@ -547,7 +553,26 @@ void serialize(Archive& ar, boost::multiprecision::backends::float128_backend& v float128_detail::do_serialize(ar, val, load_tag(), binary_tag()); } -}} +} // namepsace multiprecision + +namespace math{ + +template <multiprecision::expression_template_option ExpressionTemplates> +inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& arg) +{ + return ::signbitq(arg.backend().value()); +} + +template <multiprecision::expression_template_option ExpressionTemplates> +inline boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& a, const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& b) +{ + return ::copysignq(a.backend().value(), b.backend().value()); +} + + +} // namespace math + +} // namespace boost namespace std{ diff --git a/boost/multiprecision/gmp.hpp b/boost/multiprecision/gmp.hpp index f7d4e90961..7f01682a2a 100644 --- a/boost/multiprecision/gmp.hpp +++ b/boost/multiprecision/gmp.hpp @@ -7,11 +7,13 @@ #define BOOST_MATH_ER_GMP_BACKEND_HPP #include <boost/multiprecision/number.hpp> +#include <boost/multiprecision/debug_adaptor.hpp> #include <boost/multiprecision/detail/integer_ops.hpp> #include <boost/multiprecision/detail/big_lanczos.hpp> #include <boost/multiprecision/detail/digits.hpp> #include <boost/math/special_functions/fpclassify.hpp> #include <boost/cstdint.hpp> +#include <boost/functional/hash_fwd.hpp> #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable:4127) @@ -20,6 +22,13 @@ #ifdef BOOST_MSVC # pragma warning(pop) #endif + +#if defined(__MPIR_VERSION) && defined(__MPIR_VERSION_MINOR) && defined(__MPIR_VERSION_PATCHLEVEL) +# define BOOST_MP_MPIR_VERSION (__MPIR_VERSION * 10000 + __MPIR_VERSION_MINOR * 100 + __MPIR_VERSION_PATCHLEVEL) +#else +# define BOOST_MP_MPIR_VERSION 0 +#endif + #include <cmath> #include <limits> #include <climits> @@ -564,7 +573,7 @@ struct gmp_float<0> : public detail::gmp_float_imp<0> } unsigned precision()const BOOST_NOEXCEPT { - return multiprecision::detail::digits2_2_10(mpf_get_prec(this->m_data)); + return static_cast<unsigned>(multiprecision::detail::digits2_2_10(mpf_get_prec(this->m_data))); } void precision(unsigned digits10) BOOST_NOEXCEPT { @@ -971,16 +980,39 @@ inline void eval_ldexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& v template <unsigned Digits10> inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, int* e) { +#if BOOST_MP_MPIR_VERSION >= 20600 + mpir_si v; + mpf_get_d_2exp(&v, val.data()); +#else long v; mpf_get_d_2exp(&v, val.data()); +#endif *e = v; eval_ldexp(result, val, -v); } template <unsigned Digits10> inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long* e) { +#if BOOST_MP_MPIR_VERSION >= 20600 + mpir_si v; + mpf_get_d_2exp(&v, val.data()); + *e = v; + eval_ldexp(result, val, -v); +#else mpf_get_d_2exp(e, val.data()); eval_ldexp(result, val, -*e); +#endif +} + +template <unsigned Digits10> +inline std::size_t hash_value(const gmp_float<Digits10>& val) +{ + std::size_t result = 0; + for(int i = 0; i < std::abs(val.data()[0]._mp_size); ++i) + boost::hash_combine(result, val.data()[0]._mp_d[i]); + boost::hash_combine(result, val.data()[0]._mp_exp); + boost::hash_combine(result, val.data()[0]._mp_size); + return result; } struct gmp_int @@ -1637,7 +1669,7 @@ inline unsigned eval_lsb(const gmp_int& val) { BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); } - return mpz_scan1(val.data(), 0); + return static_cast<unsigned>(mpz_scan1(val.data(), 0)); } inline unsigned eval_msb(const gmp_int& val) @@ -1651,7 +1683,7 @@ inline unsigned eval_msb(const gmp_int& val) { BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); } - return mpz_sizeinbase(val.data(), 2) - 1; + return static_cast<unsigned>(mpz_sizeinbase(val.data(), 2) - 1); } inline bool eval_bit_test(const gmp_int& val, unsigned index) @@ -1731,6 +1763,16 @@ inline typename enable_if< mpz_powm_ui(result.data(), base.data(), p, m.data()); } +inline std::size_t hash_value(const gmp_int& val) +{ + // We should really use mpz_limbs_read here, but that's unsupported on older versions: + std::size_t result = 0; + for(int i = 0; i < std::abs(val.data()[0]._mp_size); ++i) + boost::hash_combine(result, val.data()[0]._mp_d[i]); + boost::hash_combine(result, val.data()[0]._mp_size); + return result; +} + struct gmp_rational; void eval_add(gmp_rational& t, const gmp_rational& o); @@ -2094,6 +2136,17 @@ inline void assign_components(gmp_rational& result, gmp_int const& v1, gmp_int c mpq_canonicalize(result.data()); } +inline std::size_t hash_value(const gmp_rational& val) +{ + std::size_t result = 0; + for(int i = 0; i < std::abs(val.data()[0]._mp_num._mp_size); ++i) + boost::hash_combine(result, val.data()[0]._mp_num._mp_d[i]); + for(int i = 0; i < std::abs(val.data()[0]._mp_den._mp_size); ++i) + boost::hash_combine(result, val.data()[0]._mp_den._mp_d[i]); + boost::hash_combine(result, val.data()[0]._mp_num._mp_size); + return result; +} + // // Some member functions that are dependent upon previous code go here: // @@ -2212,10 +2265,10 @@ inline number<gmp_int, ET> denominator(const number<gmp_rational, ET>& val) return result; } -#ifdef BOOST_NO_SFINAE_EXPR - namespace detail{ +#ifdef BOOST_NO_SFINAE_EXPR + template<> struct is_explicitly_convertible<canonical<mpf_t, gmp_int>::type, gmp_int> : public mpl::true_ {}; template<> @@ -2227,10 +2280,46 @@ struct is_explicitly_convertible<gmp_rational, gmp_int> : public mpl::true_ {}; template<unsigned D1, unsigned D2> struct is_explicitly_convertible<gmp_float<D1>, gmp_float<D2> > : public mpl::true_ {}; -} - #endif +template <> +struct digits2<number<gmp_float<0>, et_on> > +{ + static long value() + { + return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision()); + } +}; + +template <> +struct digits2<number<gmp_float<0>, et_off> > +{ + static long value() + { + return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision()); + } +}; + +template <> +struct digits2<number<debug_adaptor<gmp_float<0> >, et_on> > +{ + static long value() + { + return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision()); + } +}; + +template <> +struct digits2<number<debug_adaptor<gmp_float<0> >, et_off> > +{ + static long value() + { + return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision()); + } +}; + +} + template<> struct number_category<detail::canonical<mpz_t, gmp_int>::type> : public mpl::int_<number_kind_integer>{}; template<> @@ -2247,7 +2336,113 @@ typedef number<gmp_float<0> > mpf_float; typedef number<gmp_int > mpz_int; typedef number<gmp_rational > mpq_rational; -}} // namespaces +} // namespace multiprecision + +namespace math { namespace tools{ + + template <> + inline int digits<boost::multiprecision::mpf_float>() +#ifdef BOOST_MATH_NOEXCEPT + BOOST_NOEXCEPT +#endif + { + return multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::default_precision()); + } + template <> + inline int digits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >() +#ifdef BOOST_MATH_NOEXCEPT + BOOST_NOEXCEPT +#endif + { + return multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::default_precision()); + } + + template <> + inline boost::multiprecision::mpf_float + max_value<boost::multiprecision::mpf_float>() + { + boost::multiprecision::mpf_float result(0.5); + mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1); + return result; + } + + template <> + inline boost::multiprecision::mpf_float + min_value<boost::multiprecision::mpf_float>() + { + boost::multiprecision::mpf_float result(0.5); + mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::min)() / 64 + 1); + return result; + } + + template <> + inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> + max_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >() + { + boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5); + mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1); + return result; + } + + template <> + inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> + min_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >() + { + boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5); + mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1); + return result; + } + + template <> + inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >() +#ifdef BOOST_MATH_NOEXCEPT + BOOST_NOEXCEPT +#endif + { + return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::default_precision()); + } + template <> + inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >() +#ifdef BOOST_MATH_NOEXCEPT + BOOST_NOEXCEPT +#endif + { + return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::default_precision()); + } + + template <> + inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > + max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >() + { + return max_value<boost::multiprecision::mpf_float>().backend(); + } + + template <> + inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > + min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >() + { + return min_value<boost::multiprecision::mpf_float>().backend(); + } + + template <> + inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> + max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >() + { + return max_value<boost::multiprecision::mpf_float>().backend(); + } + + template <> + inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> + min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >() + { + return min_value<boost::multiprecision::mpf_float>().backend(); + } + + +}} // namespaces math::tools + + +} // namespace boost namespace std{ diff --git a/boost/multiprecision/logged_adaptor.hpp b/boost/multiprecision/logged_adaptor.hpp index 8d430c7d20..2f916dd101 100644 --- a/boost/multiprecision/logged_adaptor.hpp +++ b/boost/multiprecision/logged_adaptor.hpp @@ -139,6 +139,22 @@ public: ar & m_value; log_postfix_event(m_value, "serialize"); } + static unsigned default_precision() BOOST_NOEXCEPT + { + return Backend::default_precision(); + } + static void default_precision(unsigned v) BOOST_NOEXCEPT + { + Backend::default_precision(v); + } + unsigned precision()const BOOST_NOEXCEPT + { + return value().precision(); + } + void precision(unsigned digits10) BOOST_NOEXCEPT + { + value().precision(digits10); + } }; template <class T> @@ -490,6 +506,12 @@ NON_MEMBER_OP3(fmod, "fmod"); NON_MEMBER_OP3(pow, "pow"); NON_MEMBER_OP3(atan2, "atan2"); +template <class Backend> +std::size_t hash_value(const logged_adaptor<Backend>& val) +{ + return hash_value(val.value()); +} + } // namespace backends using backends::logged_adaptor; diff --git a/boost/multiprecision/miller_rabin.hpp b/boost/multiprecision/miller_rabin.hpp index 96dac04df5..156f9b852b 100644 --- a/boost/multiprecision/miller_rabin.hpp +++ b/boost/multiprecision/miller_rabin.hpp @@ -6,7 +6,7 @@ #ifndef BOOST_MP_MR_HPP #define BOOST_MP_MR_HPP -#include <boost/multiprecision/random.hpp> +#include <boost/random.hpp> #include <boost/multiprecision/integer.hpp> namespace boost{ diff --git a/boost/multiprecision/mpfi.hpp b/boost/multiprecision/mpfi.hpp index 1ac7d1b5b9..00a692981c 100644 --- a/boost/multiprecision/mpfi.hpp +++ b/boost/multiprecision/mpfi.hpp @@ -12,11 +12,17 @@ #include <boost/multiprecision/detail/big_lanczos.hpp> #include <boost/multiprecision/detail/digits.hpp> #include <boost/multiprecision/mpfr.hpp> +#include <boost/multiprecision/logged_adaptor.hpp> #include <boost/math/constants/constants.hpp> +#include <boost/functional/hash_fwd.hpp> #include <mpfi.h> #include <cmath> #include <algorithm> +#ifndef BOOST_MULTIPRECISION_MPFI_DEFAULT_PRECISION +# define BOOST_MULTIPRECISION_MPFI_DEFAULT_PRECISION 20 +#endif + namespace boost{ namespace multiprecision{ namespace backends{ @@ -315,7 +321,7 @@ protected: mpfi_t m_data; static unsigned& get_default_precision() BOOST_NOEXCEPT { - static unsigned val = 50; + static unsigned val = BOOST_MULTIPRECISION_MPFI_DEFAULT_PRECISION; return val; } }; @@ -1015,6 +1021,28 @@ inline void eval_tanh(mpfi_float_backend<Digits10>& result, const mpfi_float_bac mpfi_tanh(result.data(), arg.data()); } +template <unsigned Digits10> +inline std::size_t hash_value(const mpfi_float_backend<Digits10>& val) +{ + std::size_t result = 0; + std::size_t len = val.left_data()[0]._mpfr_prec / mp_bits_per_limb; + if(val.left_data()[0]._mpfr_prec % mp_bits_per_limb) + ++len; + for(int i = 0; i < len; ++i) + boost::hash_combine(result, val.left_data()[0]._mpfr_d[i]); + boost::hash_combine(result, val.left_data()[0]._mpfr_exp); + boost::hash_combine(result, val.left_data()[0]._mpfr_sign); + + len = val.right_data()[0]._mpfr_prec / mp_bits_per_limb; + if(val.right_data()[0]._mpfr_prec % mp_bits_per_limb) + ++len; + for(int i = 0; i < len; ++i) + boost::hash_combine(result, val.right_data()[0]._mpfr_d[i]); + boost::hash_combine(result, val.right_data()[0]._mpfr_exp); + boost::hash_combine(result, val.right_data()[0]._mpfr_sign); + return result; +} + } // namespace backends #ifdef BOOST_NO_SFINAE_EXPR @@ -1153,7 +1181,7 @@ inline int digits<boost::multiprecision::mpfi_float>() BOOST_NOEXCEPT #endif { - return boost::multiprecision::backends::detail::get_default_precision(); + return multiprecision::detail::digits10_2_2(boost::multiprecision::mpfi_float::default_precision()); } template <> inline int digits<boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<0>, boost::multiprecision::et_off> >() @@ -1161,9 +1189,109 @@ inline int digits<boost::multiprecision::number<boost::multiprecision::mpfi_floa BOOST_NOEXCEPT #endif { - return boost::multiprecision::backends::detail::get_default_precision(); + return multiprecision::detail::digits10_2_2(boost::multiprecision::mpfi_float::default_precision()); +} + +template <> +inline boost::multiprecision::mpfi_float +max_value<boost::multiprecision::mpfi_float>() +{ + boost::multiprecision::mpfi_float result(0.5); + mpfi_mul_2exp(result.backend().data(), result.backend().data(), mpfr_get_emax()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; +} + +template <> +inline boost::multiprecision::mpfi_float +min_value<boost::multiprecision::mpfi_float>() +{ + boost::multiprecision::mpfi_float result(0.5); + mpfi_div_2exp(result.backend().data(), result.backend().data(), -mpfr_get_emin()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; +} + +template <> +inline boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<0>, boost::multiprecision::et_off> +max_value<boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<0>, boost::multiprecision::et_off> >() +{ + boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<0>, boost::multiprecision::et_off> result(0.5); + mpfi_mul_2exp(result.backend().data(), result.backend().data(), mpfr_get_emax()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; +} + +template <> +inline boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<0>, boost::multiprecision::et_off> +min_value<boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<0>, boost::multiprecision::et_off> >() +{ + boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<0>, boost::multiprecision::et_off> result(0.5); + mpfi_div_2exp(result.backend().data(), result.backend().data(), -mpfr_get_emin()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; +} + +// mpfi gets used with logged_adaptor fairly often, so specialize for that use case as well: +typedef boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<boost::multiprecision::mpfi_float::backend_type>, boost::multiprecision::et_on> logged_type1; +typedef boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<boost::multiprecision::mpfi_float::backend_type>, boost::multiprecision::et_off> logged_type2; + +template <> +inline int digits<logged_type1>() +#ifdef BOOST_MATH_NOEXCEPT +BOOST_NOEXCEPT +#endif +{ + return multiprecision::detail::digits10_2_2(logged_type1::default_precision()); +} +template <> +inline int digits<logged_type2 >() +#ifdef BOOST_MATH_NOEXCEPT +BOOST_NOEXCEPT +#endif +{ + return multiprecision::detail::digits10_2_2(logged_type1::default_precision()); +} + +template <> +inline logged_type1 +max_value<logged_type1>() +{ + logged_type1 result(0.5); + mpfi_mul_2exp(result.backend().value().data(), result.backend().value().data(), mpfr_get_emax()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; +} + +template <> +inline logged_type1 +min_value<logged_type1>() +{ + logged_type1 result(0.5); + mpfi_div_2exp(result.backend().value().data(), result.backend().value().data(), -mpfr_get_emin()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; +} + +template <> +inline logged_type2 +max_value<logged_type2 >() +{ + logged_type2 result(0.5); + mpfi_mul_2exp(result.backend().value().data(), result.backend().value().data(), mpfr_get_emax()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; } +template <> +inline logged_type2 +min_value<logged_type2 >() +{ + logged_type2 result(0.5); + mpfi_div_2exp(result.backend().value().data(), result.backend().value().data(), -mpfr_get_emin()); + //BOOST_ASSERT(mpfi_number_p(result.backend().data())); + return result; +} } // namespace tools namespace constants{ namespace detail{ @@ -1217,13 +1345,19 @@ struct constant_pi<boost::multiprecision::number<boost::multiprecision::mpfi_flo } return result; } + static inline result_type get(const mpl::int_<0>&) + { + result_type result; + mpfi_const_pi(result.backend().data()); + return result; + } }; template<unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> struct constant_ln_two<boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<Digits10>, ExpressionTemplates> > { typedef boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<Digits10>, ExpressionTemplates> result_type; template<int N> - static inline result_type const& get(const mpl::int_<N>&) + static inline result_type get(const mpl::int_<N>&) { mpfi_initializer<result_type>::force_instantiate(); static result_type result; @@ -1235,6 +1369,12 @@ struct constant_ln_two<boost::multiprecision::number<boost::multiprecision::mpfi } return result; } + static inline result_type get(const mpl::int_<0>&) + { + result_type result; + mpfi_const_log2(result.backend().data()); + return result; + } }; template<unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> struct constant_euler<boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<Digits10>, ExpressionTemplates> > @@ -1253,6 +1393,12 @@ struct constant_euler<boost::multiprecision::number<boost::multiprecision::mpfi_ } return result; } + static inline result_type get(const mpl::int_<0>&) + { + result_type result; + mpfi_const_euler(result.backend().data()); + return result; + } }; template<unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> struct constant_catalan<boost::multiprecision::number<boost::multiprecision::mpfi_float_backend<Digits10>, ExpressionTemplates> > @@ -1271,6 +1417,12 @@ struct constant_catalan<boost::multiprecision::number<boost::multiprecision::mpf } return result; } + static inline result_type get(const mpl::int_<0>&) + { + result_type result; + mpfi_const_catalan(result.backend().data()); + return result; + } }; }} // namespaces diff --git a/boost/multiprecision/mpfr.hpp b/boost/multiprecision/mpfr.hpp index 299de4a587..e6ccc18abb 100644 --- a/boost/multiprecision/mpfr.hpp +++ b/boost/multiprecision/mpfr.hpp @@ -7,6 +7,7 @@ #define BOOST_MATH_BN_MPFR_HPP #include <boost/multiprecision/number.hpp> +#include <boost/multiprecision/debug_adaptor.hpp> #include <boost/multiprecision/gmp.hpp> #include <boost/math/special_functions/fpclassify.hpp> #include <boost/cstdint.hpp> @@ -16,6 +17,10 @@ #include <cmath> #include <algorithm> +#ifndef BOOST_MULTIPRECISION_MPFR_DEFAULT_PRECISION +# define BOOST_MULTIPRECISION_MPFR_DEFAULT_PRECISION 20 +#endif + namespace boost{ namespace multiprecision{ @@ -30,6 +35,9 @@ namespace backends{ template <unsigned digits10, mpfr_allocation_type AllocationType = allocate_dynamic> struct mpfr_float_backend; +template <> +struct mpfr_float_backend<0, allocate_stack>; + } // namespace backends template <unsigned digits10, mpfr_allocation_type AllocationType> @@ -55,7 +63,6 @@ struct mpfr_cleanup template <bool b> typename mpfr_cleanup<b>::initializer const mpfr_cleanup<b>::init; -inline long get_default_precision() { return 50; } template <unsigned digits10, mpfr_allocation_type AllocationType> struct mpfr_float_imp; @@ -311,7 +318,7 @@ struct mpfr_float_imp<digits10, allocate_dynamic> } ~mpfr_float_imp() BOOST_NOEXCEPT { - if(m_data[0]._mpfr_d) + if(m_data[0]._mpfr_d) mpfr_clear(m_data); detail::mpfr_cleanup<true>::force_instantiate(); } @@ -357,7 +364,7 @@ protected: mpfr_t m_data; static unsigned& get_default_precision() BOOST_NOEXCEPT { - static unsigned val = 50; + static unsigned val = BOOST_MULTIPRECISION_MPFR_DEFAULT_PRECISION; return val; } }; @@ -1425,6 +1432,40 @@ inline void eval_tanh(mpfr_float_backend<Digits10, AllocateType>& result, const mpfr_tanh(result.data(), arg.data(), GMP_RNDN); } +template <unsigned Digits10, mpfr_allocation_type AllocateType> +inline void eval_modf(mpfr_float_backend<Digits10, AllocateType>& result, const mpfr_float_backend<Digits10, AllocateType>& arg, mpfr_float_backend<Digits10, AllocateType>* pipart) +{ + if(0 == pipart) + { + mpfr_float_backend<Digits10, AllocateType> ipart; + mpfr_modf(ipart.data(), result.data(), arg.data(), GMP_RNDN); + } + else + { + mpfr_modf(pipart->data(), result.data(), arg.data(), GMP_RNDN); + } +} + +template <unsigned Digits10, mpfr_allocation_type AllocateType> +inline void eval_fmod(mpfr_float_backend<Digits10, AllocateType>& result, const mpfr_float_backend<Digits10, AllocateType>& a, const mpfr_float_backend<Digits10, AllocateType>& b) +{ + mpfr_fmod(result.data(), a.data(), b.data(), GMP_RNDN); +} + +template <unsigned Digits10, mpfr_allocation_type AllocateType> +inline std::size_t hash_value(const mpfr_float_backend<Digits10, AllocateType>& val) +{ + std::size_t result = 0; + std::size_t len = val.data()[0]._mpfr_prec / mp_bits_per_limb; + if(val.data()[0]._mpfr_prec % mp_bits_per_limb) + ++len; + for(int i = 0; i < len; ++i) + boost::hash_combine(result, val.data()[0]._mpfr_d[i]); + boost::hash_combine(result, val.data()[0]._mpfr_exp); + boost::hash_combine(result, val.data()[0]._mpfr_sign); + return result; +} + } // namespace backends #ifdef BOOST_NO_SFINAE_EXPR @@ -1464,7 +1505,7 @@ inline int digits<boost::multiprecision::mpfr_float>() BOOST_NOEXCEPT #endif { - return boost::multiprecision::backends::detail::get_default_precision(); + return multiprecision::detail::digits10_2_2(boost::multiprecision::mpfr_float::default_precision()); } template <> inline int digits<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0>, boost::multiprecision::et_off> >() @@ -1472,7 +1513,7 @@ inline int digits<boost::multiprecision::number<boost::multiprecision::mpfr_floa BOOST_NOEXCEPT #endif { - return boost::multiprecision::backends::detail::get_default_precision(); + return multiprecision::detail::digits10_2_2(boost::multiprecision::mpfr_float::default_precision()); } template <> @@ -1515,6 +1556,51 @@ inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0 return result; } +template <> +inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float::backend_type> > >() +#ifdef BOOST_MATH_NOEXCEPT +BOOST_NOEXCEPT +#endif +{ + return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float::backend_type> >::default_precision()); +} +template <> +inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<0> >, boost::multiprecision::et_off> >() +#ifdef BOOST_MATH_NOEXCEPT +BOOST_NOEXCEPT +#endif +{ + return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float::backend_type> >::default_precision()); +} + +template <> +inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float::backend_type> > +max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float::backend_type> > >() +{ + return max_value<boost::multiprecision::mpfr_float>().backend(); +} + +template <> +inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float::backend_type> > +min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float::backend_type> > >() +{ + return min_value<boost::multiprecision::mpfr_float>().backend(); +} + +template <> +inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<0> >, boost::multiprecision::et_off> +max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<0> >, boost::multiprecision::et_off> >() +{ + return max_value<boost::multiprecision::mpfr_float>().backend(); +} + +template <> +inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<0> >, boost::multiprecision::et_off> +min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<0> >, boost::multiprecision::et_off> >() +{ + return min_value<boost::multiprecision::mpfr_float>().backend(); +} + } // namespace tools namespace constants{ namespace detail{ @@ -1567,6 +1653,12 @@ struct constant_pi<boost::multiprecision::number<boost::multiprecision::mpfr_flo } return result; } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_pi(result.backend().data(), GMP_RNDN); + return result; + } }; template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> struct constant_ln_two<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > @@ -1585,6 +1677,12 @@ struct constant_ln_two<boost::multiprecision::number<boost::multiprecision::mpfr } return result; } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_log2(result.backend().data(), GMP_RNDN); + return result; + } }; template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> struct constant_euler<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > @@ -1603,6 +1701,12 @@ struct constant_euler<boost::multiprecision::number<boost::multiprecision::mpfr_ } return result; } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_euler(result.backend().data(), GMP_RNDN); + return result; + } }; template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> struct constant_catalan<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > @@ -1621,11 +1725,144 @@ struct constant_catalan<boost::multiprecision::number<boost::multiprecision::mpf } return result; } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_catalan(result.backend().data(), GMP_RNDN); + return result; + } +}; + +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +struct constant_pi<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> > +{ + typedef boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> result_type; + template<int N> + static inline const result_type& get(const mpl::int_<N>&) + { + detail::mpfr_constant_initializer<constant_pi<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> >, N>::force_instantiate(); + static result_type result; + static bool has_init = false; + if(!has_init) + { + mpfr_const_pi(result.backend().value().data(), GMP_RNDN); + has_init = true; + } + return result; + } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_pi(result.backend().value().data(), GMP_RNDN); + return result; + } +}; +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +struct constant_ln_two<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> > +{ + typedef boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> result_type; + template<int N> + static inline const result_type& get(const mpl::int_<N>&) + { + detail::mpfr_constant_initializer<constant_ln_two<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> >, N>::force_instantiate(); + static result_type result; + static bool init = false; + if(!init) + { + mpfr_const_log2(result.backend().value().data(), GMP_RNDN); + init = true; + } + return result; + } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_log2(result.backend().value().data(), GMP_RNDN); + return result; + } +}; +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +struct constant_euler<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> > +{ + typedef boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> result_type; + template<int N> + static inline const result_type& get(const mpl::int_<N>&) + { + detail::mpfr_constant_initializer<constant_euler<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> >, N>::force_instantiate(); + static result_type result; + static bool init = false; + if(!init) + { + mpfr_const_euler(result.backend().value().data(), GMP_RNDN); + init = true; + } + return result; + } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_euler(result.backend().value().data(), GMP_RNDN); + return result; + } +}; +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +struct constant_catalan<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> > +{ + typedef boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> result_type; + template<int N> + static inline const result_type& get(const mpl::int_<N>&) + { + detail::mpfr_constant_initializer<constant_catalan<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> >, N>::force_instantiate(); + static result_type result; + static bool init = false; + if(!init) + { + mpfr_const_catalan(result.backend().value().data(), GMP_RNDN); + init = true; + } + return result; + } + static inline const result_type get(const mpl::int_<0>&) + { + result_type result; + mpfr_const_catalan(result.backend().value().data(), GMP_RNDN); + return result; + } }; }} // namespaces -}} // namespaces +} // namespace multiprecision + +namespace math{ + +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) +{ + return (arg.backend().data()[0]._mpfr_sign < 0) ? 1 : 0; +} + +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& a, const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& b) +{ + return (boost::math::signbit)(a) != (boost::math::signbit)(b) ? boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>(-a) : a; +} + +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates>& arg) +{ + return (arg.backend().value().data()[0]._mpfr_sign < 0) ? 1 : 0; +} + +template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates> +inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates>& a, const boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates>& b) +{ + return (boost::math::signbit)(a) != (boost::math::signbit)(b) ? boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType> >, ExpressionTemplates>(-a) : a; +} + +} // namespace math + +} // namespace boost namespace std{ diff --git a/boost/multiprecision/number.hpp b/boost/multiprecision/number.hpp index fca63661e3..15af7ef846 100644 --- a/boost/multiprecision/number.hpp +++ b/boost/multiprecision/number.hpp @@ -632,7 +632,9 @@ public: { return !is_zero(); } - explicit operator void()const {} +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_MP_FORCEINLINE explicit operator void()const {} +#endif # endif #else typedef bool (self_type::*unmentionable_type)()const; @@ -759,7 +761,12 @@ private: bool bl = contains_self(e.left()); bool br = contains_self(e.right()); - if(bl && is_self(e.left())) + if(bl && br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else if(bl && is_self(e.left())) { // Ignore the left node, it's *this, just add the right: do_add(e.right(), typename right_type::tag_type()); @@ -769,11 +776,6 @@ private: // Ignore the right node, it's *this, just add the left: do_add(e.left(), typename left_type::tag_type()); } - else if(bl && br) - { - self_type temp(e); - temp.m_backend.swap(this->m_backend); - } else if(!br && (bl || (left_depth >= right_depth))) { // br is always false, but if bl is true we must take the this branch: do_assign(e.left(), typename left_type::tag_type()); @@ -797,7 +799,12 @@ private: bool bl = contains_self(e.left()); bool br = contains_self(e.right()); - if(bl && is_self(e.left())) + if(bl && br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else if(bl && is_self(e.left())) { // Ignore the left node, it's *this, just subtract the right: do_subtract(e.right(), typename right_type::tag_type()); @@ -808,11 +815,6 @@ private: do_subtract(e.left(), typename left_type::tag_type()); m_backend.negate(); } - else if(bl && br) - { - self_type temp(e); - temp.m_backend.swap(this->m_backend); - } else if(!br && (bl || (left_depth >= right_depth))) { // br is always false, but if bl is true we must take the this branch: do_assign(e.left(), typename left_type::tag_type()); @@ -837,7 +839,12 @@ private: bool bl = contains_self(e.left()); bool br = contains_self(e.right()); - if(bl && is_self(e.left())) + if(bl && br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else if(bl && is_self(e.left())) { // Ignore the left node, it's *this, just add the right: do_multiplies(e.right(), typename right_type::tag_type()); @@ -847,11 +854,6 @@ private: // Ignore the right node, it's *this, just add the left: do_multiplies(e.left(), typename left_type::tag_type()); } - else if(bl && br) - { - self_type temp(e); - temp.m_backend.swap(this->m_backend); - } else if(!br && (bl || (left_depth >= right_depth))) { // br is always false, but if bl is true we must take the this branch: do_assign(e.left(), typename left_type::tag_type()); @@ -1793,6 +1795,14 @@ BOOST_MP_FORCEINLINE void swap(number<Backend, ExpressionTemplates>& a, number<B { a.swap(b); } +// +// Boost.Hash support, just call hash_value for the backend, which may or may not be supported: +// +template <class Backend, expression_template_option ExpressionTemplates> +inline std::size_t hash_value(const number<Backend, ExpressionTemplates>& val) +{ + return hash_value(val.backend()); +} } // namespace multiprecision @@ -1945,6 +1955,22 @@ struct component_type<boost::rational<I> > } // namespaces +#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL + +#include <functional> + +namespace std { + + template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates> + struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> > + { + std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val)const { return hash_value(val); } + }; + +} + +#endif + #include <boost/multiprecision/detail/ublas_interop.hpp> #endif diff --git a/boost/multiprecision/rational_adaptor.hpp b/boost/multiprecision/rational_adaptor.hpp index e3cec0e482..334238c92f 100644 --- a/boost/multiprecision/rational_adaptor.hpp +++ b/boost/multiprecision/rational_adaptor.hpp @@ -10,6 +10,7 @@ #include <iomanip> #include <sstream> #include <boost/cstdint.hpp> +#include <boost/functional/hash_fwd.hpp> #include <boost/multiprecision/number.hpp> #ifdef BOOST_MSVC # pragma warning(push) @@ -277,6 +278,15 @@ inline void assign_components(rational_adaptor<IntBackend>& result, const V& v1, result.data().assign(v1, v2); } +template <class IntBackend> +inline std::size_t hash_value(const rational_adaptor<IntBackend>& val) +{ + std::size_t result = hash_value(val.data().numerator()); + boost::hash_combine(result, val.data().denominator()); + return result; +} + + } // namespace backends template<class IntBackend> diff --git a/boost/multiprecision/tommath.hpp b/boost/multiprecision/tommath.hpp index 3d576051ae..38a112fe9f 100644 --- a/boost/multiprecision/tommath.hpp +++ b/boost/multiprecision/tommath.hpp @@ -12,6 +12,7 @@ #include <boost/math/special_functions/fpclassify.hpp> #include <boost/cstdint.hpp> #include <boost/scoped_array.hpp> +#include <boost/functional/hash_fwd.hpp> #include <tommath.h> #include <cmath> #include <limits> @@ -651,6 +652,16 @@ inline typename enable_if<is_signed<Integer>, Integer>::type eval_integer_modulu return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val)); } +inline std::size_t hash_value(const tommath_int& val) +{ + std::size_t result = 0; + std::size_t len = val.data().used; + for(std::size_t i = 0; i < len; ++i) + boost::hash_combine(result, val.data().dp[i]); + boost::hash_combine(result, val.data().sign); + return result; +} + } // namespace backends using boost::multiprecision::backends::tommath_int; diff --git a/boost/multiprecision/traits/explicit_conversion.hpp b/boost/multiprecision/traits/explicit_conversion.hpp index b4cd8215e0..0a14f03442 100644 --- a/boost/multiprecision/traits/explicit_conversion.hpp +++ b/boost/multiprecision/traits/explicit_conversion.hpp @@ -11,69 +11,79 @@ #include <boost/utility/declval.hpp> -namespace boost{ namespace multiprecision{ namespace detail{ +namespace boost { + namespace multiprecision { + namespace detail { -template <int N> -struct dummy_size{}; + template <int N> + struct dummy_size {}; -template<typename S, typename T> -struct has_generic_interconversion -{ - typedef typename mpl::if_c< - is_number<S>::value && is_number<T>::value, - typename mpl::if_c< - number_category<S>::value == number_kind_integer, - typename mpl::if_c< - number_category<T>::value == number_kind_integer - || number_category<T>::value == number_kind_floating_point - || number_category<T>::value == number_kind_rational - || number_category<T>::value == number_kind_fixed_point, - mpl::true_, - mpl::false_ - >::type, - typename mpl::if_c< - number_category<S>::value == number_kind_rational, - typename mpl::if_c< + template<typename S, typename T> + struct has_generic_interconversion + { + typedef typename mpl::if_c < + is_number<S>::value && is_number<T>::value, + typename mpl::if_c < + number_category<S>::value == number_kind_integer, + typename mpl::if_c< + number_category<T>::value == number_kind_integer + || number_category<T>::value == number_kind_floating_point + || number_category<T>::value == number_kind_rational + || number_category<T>::value == number_kind_fixed_point, + mpl::true_, + mpl::false_ + >::type, + typename mpl::if_c< + number_category<S>::value == number_kind_rational, + typename mpl::if_c< number_category<T>::value == number_kind_rational || number_category<T>::value == number_kind_rational, mpl::true_, mpl::false_ - >::type, - typename mpl::if_c< + >::type, + typename mpl::if_c< number_category<T>::value == number_kind_floating_point, mpl::true_, mpl::false_ - >::type - >::type - >::type, - mpl::false_ - >::type type; -}; + >::type + >::type + > ::type, + mpl::false_ + > ::type type; + }; -template<typename S, typename T> -struct is_explicitly_convertible_imp -{ + template<typename S, typename T> + struct is_explicitly_convertible_imp + { #ifndef BOOST_NO_SFINAE_EXPR - template<typename S1, typename T1> - static type_traits::yes_type selector(dummy_size<sizeof(static_cast<T1>(declval<S1>()))>*); + template<typename S1, typename T1> + static type_traits::yes_type selector(dummy_size<sizeof(static_cast<T1>(declval<S1>()))>*); - template<typename S1, typename T1> - static type_traits::no_type selector(...); + template<typename S1, typename T1> + static type_traits::no_type selector(...); - static const bool value = sizeof(selector<S,T>(0)) == sizeof(type_traits::yes_type); + static const bool value = sizeof(selector<S, T>(0)) == sizeof(type_traits::yes_type); - typedef boost::integral_constant<bool,value> type; + typedef boost::integral_constant<bool, value> type; #else - typedef typename has_generic_interconversion<S, T>::type gen_type; - typedef mpl::bool_<boost::is_convertible<S, T>::value || gen_type::value> type; + typedef typename has_generic_interconversion<S, T>::type gen_type; + typedef mpl::bool_<boost::is_convertible<S, T>::value || gen_type::value> type; #endif -}; + }; template<typename From, typename To> struct is_explicitly_convertible : public is_explicitly_convertible_imp<From, To>::type { }; +#ifdef BOOST_NO_SFINAE_EXPR +template<class Backend1, expression_template_option ExpressionTemplates1, class Backend2, expression_template_option ExpressionTemplates2> +struct is_explicitly_convertible<number<Backend1, ExpressionTemplates1>, number<Backend2, ExpressionTemplates2> > + : public is_explicitly_convertible<Backend1, Backend2> +{ +}; +#endif + }}} // namespaces #endif |