diff --git a/doc/multiprecision.qbk b/doc/multiprecision.qbk index b852b99e..c5ebce6d 100644 --- a/doc/multiprecision.qbk +++ b/doc/multiprecision.qbk @@ -3789,7 +3789,7 @@ whose precision can vary at compile time (such as `mpf_float`). // Over again, but with checking enabled this time: typedef number > checked_cpp_int; typedef rational_adaptor > checked_cpp_rational_backend; - typedef number checked_cpp_rational; + typedef number checked_cpp_rational; // Checked fixed precision unsigned types: typedef number > checked_uint128_t; @@ -5266,6 +5266,8 @@ should now respect signed-zeros correctly. * Fix fencepost error in rational to float conversion routines, see [@https://svn.boost.org/trac/boost/ticket/12327 #12327]. * Fix some Oracle C++ compiler compatibility issues. * Add modf support to complete C90 compatibility. +* Fix self assignment bug in expression template code for expressions such as `a = a * a * a`, see [@https://svn.boost.org/trac/boost/ticket/12408 #12408]. +* Fixed some compiler errors that occur when converting from `cpp_int` to `cpp_bin_float`. [h4 Multiprecision-2.2.7 (Boost-1.61)] diff --git a/include/boost/multiprecision/cpp_int.hpp b/include/boost/multiprecision/cpp_int.hpp index 3e830d2e..c348020d 100644 --- a/include/boost/multiprecision/cpp_int.hpp +++ b/include/boost/multiprecision/cpp_int.hpp @@ -1392,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. // diff --git a/include/boost/multiprecision/cpp_int/misc.hpp b/include/boost/multiprecision/cpp_int/misc.hpp index 7de93f24..0412ff14 100644 --- a/include/boost/multiprecision/cpp_int/misc.hpp +++ b/include/boost/multiprecision/cpp_int/misc.hpp @@ -541,6 +541,7 @@ template >::value && is_signed_number >::value + && boost::is_convertible::local_limb_type, R>::value >::type eval_convert_to(R* result, const cpp_int_backend& val) { @@ -564,8 +565,8 @@ inline typename enable_if_c< *result = static_cast(*val.limbs()); if(val.isneg()) { - check_is_negative(mpl::bool_::value || boost::is_floating_point::value>()); - *result = negate_integer(*result, mpl::bool_::value || boost::is_floating_point::value>()); + check_is_negative(mpl::bool_::value || (number_category::value == number_kind_floating_point)>()); + *result = negate_integer(*result, mpl::bool_::value || (number_category::value == number_kind_floating_point)>()); } } } @@ -574,6 +575,7 @@ template >::value && is_unsigned_number >::value + && boost::is_convertible::local_limb_type, R>::value >::type eval_convert_to(R* result, const cpp_int_backend& val) { diff --git a/include/boost/multiprecision/detail/default_ops.hpp b/include/boost/multiprecision/detail/default_ops.hpp index 23b05f6d..d6910e7c 100644 --- a/include/boost/multiprecision/detail/default_ops.hpp +++ b/include/boost/multiprecision/detail/default_ops.hpp @@ -33,7 +33,18 @@ namespace boost{ namespace multiprecision{ template struct is_backend; - } + template + void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); + template + void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); + template + void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); + template + void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); + template + void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/); + +} namespace default_ops{ @@ -368,6 +379,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 inline typename enable_if_c >::value && !is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) { @@ -386,6 +398,7 @@ inline typename enable_if_c >::value>::type e { eval_multiply(t, v, u); } +#endif template inline void eval_multiply_default(T& t, const U& u, const V& v) { @@ -485,6 +498,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 inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) { @@ -511,12 +525,14 @@ inline typename enable_if_c >::value && is_co T uu(u); eval_divide(t, uu, v); } +#endif template inline void eval_divide_default(T& t, const U& u, const V& v) { if(is_same::value && ((void*)&t == (void*)&v)) { - T temp(u); + T temp; + temp = u; eval_divide(temp, v); t = temp; } @@ -918,6 +934,16 @@ inline void eval_convert_to(terminal* result, const B& backend) result->value = boost::lexical_cast(backend.str(0, std::ios_base::fmtflags(0))); } +template +inline void eval_convert_to(terminal >* result, const B2& backend) +{ + // + // We ran out of types to try for the conversion, try + // a generic conversion and hope for the best: + // + boost::multiprecision::detail::generic_interconvert(result->value.backend(), backend, number_category(), number_category()); +} + template inline void eval_convert_to(std::string* result, const B& backend) { diff --git a/include/boost/multiprecision/detail/generic_interconvert.hpp b/include/boost/multiprecision/detail/generic_interconvert.hpp index aa6d3bf5..6a840f85 100644 --- a/include/boost/multiprecision/detail/generic_interconvert.hpp +++ b/include/boost/multiprecision/detail/generic_interconvert.hpp @@ -35,36 +35,37 @@ void generic_interconvert(To& to, const From& from, const mpl::int_::type limb_type; + typedef typename canonical::type l_limb_type; // get the corresponding type that we can assign to "To": - typedef typename canonical::type to_type; + typedef typename canonical::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(0); + l_limb_type limb; + l_limb_type mask = static_cast(~static_cast(0)); From fl; eval_bitwise_and(fl, t, mask); eval_convert_to(&limb, fl); to = static_cast(limb); - eval_right_shift(t, std::numeric_limits::digits); + eval_right_shift(t, std::numeric_limits::digits); // // Then keep picking off more limbs until "t" is zero: // To l; - unsigned shift = std::numeric_limits::digits; + unsigned shift = std::numeric_limits::digits; while(!eval_is_zero(t)) { eval_bitwise_and(fl, t, mask); eval_convert_to(&limb, fl); l = static_cast(limb); - eval_right_shift(t, std::numeric_limits::digits); + eval_right_shift(t, std::numeric_limits::digits); eval_ldexp(l, l, shift); eval_add(to, l); - shift += std::numeric_limits::digits; + shift += std::numeric_limits::digits; } // // Finish off by setting the sign: diff --git a/include/boost/multiprecision/number.hpp b/include/boost/multiprecision/number.hpp index 62321a63..15af7ef8 100644 --- a/include/boost/multiprecision/number.hpp +++ b/include/boost/multiprecision/number.hpp @@ -761,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()); @@ -771,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()); @@ -799,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()); @@ -810,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()); @@ -839,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()); @@ -849,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()); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 046ddb60..3f3a48eb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -370,6 +370,7 @@ compile test_nothrow_mpfr.cpp : [ check-target-builds ../config//has_mpfr : : -inline Real negate(const Real& val, const boost::mpl::true_&) +inline Real negate_value(const Real& val, const boost::mpl::true_&) { return -val; } template -inline Real negate(const Real& val, const boost::mpl::false_&) +inline Real negate_value(const Real& val, const boost::mpl::false_&) { return val; } @@ -1764,14 +1764,14 @@ void test_mixed(const boost::mpl::true_&) { d = static_cast(std::numeric_limits::infinity()); BOOST_CHECK_GT(d, (std::numeric_limits::max)()); - d = static_cast(negate(std::numeric_limits::infinity(), boost::mpl::bool_::is_signed>())); - BOOST_CHECK_LT(d, negate((std::numeric_limits::max)(), boost::mpl::bool_::is_signed>())); + d = static_cast(negate_value(std::numeric_limits::infinity(), boost::mpl::bool_::is_signed>())); + BOOST_CHECK_LT(d, negate_value((std::numeric_limits::max)(), boost::mpl::bool_::is_signed>())); } if(std::numeric_limits::has_quiet_NaN && std::numeric_limits::has_quiet_NaN) { d = static_cast(std::numeric_limits::quiet_NaN()); BOOST_CHECK(check_is_nan(d, boost::mpl::bool_::has_quiet_NaN>())); - d = static_cast(negate(std::numeric_limits::quiet_NaN(), boost::mpl::bool_::is_signed>())); + d = static_cast(negate_value(std::numeric_limits::quiet_NaN(), boost::mpl::bool_::is_signed>())); BOOST_CHECK(check_is_nan(d, boost::mpl::bool_::has_quiet_NaN>())); } } @@ -2290,5 +2290,27 @@ void test() a = 20; a = a; BOOST_CHECK_EQUAL(a, 20); + + a = 2; + a = a * a * a; + BOOST_CHECK_EQUAL(a, 8); + a = 2; + a = a + a + a; + BOOST_CHECK_EQUAL(a, 6); + a = 2; + a = a - a + a; + BOOST_CHECK_EQUAL(a, 2); + a = 2; + a = a + a - a; + BOOST_CHECK_EQUAL(a, 2); + a = 2; + a = a * a - a; + BOOST_CHECK_EQUAL(a, 2); + a = 2; + a = a + a * a; + BOOST_CHECK_EQUAL(a, 6); + a = 2; + a = (a + a) * a; + BOOST_CHECK_EQUAL(a, 8); } diff --git a/test/test_cpp_bin_float_conv.cpp b/test/test_cpp_bin_float_conv.cpp new file mode 100644 index 00000000..7c58eb82 --- /dev/null +++ b/test/test_cpp_bin_float_conv.cpp @@ -0,0 +1,86 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ +// + +#ifdef _MSC_VER +# define _SCL_SECURE_NO_WARNINGS +#endif + +#include +#include +#include "test.hpp" + +#include +#include + +int main() +{ + using namespace boost::multiprecision; + + cpp_int i(20); + cpp_bin_float_50 f50(i); + BOOST_CHECK_EQUAL(f50, 20); + f50 = i.convert_to(); + BOOST_CHECK_EQUAL(f50, 20); + + int1024_t i1024(45); + cpp_bin_float_100 f100(i1024); + BOOST_CHECK_EQUAL(f100, 45); + f100 = i1024.convert_to(); + BOOST_CHECK_EQUAL(f100, 45); + + uint1024_t ui1024(55); + cpp_bin_float_100 f100b(ui1024); + BOOST_CHECK_EQUAL(f100b, 55); + f100b = ui1024.convert_to(); + BOOST_CHECK_EQUAL(f100b, 55); + + typedef number, et_off> i32_t; + i32_t i32(67); + cpp_bin_float_100 f100c(i32); + BOOST_CHECK_EQUAL(f100c, 67); + f100c = i32.convert_to(); + BOOST_CHECK_EQUAL(f100c, 67); + + typedef number, et_off> ui32_t; + ui32_t ui32(98); + cpp_bin_float_100 f100d(ui32); + BOOST_CHECK_EQUAL(f100d, 98); + f100d = ui32.convert_to(); + BOOST_CHECK_EQUAL(f100d, 98); + + typedef number, et_off> i64_t; + i64_t i64(67); + cpp_bin_float_100 f100e(i64); + BOOST_CHECK_EQUAL(f100e, 67); + f100e = i64.convert_to(); + BOOST_CHECK_EQUAL(f100e, 67); + + typedef number, et_off> ui64_t; + ui64_t ui64(98); + cpp_bin_float_100 f100f(ui64); + BOOST_CHECK_EQUAL(f100f, 98); + f100f = ui64.convert_to(); + BOOST_CHECK_EQUAL(f100f, 98); + + typedef number, et_off> i128_t; + i128_t i128(67); + cpp_bin_float_100 f100g(i128); + BOOST_CHECK_EQUAL(f100g, 67); + f100g = i128.convert_to(); + BOOST_CHECK_EQUAL(f100g, 67); + + typedef number, et_off> ui128_t; + ui128_t ui128(98); + cpp_bin_float_100 f100h(ui128); + BOOST_CHECK_EQUAL(f100h, 98); + f100h = ui128.convert_to(); + BOOST_CHECK_EQUAL(f100h, 98); + + return boost::report_errors(); +} + + +