mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-02-18 14:12:32 +00:00
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:
@@ -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)]
|
||||
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
86
test/test_cpp_bin_float_conv.cpp
Normal file
86
test/test_cpp_bin_float_conv.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user