diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:22:41 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:22:41 +0900 |
commit | 3c1df2168531ad5580076ae08d529054689aeedd (patch) | |
tree | 941aff6f86393eecacddfec252a8508c7e8351c9 /boost/multiprecision | |
parent | d6a306e745acfee00e81ccaf3324a2a03516db41 (diff) | |
download | boost-3c1df2168531ad5580076ae08d529054689aeedd.tar.gz boost-3c1df2168531ad5580076ae08d529054689aeedd.tar.bz2 boost-3c1df2168531ad5580076ae08d529054689aeedd.zip |
Imported Upstream version 1.70.0upstream/1.70.0
Diffstat (limited to 'boost/multiprecision')
-rw-r--r-- | boost/multiprecision/cpp_bin_float.hpp | 65 | ||||
-rw-r--r-- | boost/multiprecision/cpp_bin_float/transcendental.hpp | 8 | ||||
-rw-r--r-- | boost/multiprecision/cpp_dec_float.hpp | 10 | ||||
-rw-r--r-- | boost/multiprecision/cpp_int.hpp | 2 | ||||
-rw-r--r-- | boost/multiprecision/cpp_int/serialize.hpp | 28 | ||||
-rw-r--r-- | boost/multiprecision/debug_adaptor.hpp | 2 | ||||
-rw-r--r-- | boost/multiprecision/detail/functions/pow.hpp | 1 | ||||
-rw-r--r-- | boost/multiprecision/detail/generic_interconvert.hpp | 10 | ||||
-rw-r--r-- | boost/multiprecision/detail/number_base.hpp | 19 | ||||
-rw-r--r-- | boost/multiprecision/detail/precision.hpp | 75 | ||||
-rw-r--r-- | boost/multiprecision/float128.hpp | 4 | ||||
-rw-r--r-- | boost/multiprecision/gmp.hpp | 11 | ||||
-rw-r--r-- | boost/multiprecision/logged_adaptor.hpp | 2 | ||||
-rw-r--r-- | boost/multiprecision/mpfr.hpp | 246 | ||||
-rw-r--r-- | boost/multiprecision/number.hpp | 134 | ||||
-rw-r--r-- | boost/multiprecision/rational_adaptor.hpp | 8 | ||||
-rw-r--r-- | boost/multiprecision/traits/explicit_conversion.hpp | 45 | ||||
-rw-r--r-- | boost/multiprecision/traits/is_byte_container.hpp | 9 |
18 files changed, 514 insertions, 165 deletions
diff --git a/boost/multiprecision/cpp_bin_float.hpp b/boost/multiprecision/cpp_bin_float.hpp index 03daf96fe4..3d8369500d 100644 --- a/boost/multiprecision/cpp_bin_float.hpp +++ b/boost/multiprecision/cpp_bin_float.hpp @@ -45,6 +45,43 @@ inline typename enable_if_c<is_unsigned<U>::value, bool>::type is_negative(U) { template <class S> inline typename disable_if_c<is_unsigned<S>::value, bool>::type is_negative(S s) { return s < 0; } +template <class Float, int, bool = number_category<Float>::value == number_kind_floating_point> +struct is_cpp_bin_float_implicitly_constructible_from_type +{ + static const bool value = false; +}; + +template <class Float, int bit_count> +struct is_cpp_bin_float_implicitly_constructible_from_type<Float, bit_count, true> +{ + static const bool value = (std::numeric_limits<Float>::digits <= (int)bit_count) + && (std::numeric_limits<Float>::radix == 2) + && std::numeric_limits<Float>::is_specialized +#ifdef BOOST_HAS_FLOAT128 + && !boost::is_same<Float, __float128>::value +#endif + && (is_floating_point<Float>::value || is_number<Float>::value) + ; +}; + +template <class Float, int, bool = number_category<Float>::value == number_kind_floating_point> +struct is_cpp_bin_float_explicitly_constructible_from_type +{ + static const bool value = false; +}; + +template <class Float, int bit_count> +struct is_cpp_bin_float_explicitly_constructible_from_type<Float, bit_count, true> +{ + static const bool value = (std::numeric_limits<Float>::digits > (int)bit_count) + && (std::numeric_limits<Float>::radix == 2) + && std::numeric_limits<Float>::is_specialized +#ifdef BOOST_HAS_FLOAT128 + && !boost::is_same<Float, __float128>::value +#endif + ; +}; + } template <unsigned Digits, digit_base_type DigitBase = digit_base_10, class Allocator = void, class Exponent = int, Exponent MinExponent = 0, Exponent MaxExponent = 0> @@ -99,15 +136,7 @@ public: } template <class Float> cpp_bin_float(const Float& f, - typename boost::enable_if_c< - (number_category<Float>::value == number_kind_floating_point) - && (std::numeric_limits<Float>::digits <= (int)bit_count) - && (std::numeric_limits<Float>::radix == 2) - && (std::numeric_limits<Float>::is_specialized) -#ifdef BOOST_HAS_FLOAT128 - && !boost::is_same<Float, __float128>::value -#endif - >::type const* = 0) + typename boost::enable_if_c<detail::is_cpp_bin_float_implicitly_constructible_from_type<Float, bit_count>::value>::type const* = 0) : m_data(), m_exponent(0), m_sign(false) { this->assign_float(f); @@ -115,15 +144,7 @@ public: template <class Float> explicit cpp_bin_float(const Float& f, - typename boost::enable_if_c< - (number_category<Float>::value == number_kind_floating_point) - && (std::numeric_limits<Float>::digits > (int)bit_count) - && (std::numeric_limits<Float>::radix == 2) - && (std::numeric_limits<Float>::is_specialized) -#ifdef BOOST_HAS_FLOAT128 - && !boost::is_same<Float, __float128>::value -#endif ->::type const* = 0) + typename boost::enable_if_c<detail::is_cpp_bin_float_explicitly_constructible_from_type<Float, bit_count>::value>::type const* = 0) : m_data(), m_exponent(0), m_sign(false) { this->assign_float(f); @@ -330,7 +351,7 @@ public: typename boost::enable_if_c< (number_category<Float>::value == number_kind_floating_point) && !boost::is_floating_point<Float>::value - /*&& (std::numeric_limits<number<Float> >::radix == 2)*/, + && is_number<Float>::value, cpp_bin_float&>::type assign_float(Float f) { BOOST_MATH_STD_USING @@ -507,9 +528,9 @@ public: template<class Archive> void serialize(Archive & ar, const unsigned int /*version*/) { - ar & m_data; - ar & m_exponent; - ar & m_sign; + ar & boost::serialization::make_nvp("data", m_data); + ar & boost::serialization::make_nvp("exponent", m_exponent); + ar & boost::serialization::make_nvp("sign", m_sign); } }; diff --git a/boost/multiprecision/cpp_bin_float/transcendental.hpp b/boost/multiprecision/cpp_bin_float/transcendental.hpp index 5c969716a5..5c1842dc7e 100644 --- a/boost/multiprecision/cpp_bin_float/transcendental.hpp +++ b/boost/multiprecision/cpp_bin_float/transcendental.hpp @@ -64,6 +64,7 @@ void eval_exp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> using default_ops::eval_subtract; using default_ops::eval_add; using default_ops::eval_convert_to; + using default_ops::eval_increment; int type = eval_fpclassify(arg); bool isneg = eval_get_sign(arg) < 0; @@ -104,6 +105,13 @@ void eval_exp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> eval_multiply(t, n, default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >()); eval_subtract(t, arg); t.negate(); + if (t.compare(default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >()) > 0) + { + // There are some rare cases where the multiply rounds down leaving a remainder > ln2 + // See https://github.com/boostorg/multiprecision/issues/120 + eval_increment(n); + t = limb_type(0); + } if(eval_get_sign(t) < 0) { // There are some very rare cases where arg/ln2 is an integer, and the subsequent multiply diff --git a/boost/multiprecision/cpp_dec_float.hpp b/boost/multiprecision/cpp_dec_float.hpp index 9149029b8f..c09ddee5e3 100644 --- a/boost/multiprecision/cpp_dec_float.hpp +++ b/boost/multiprecision/cpp_dec_float.hpp @@ -608,11 +608,11 @@ public: void serialize(Archive & ar, const unsigned int /*version*/) { for(unsigned i = 0; i < data.size(); ++i) - ar & data[i]; - ar & exp; - ar & neg; - ar & fpclass; - ar & prec_elem; + ar & boost::serialization::make_nvp("digit", data[i]); + ar & boost::serialization::make_nvp("exponent", exp); + ar & boost::serialization::make_nvp("sign", neg); + ar & boost::serialization::make_nvp("class-type", fpclass); + ar & boost::serialization::make_nvp("precision", prec_elem); } private: diff --git a/boost/multiprecision/cpp_int.hpp b/boost/multiprecision/cpp_int.hpp index d81831b8a6..6af30fd9ec 100644 --- a/boost/multiprecision/cpp_int.hpp +++ b/boost/multiprecision/cpp_int.hpp @@ -830,7 +830,7 @@ public: m_sign = false; } } - BOOST_MP_FORCEINLINE void resize(unsigned new_size, unsigned min_size) + BOOST_MP_FORCEINLINE void resize(unsigned /* new_size */, unsigned min_size) { detail::verify_new_size(2, min_size, checked_type()); } diff --git a/boost/multiprecision/cpp_int/serialize.hpp b/boost/multiprecision/cpp_int/serialize.hpp index 042a9f89f7..ad0031b9de 100644 --- a/boost/multiprecision/cpp_int/serialize.hpp +++ b/boost/multiprecision/cpp_int/serialize.hpp @@ -44,11 +44,12 @@ void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, // Non-trivial. // Non binary. + using boost::serialization::make_nvp; bool s; - ar & s; + ar & make_nvp("sign", s); std::size_t limb_count; std::size_t byte_count; - ar & byte_count; + ar & make_nvp("byte-count", byte_count); limb_count = byte_count / sizeof(limb_type) + ((byte_count % sizeof(limb_type)) ? 1 : 0); val.resize(limb_count, limb_count); limb_type* pl = val.limbs(); @@ -58,7 +59,7 @@ void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, for(std::size_t j = 0; (j < sizeof(limb_type)) && byte_count; ++j) { unsigned char byte; - ar & byte; + ar & make_nvp("byte", byte); pl[i] |= static_cast<limb_type>(byte) << (j * CHAR_BIT); --byte_count; } @@ -74,12 +75,13 @@ void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, // Non-trivial. // Non binary. + using boost::serialization::make_nvp; bool s = val.sign(); - ar & s; + ar & make_nvp("sign", s); limb_type* pl = val.limbs(); std::size_t limb_count = val.size(); std::size_t byte_count = limb_count * sizeof(limb_type); - ar & byte_count; + ar & make_nvp("byte-count", byte_count); for(std::size_t i = 0; i < limb_count; ++i) { @@ -87,7 +89,7 @@ void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, for(std::size_t j = 0; j < sizeof(limb_type); ++j) { unsigned char byte = static_cast<unsigned char>((l >> (j * CHAR_BIT)) & ((1u << CHAR_BIT) - 1)); - ar & byte; + ar & make_nvp("byte", byte); } } } @@ -97,15 +99,16 @@ void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::true_ const&, // Load. // Trivial. // Non binary. + using boost::serialization::make_nvp; bool s; typename Int::local_limb_type l = 0; - ar & s; + ar & make_nvp("sign", s); std::size_t byte_count; - ar & byte_count; + ar & make_nvp("byte-count", byte_count); for(std::size_t i = 0; i < byte_count; ++i) { unsigned char b; - ar & b; + ar & make_nvp("byte", b); l |= static_cast<typename Int::local_limb_type>(b) << (i * CHAR_BIT); } *val.limbs() = l; @@ -118,15 +121,16 @@ void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::true_ const&, m // Store. // Trivial. // Non binary. + using boost::serialization::make_nvp; bool s = val.sign(); typename Int::local_limb_type l = *val.limbs(); - ar & s; + ar & make_nvp("sign", s); std::size_t limb_count = sizeof(l); - ar & limb_count; + ar & make_nvp("byte-count", limb_count); for(std::size_t i = 0; i < limb_count; ++i) { unsigned char b = static_cast<unsigned char>(static_cast<typename Int::local_limb_type>(l >> (i * CHAR_BIT)) & static_cast<typename Int::local_limb_type>((1u << CHAR_BIT) - 1)); - ar & b; + ar & make_nvp("byte", b); } } template <class Archive, class Int> diff --git a/boost/multiprecision/debug_adaptor.hpp b/boost/multiprecision/debug_adaptor.hpp index cb61c5b59b..505bea1df1 100644 --- a/boost/multiprecision/debug_adaptor.hpp +++ b/boost/multiprecision/debug_adaptor.hpp @@ -120,7 +120,7 @@ public: template <class Archive> void serialize(Archive& ar, const unsigned int /*version*/) { - ar & m_value; + ar & boost::serialization::make_nvp("value", m_value); typedef typename Archive::is_loading tag; if(tag::value) update_view(); diff --git a/boost/multiprecision/detail/functions/pow.hpp b/boost/multiprecision/detail/functions/pow.hpp index 1abc705a9a..8fd6f1f953 100644 --- a/boost/multiprecision/detail/functions/pow.hpp +++ b/boost/multiprecision/detail/functions/pow.hpp @@ -537,6 +537,7 @@ inline void eval_pow(T& result, const T& x, const T& a) { // fallthrough.. } + BOOST_FALLTHROUGH; } default: if(eval_signbit(a)) diff --git a/boost/multiprecision/detail/generic_interconvert.hpp b/boost/multiprecision/detail/generic_interconvert.hpp index 730f45cc3a..783ddca6e2 100644 --- a/boost/multiprecision/detail/generic_interconvert.hpp +++ b/boost/multiprecision/detail/generic_interconvert.hpp @@ -481,9 +481,15 @@ void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<2> number<To> num(0u); number<From> val(from); val = frexp(val, &e); + bool neg = false; + if (val.sign() < 0) + { + val.backend().negate(); + neg = true; + } while(e > 0) { - int s = (std::min)(e, shift); + exponent_type s = (std::min)(e, shift); val = ldexp(val, s); e -= s; boost::long_long_type ll = boost::math::lltrunc(val); @@ -492,6 +498,8 @@ void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<2> num += ll; } to = num.backend(); + if (neg) + to.negate(); } template <class To, class From, int Radix> diff --git a/boost/multiprecision/detail/number_base.hpp b/boost/multiprecision/detail/number_base.hpp index 9665a825a0..cb29515706 100644 --- a/boost/multiprecision/detail/number_base.hpp +++ b/boost/multiprecision/detail/number_base.hpp @@ -53,6 +53,15 @@ #endif namespace boost{ + + namespace serialization + { + template <class T> + struct nvp; + template<class T> + const nvp< T > make_nvp(const char * name, T & t); + } + namespace multiprecision{ enum expression_template_option @@ -1540,8 +1549,12 @@ enum number_category_type number_kind_complex = 4 }; +template <class Num, bool, bool> +struct number_category_base : public mpl::int_<number_kind_unknown> {}; +template <class Num> +struct number_category_base<Num, true, false> : public mpl::int_<std::numeric_limits<Num>::is_integer ? number_kind_integer : (std::numeric_limits<Num>::max_exponent ? number_kind_floating_point : number_kind_unknown)> {}; template <class Num> -struct number_category : public mpl::int_<std::numeric_limits<Num>::is_integer ? number_kind_integer : (std::numeric_limits<Num>::max_exponent ? number_kind_floating_point : number_kind_unknown)> {}; +struct number_category : public number_category_base<Num, boost::is_class<Num>::value || boost::is_arithmetic<Num>::value, boost::is_abstract<Num>::value> {}; template <class Backend, expression_template_option ExpressionTemplates> struct number_category<number<Backend, ExpressionTemplates> > : public number_category<Backend>{}; template <class tag, class A1, class A2, class A3, class A4> @@ -1551,9 +1564,9 @@ struct number_category<detail::expression<tag, A1, A2, A3, A4> > : public number // #ifdef BOOST_HAS_INT128 template <> -struct number_category<__int128> : public mpl::int_<number_kind_integer> {}; +struct number_category<boost::int128_type> : public mpl::int_<number_kind_integer> {}; template <> -struct number_category<unsigned __int128> : public mpl::int_<number_kind_integer> {}; +struct number_category<boost::uint128_type> : public mpl::int_<number_kind_integer> {}; #endif #ifdef BOOST_HAS_FLOAT128 template <> diff --git a/boost/multiprecision/detail/precision.hpp b/boost/multiprecision/detail/precision.hpp index f5963abf69..c5d373a33d 100644 --- a/boost/multiprecision/detail/precision.hpp +++ b/boost/multiprecision/detail/precision.hpp @@ -8,18 +8,42 @@ #include <boost/multiprecision/traits/is_variable_precision.hpp> #include <boost/multiprecision/detail/number_base.hpp> +#include <boost/multiprecision/detail/digits.hpp> namespace boost{ namespace multiprecision{ namespace detail{ template <class B, boost::multiprecision::expression_template_option ET> + inline BOOST_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>&, const mpl::false_&) + { + return std::numeric_limits<boost::multiprecision::number<B, ET> >::digits10; + } + template <class B, boost::multiprecision::expression_template_option ET> + inline unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>& val, const mpl::true_&) + { + // + // We have an arbitrary precision integer, take it's "precision" as the + // location of the most-significant-bit less the location of the + // least-significant-bit, ie the number of bits required to represent the + // the value assuming we will have an exponent to shift things by: + // + return val.is_zero() ? 1 : digits2_2_10(msb(abs(val)) - lsb(abs(val)) + 1); + } + + + template <class B, boost::multiprecision::expression_template_option ET> inline unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& n, const mpl::true_&) { return n.precision(); } template <class B, boost::multiprecision::expression_template_option ET> - inline BOOST_CONSTEXPR unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>&, const mpl::false_&) + inline BOOST_CONSTEXPR unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& val, const mpl::false_&) { - return std::numeric_limits<boost::multiprecision::number<B, ET> >::digits10; + return current_precision_of_last_chance_imp(val, + mpl::bool_< + std::numeric_limits<boost::multiprecision::number<B, ET> >::is_specialized + && std::numeric_limits<boost::multiprecision::number<B, ET> >::is_integer + && std::numeric_limits<boost::multiprecision::number<B, ET> >::is_exact + && !std::numeric_limits<boost::multiprecision::number<B, ET> >::is_modulo>()); } template <class Terminal> @@ -64,47 +88,74 @@ namespace boost{ namespace multiprecision{ namespace detail{ return (std::max)((std::max)(current_precision_of(expr.left_ref()), current_precision_of(expr.right_ref())), current_precision_of(expr.middle_ref())); } +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4130) +#endif + template <class R, bool = boost::multiprecision::detail::is_variable_precision<R>::value> struct scoped_default_precision { template <class T> - scoped_default_precision(const T&) {} + BOOST_CONSTEXPR scoped_default_precision(const T&) {} template <class T, class U> - scoped_default_precision(const T&, const U&) {} + BOOST_CONSTEXPR scoped_default_precision(const T&, const U&) {} template <class T, class U, class V> - scoped_default_precision(const T&, const U&, const V&) {} + BOOST_CONSTEXPR scoped_default_precision(const T&, const U&, const V&) {} + + // + // This function is never called: in C++17 it won't be compiled either: + // + unsigned precision()const + { + BOOST_ASSERT("This function should never be called!!" == 0); + return 0; + } }; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + template <class R> struct scoped_default_precision<R, true> { template <class T> - scoped_default_precision(const T& a) + BOOST_CXX14_CONSTEXPR scoped_default_precision(const T& a) { init(current_precision_of(a)); } template <class T, class U> - scoped_default_precision(const T& a, const U& b) + BOOST_CXX14_CONSTEXPR scoped_default_precision(const T& a, const U& b) { init((std::max)(current_precision_of(a), current_precision_of(b))); } template <class T, class U, class V> - scoped_default_precision(const T& a, const U& b, const V& c) + BOOST_CXX14_CONSTEXPR scoped_default_precision(const T& a, const U& b, const V& c) { init((std::max)((std::max)(current_precision_of(a), current_precision_of(b)), current_precision_of(c))); } ~scoped_default_precision() { - R::default_precision(m_prec); + R::default_precision(m_old_prec); + } + BOOST_CXX14_CONSTEXPR unsigned precision()const + { + return m_new_prec; } private: - void init(unsigned p) + BOOST_CXX14_CONSTEXPR void init(unsigned p) { - m_prec = R::default_precision(); + m_old_prec = R::default_precision(); if (p) + { R::default_precision(p); + m_new_prec = p; + } + else + m_new_prec = m_old_prec; } - unsigned m_prec; + unsigned m_old_prec, m_new_prec; }; template <class T> diff --git a/boost/multiprecision/float128.hpp b/boost/multiprecision/float128.hpp index b4b16c5974..dd216c66db 100644 --- a/boost/multiprecision/float128.hpp +++ b/boost/multiprecision/float128.hpp @@ -668,7 +668,7 @@ void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend // saving // non-binary std::string s(val.str(0, std::ios_base::scientific)); - ar & s; + ar & boost::serialization::make_nvp("value", s); } template <class Archive> void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::true_&, const mpl::false_&) @@ -676,7 +676,7 @@ void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend // loading // non-binary std::string s; - ar & s; + ar & boost::serialization::make_nvp("value", s); val = s.c_str(); } diff --git a/boost/multiprecision/gmp.hpp b/boost/multiprecision/gmp.hpp index d08e7080e5..0f5800ed3d 100644 --- a/boost/multiprecision/gmp.hpp +++ b/boost/multiprecision/gmp.hpp @@ -342,8 +342,19 @@ struct gmp_float_imp } else if(digits > 0) { + mp_exp_t old_e = e; ps = mpf_get_str (0, &e, 10, static_cast<std::size_t>(digits), m_data); --e; // To match with what our formatter expects. + if (old_e > e) + { + // in some cases, when we ask for more digits of precision, it will + // change the number of digits to the left of the decimal, if that + // happens, account for it here. + // example: cout << fixed << setprecision(3) << mpf_float_50("99.9809") + digits -= old_e - e; + ps = mpf_get_str (0, &e, 10, static_cast<std::size_t>(digits), m_data); + --e; // To match with what our formatter expects. + } } else { diff --git a/boost/multiprecision/logged_adaptor.hpp b/boost/multiprecision/logged_adaptor.hpp index a08ca43c28..596d13ed74 100644 --- a/boost/multiprecision/logged_adaptor.hpp +++ b/boost/multiprecision/logged_adaptor.hpp @@ -157,7 +157,7 @@ public: void serialize(Archive& ar, const unsigned int /*version*/) { log_prefix_event(m_value, "serialize"); - ar & m_value; + ar & boost::serialization::make_nvp("value", m_value); log_postfix_event(m_value, "serialize"); } static unsigned default_precision() BOOST_NOEXCEPT diff --git a/boost/multiprecision/mpfr.hpp b/boost/multiprecision/mpfr.hpp index 36aee83d80..112a275a46 100644 --- a/boost/multiprecision/mpfr.hpp +++ b/boost/multiprecision/mpfr.hpp @@ -320,8 +320,19 @@ struct mpfr_float_imp<digits10, allocate_dynamic> } else if(digits > 0) { + mp_exp_t old_e = e; ps = mpfr_get_str (0, &e, 10, static_cast<std::size_t>(digits), m_data, GMP_RNDN); --e; // To match with what our formatter expects. + if (old_e > e) + { + // in some cases, when we ask for more digits of precision, it will + // change the number of digits to the left of the decimal, if that + // happens, account for it here. + // example: cout << fixed << setprecision(3) << mpf_float_50("99.9809") + digits -= old_e - e; + ps = mpfr_get_str(0, &e, 10, static_cast<std::size_t>(digits), m_data, GMP_RNDN); + --e; // To match with what our formatter expects. + } } else { @@ -2058,6 +2069,241 @@ namespace multiprecision { } +namespace math { + // + // Overloaded special functions which call native mpfr routines: + // + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_asinh(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("asinh<%1%>(%1%)", 0, Policy()); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("asinh<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); + return result; + } + 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> asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return asinh(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_acosh(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("acosh<%1%>(%1%)", 0, Policy()); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("acosh<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); + return result; + } + 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> acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return acosh(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_atanh(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("atanh<%1%>(%1%)", 0, Policy()); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("atanh<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); + return result; + } + 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> atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return atanh(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_cbrt(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("cbrt<%1%>(%1%)", 0, Policy()); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("cbrt<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); + return result; + } + 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> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return cbrt(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_erf(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("erf<%1%>(%1%)", 0, pol); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("erf<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); + return result; + } + 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> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return erf(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_erfc(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("erfc<%1%>(%1%)", 0, pol); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("erfc<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); + return result; + } + 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> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return erfc(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_expm1(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("expm1<%1%>(%1%)", 0, pol); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("expm1<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); + return result; + } + 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> exm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return expm1(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> arg, int* sign, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + if (arg > 0) + { + mpfr_lngamma(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (sign) + *sign = 1; + } + else + { + if (floor(arg) == arg) + return policies::raise_pole_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >( + "lgamma<%1%>", "Evaluation of lgamma at a negative integer %1%.", arg, pol); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> t = detail::sinpx(arg); + arg = -arg; + if (t < 0) + { + t = -t; + } + result = log(boost::math::constants::pi<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >()) - lgamma(arg, 0, pol) - log(t); + if (sign) + { + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> phase = 1 - arg; + phase = floor(phase) / 2; + if (floor(phase) == phase) + *sign = -1; + else + *sign = 1; + } + } + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("lgamma<%1%>(%1%)", 0, pol); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("lgamma<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); + return result; + } + 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> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, int* sign) + { + return lgamma(arg, sign, policies::policy<>()); + } + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + return lgamma(arg, 0, pol); + } + 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> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return lgamma(arg, 0, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline typename boost::enable_if_c<boost::math::policies::is_policy<Policy>::value, boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >::type tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_gamma(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("tgamma<%1%>(%1%)", 0, pol); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("tgamma<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); + return result; + } + 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> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return tgamma(arg, policies::policy<>()); + } + + template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy> + inline boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg, const Policy& pol) + { + boost::multiprecision::detail::scoped_default_precision<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> > precision_guard(arg); + + boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> result; + mpfr_log1p(result.backend().data(), arg.backend().data(), GMP_RNDN); + if (mpfr_inf_p(result.backend().data())) + return policies::raise_overflow_error<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> >("log1p<%1%>(%1%)", 0, pol); + if (mpfr_nan_p(result.backend().data())) + return policies::raise_evaluation_error("log1p<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); + return result; + } + 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> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates>& arg) + { + return log1p(arg, policies::policy<>()); + } + + +} + } // namespace boost namespace std{ diff --git a/boost/multiprecision/number.hpp b/boost/multiprecision/number.hpp index 42c6a8fa5d..892996b397 100644 --- a/boost/multiprecision/number.hpp +++ b/boost/multiprecision/number.hpp @@ -224,11 +224,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(e); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(e); + return *this = BOOST_MP_MOVE(t); + } do_assign(e, tag_type()); return *this; } @@ -247,12 +247,12 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t; - t.assign(e); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t; + t.assign(e); + return *this = BOOST_MP_MOVE(t); + } do_assign(e, tag_type()); return *this; } @@ -305,11 +305,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(v) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(v); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(v); + return *this = BOOST_MP_MOVE(t); + } generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>()); return *this; } @@ -317,22 +317,9 @@ public: template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename boost::enable_if_c<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0) { - detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(e); // - // If the current precision of *this differs from that of expression e, then we - // create a temporary (which will have the correct precision thanks to precision_guard) - // and then move the result into *this. In C++17 we add a leading "if constexpr" - // which causes this code to be eliminated in the common case that this type is - // not actually variable precision. Pre C++17 this code should still be mostly - // optimised away, but we can't prevent instantiation of the dead code leading - // to longer build and possibly link times. + // No preicsion guard here, we already have one in operator= // - BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(e); - *this = BOOST_MP_MOVE(t); - } *this = e; } template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> @@ -340,22 +327,9 @@ public: typename boost::enable_if_c<!is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value && boost::multiprecision::detail::is_explicitly_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0) { - detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(e); // - // If the current precision of *this differs from that of expression e, then we - // create a temporary (which will have the correct precision thanks to precision_guard) - // and then move the result into *this. In C++17 we add a leading "if constexpr" - // which causes this code to be eliminated in the common case that this type is - // not actually variable precision. Pre C++17 this code should still be mostly - // optimised away, but we can't prevent instantiation of the dead code leading - // to longer build and possibly link times. + // No precision guard as assign has one already: // - BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(e); - *this = BOOST_MP_MOVE(t); - } assign(e); } @@ -383,11 +357,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(val) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(*this + val); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(*this + val); + return *this = BOOST_MP_MOVE(t); + } do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal()); return *this; } @@ -424,11 +398,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(*this + e); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(*this + e); + return *this = BOOST_MP_MOVE(t); + } // // Fused multiply-add: // @@ -459,11 +433,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(val) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(*this - val); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(*this - val); + return *this = BOOST_MP_MOVE(t); + } do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal()); return *this; } @@ -508,11 +482,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(*this - e); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(*this - e); + return *this = BOOST_MP_MOVE(t); + } // // Fused multiply-subtract: // @@ -535,11 +509,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(*this * e); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(*this * e); + return *this = BOOST_MP_MOVE(t); + } do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal()); return *this; } @@ -585,11 +559,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(*this % e); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(*this % e); + return *this = BOOST_MP_MOVE(t); + } do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal()); return *this; } @@ -689,11 +663,11 @@ public: // to longer build and possibly link times. // BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number) - if (boost::multiprecision::detail::current_precision_of(e) != boost::multiprecision::detail::current_precision_of(*this)) - { - number t(*this / e); - return *this = BOOST_MP_MOVE(t); - } + if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this)) + { + number t(*this / e); + return *this = BOOST_MP_MOVE(t); + } do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal()); return *this; } @@ -856,7 +830,7 @@ public: template<class Archive> void serialize(Archive & ar, const unsigned int /*version*/) { - ar & m_backend; + ar & boost::serialization::make_nvp("backend", m_backend); } private: template <class T> diff --git a/boost/multiprecision/rational_adaptor.hpp b/boost/multiprecision/rational_adaptor.hpp index b06a157010..860a43bfa8 100644 --- a/boost/multiprecision/rational_adaptor.hpp +++ b/boost/multiprecision/rational_adaptor.hpp @@ -186,16 +186,16 @@ struct rational_adaptor { // Saving integer_type n(m_value.numerator()), d(m_value.denominator()); - ar & n; - ar & d; + ar & boost::serialization::make_nvp("numerator", n); + ar & boost::serialization::make_nvp("denominator", d); } template <class Archive> void serialize(Archive& ar, const mpl::false_&) { // Loading integer_type n, d; - ar & n; - ar & d; + ar & boost::serialization::make_nvp("numerator", n); + ar & boost::serialization::make_nvp("denominator", d); m_value.assign(n, d); } template <class Archive> diff --git a/boost/multiprecision/traits/explicit_conversion.hpp b/boost/multiprecision/traits/explicit_conversion.hpp index 0a14f03442..9ebec6a93b 100644 --- a/boost/multiprecision/traits/explicit_conversion.hpp +++ b/boost/multiprecision/traits/explicit_conversion.hpp @@ -7,48 +7,51 @@ #ifndef BOOST_MP_EXPLICIT_CONVERTIBLE_HPP #define BOOST_MP_EXPLICIT_CONVERTIBLE_HPP +#include <boost/config.hpp> +#include <boost/type_traits/conditional.hpp> +#include <boost/type_traits/integral_constant.hpp> #include <boost/type_traits/is_convertible.hpp> -#include <boost/utility/declval.hpp> - +#include <boost/type_traits/declval.hpp> +#include <boost/multiprecision/detail/number_base.hpp> // number_category namespace boost { namespace multiprecision { namespace detail { - template <int N> + template <unsigned int N> struct dummy_size {}; template<typename S, typename T> struct has_generic_interconversion { - typedef typename mpl::if_c < + typedef typename boost::conditional < is_number<S>::value && is_number<T>::value, - typename mpl::if_c < + typename boost::conditional < number_category<S>::value == number_kind_integer, - typename mpl::if_c< + typename boost::conditional< 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_ + boost::true_type, + boost::false_type >::type, - typename mpl::if_c< + typename boost::conditional< number_category<S>::value == number_kind_rational, - typename mpl::if_c< + typename boost::conditional< number_category<T>::value == number_kind_rational || number_category<T>::value == number_kind_rational, - mpl::true_, - mpl::false_ + boost::true_type, + boost::false_type >::type, - typename mpl::if_c< + typename boost::conditional< number_category<T>::value == number_kind_floating_point, - mpl::true_, - mpl::false_ + boost::true_type, + boost::false_type >::type >::type > ::type, - mpl::false_ + boost::false_type > ::type type; }; @@ -57,7 +60,13 @@ namespace boost { { #ifndef BOOST_NO_SFINAE_EXPR template<typename S1, typename T1> - static type_traits::yes_type selector(dummy_size<sizeof(static_cast<T1>(declval<S1>()))>*); + static type_traits::yes_type selector(dummy_size<sizeof(new T1(boost::declval< +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + S1 +#else + S1 const& +#endif + >()))>*); template<typename S1, typename T1> static type_traits::no_type selector(...); @@ -67,7 +76,7 @@ namespace boost { 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 boost::integral_constant<bool, boost::is_convertible<S, T>::value || gen_type::value> type; #endif }; diff --git a/boost/multiprecision/traits/is_byte_container.hpp b/boost/multiprecision/traits/is_byte_container.hpp index d97428f0f2..64999800a7 100644 --- a/boost/multiprecision/traits/is_byte_container.hpp +++ b/boost/multiprecision/traits/is_byte_container.hpp @@ -6,25 +6,28 @@ #ifndef BOOST_IS_BYTE_CONTAINER_HPP #define BOOST_IS_BYTE_CONTAINER_HPP +#include <iterator> #include <boost/mpl/has_xxx.hpp> #include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/remove_cv.hpp> namespace boost{ namespace multiprecision{ namespace detail{ - BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_member_value_type, value_type, false) BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_member_const_iterator, const_iterator, false) template <class C, bool b> struct is_byte_container_imp { - static const bool value = boost::is_integral<typename C::value_type>::value && (sizeof(typename C::value_type) == 1); + // Note: Don't use C::value_type as this is a rather widespread typedef, even for non-range types + typedef typename boost::remove_cv<typename std::iterator_traits<typename C::const_iterator>::value_type>::type container_value_type; + static const bool value = boost::is_integral<container_value_type>::value && (sizeof(container_value_type) == 1); }; template <class C> struct is_byte_container_imp<C, false> : public boost::false_type {}; template <class C> - struct is_byte_container : public is_byte_container_imp<C, has_member_value_type<C>::value && has_member_const_iterator<C>::value> {}; + struct is_byte_container : public is_byte_container_imp<C, has_member_const_iterator<C>::value> {}; }}} // namespaces |