Merge branch 'develop' into c99

# Resolved Conflicts:
#	doc/html/boost_multiprecision/indexes/s01.html
#	doc/html/boost_multiprecision/indexes/s02.html
#	doc/html/boost_multiprecision/indexes/s03.html
#	doc/html/boost_multiprecision/indexes/s04.html
#	doc/html/index.html
#	include/boost/multiprecision/detail/default_ops.hpp
This commit is contained in:
jzmaddock
2016-09-23 09:01:56 +01:00
9 changed files with 177 additions and 37 deletions

View File

@@ -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<cpp_int_backend<0, 0, signed_magnitude, checked> > checked_cpp_int;
typedef rational_adaptor<cpp_int_backend<0, 0, signed_magnitude, checked> > checked_cpp_rational_backend;
typedef number<cpp_rational_backend> checked_cpp_rational;
typedef number<checked_cpp_rational_backend> checked_cpp_rational;
// Checked fixed precision unsigned types:
typedef number<cpp_int_backend<128, 128, unsigned_magnitude, checked, void> > 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)]

View File

@@ -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.
//

View File

@@ -541,6 +541,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_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)
{
@@ -564,8 +565,8 @@ inline typename enable_if_c<
*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>());
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)>());
}
}
}
@@ -574,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)
{

View File

@@ -33,7 +33,18 @@ namespace boost{ namespace multiprecision{
template <class T>
struct is_backend;
}
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{
@@ -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 <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)
{
@@ -386,6 +398,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)
{
@@ -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 <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)
{
@@ -511,12 +525,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;
}
@@ -918,6 +934,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)
{

View File

@@ -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:

View File

@@ -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());

View File

@@ -370,6 +370,7 @@ compile test_nothrow_mpfr.cpp : [ check-target-builds ../config//has_mpfr : : <b
# This take too long to run as a regular part of the tests:
#
# run test_cpp_bin_float_round.cpp mpfr gmp ;
run test_cpp_bin_float_conv.cpp ;
run test_cpp_bin_float_io.cpp no_eh_support /boost/system//boost_system /boost/chrono//boost_chrono
: # command line

View File

@@ -1548,12 +1548,12 @@ inline bool check_is_nan(const Real&, const boost::mpl::false_&)
return false;
}
template <class Real>
inline Real negate(const Real& val, const boost::mpl::true_&)
inline Real negate_value(const Real& val, const boost::mpl::true_&)
{
return -val;
}
template <class Real>
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<Real>(std::numeric_limits<Num>::infinity());
BOOST_CHECK_GT(d, (std::numeric_limits<Real>::max)());
d = static_cast<Real>(negate(std::numeric_limits<Num>::infinity(), boost::mpl::bool_<std::numeric_limits<Num>::is_signed>()));
BOOST_CHECK_LT(d, negate((std::numeric_limits<Real>::max)(), boost::mpl::bool_<std::numeric_limits<Real>::is_signed>()));
d = static_cast<Real>(negate_value(std::numeric_limits<Num>::infinity(), boost::mpl::bool_<std::numeric_limits<Num>::is_signed>()));
BOOST_CHECK_LT(d, negate_value((std::numeric_limits<Real>::max)(), boost::mpl::bool_<std::numeric_limits<Real>::is_signed>()));
}
if(std::numeric_limits<Real>::has_quiet_NaN && std::numeric_limits<Num>::has_quiet_NaN)
{
d = static_cast<Real>(std::numeric_limits<Num>::quiet_NaN());
BOOST_CHECK(check_is_nan(d, boost::mpl::bool_<std::numeric_limits<Real>::has_quiet_NaN>()));
d = static_cast<Real>(negate(std::numeric_limits<Num>::quiet_NaN(), boost::mpl::bool_<std::numeric_limits<Num>::is_signed>()));
d = static_cast<Real>(negate_value(std::numeric_limits<Num>::quiet_NaN(), boost::mpl::bool_<std::numeric_limits<Num>::is_signed>()));
BOOST_CHECK(check_is_nan(d, boost::mpl::bool_<std::numeric_limits<Real>::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);
}

View File

@@ -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 <boost/detail/lightweight_test.hpp>
#include <boost/array.hpp>
#include "test.hpp"
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
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<cpp_bin_float_50>();
BOOST_CHECK_EQUAL(f50, 20);
int1024_t i1024(45);
cpp_bin_float_100 f100(i1024);
BOOST_CHECK_EQUAL(f100, 45);
f100 = i1024.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100, 45);
uint1024_t ui1024(55);
cpp_bin_float_100 f100b(ui1024);
BOOST_CHECK_EQUAL(f100b, 55);
f100b = ui1024.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100b, 55);
typedef number<cpp_int_backend<32, 32>, et_off> i32_t;
i32_t i32(67);
cpp_bin_float_100 f100c(i32);
BOOST_CHECK_EQUAL(f100c, 67);
f100c = i32.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100c, 67);
typedef number<cpp_int_backend<32, 32, unsigned_magnitude>, et_off> ui32_t;
ui32_t ui32(98);
cpp_bin_float_100 f100d(ui32);
BOOST_CHECK_EQUAL(f100d, 98);
f100d = ui32.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100d, 98);
typedef number<cpp_int_backend<64, 64>, et_off> i64_t;
i64_t i64(67);
cpp_bin_float_100 f100e(i64);
BOOST_CHECK_EQUAL(f100e, 67);
f100e = i64.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100e, 67);
typedef number<cpp_int_backend<64, 64, unsigned_magnitude>, et_off> ui64_t;
ui64_t ui64(98);
cpp_bin_float_100 f100f(ui64);
BOOST_CHECK_EQUAL(f100f, 98);
f100f = ui64.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100f, 98);
typedef number<cpp_int_backend<128, 128>, et_off> i128_t;
i128_t i128(67);
cpp_bin_float_100 f100g(i128);
BOOST_CHECK_EQUAL(f100g, 67);
f100g = i128.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100g, 67);
typedef number<cpp_int_backend<128, 128, unsigned_magnitude>, et_off> ui128_t;
ui128_t ui128(98);
cpp_bin_float_100 f100h(ui128);
BOOST_CHECK_EQUAL(f100h, 98);
f100h = ui128.convert_to<cpp_bin_float_100>();
BOOST_CHECK_EQUAL(f100h, 98);
return boost::report_errors();
}