Test and fix mixed precision arithmetic with component types.

This commit is contained in:
jzmaddock
2021-04-20 11:54:36 +01:00
parent 2bba4a7a2a
commit 26ab08df2e
7 changed files with 248 additions and 13 deletions

View File

@@ -52,7 +52,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type
operator+(const number<B, et_off>& a, const V& b) operator+(const number<B, et_off>& a, const V& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a, b);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_add; using default_ops::eval_add;
eval_add(result.backend(), a.backend(), number<B, et_off>::canonical_value(b)); eval_add(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
@@ -62,7 +62,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type
operator+(const V& a, const number<B, et_off>& b) operator+(const V& a, const number<B, et_off>& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b, a);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_add; using default_ops::eval_add;
eval_add(result.backend(), b.backend(), number<B, et_off>::canonical_value(a)); eval_add(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
@@ -84,7 +84,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type
operator-(const number<B, et_off>& a, const V& b) operator-(const number<B, et_off>& a, const V& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a, b);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_subtract; using default_ops::eval_subtract;
eval_subtract(result.backend(), a.backend(), number<B, et_off>::canonical_value(b)); eval_subtract(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
@@ -94,7 +94,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type
operator-(const V& a, const number<B, et_off>& b) operator-(const V& a, const number<B, et_off>& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b, a);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_subtract; using default_ops::eval_subtract;
eval_subtract(result.backend(), number<B, et_off>::canonical_value(a), b.backend()); eval_subtract(result.backend(), number<B, et_off>::canonical_value(a), b.backend());
@@ -116,7 +116,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type
operator*(const number<B, et_off>& a, const V& b) operator*(const number<B, et_off>& a, const V& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a, b);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_multiply; using default_ops::eval_multiply;
eval_multiply(result.backend(), a.backend(), number<B, et_off>::canonical_value(b)); eval_multiply(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
@@ -126,7 +126,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type
operator*(const V& a, const number<B, et_off>& b) operator*(const V& a, const number<B, et_off>& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b, a);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_multiply; using default_ops::eval_multiply;
eval_multiply(result.backend(), b.backend(), number<B, et_off>::canonical_value(a)); eval_multiply(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
@@ -148,7 +148,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value, number<B, et_off> >::type
operator/(const number<B, et_off>& a, const V& b) operator/(const number<B, et_off>& a, const V& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(a, b);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_divide; using default_ops::eval_divide;
eval_divide(result.backend(), a.backend(), number<B, et_off>::canonical_value(b)); eval_divide(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
@@ -158,7 +158,7 @@ namespace boost {
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >::value && !is_equivalent_number_type<V, B>::value, number<B, et_off> >::type
operator/(const V& a, const number<B, et_off>& b) operator/(const V& a, const number<B, et_off>& b)
{ {
detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b); detail::scoped_default_precision<multiprecision::number<B, et_off> > precision_guard(b, a);
number<B, et_off> result; number<B, et_off> result;
using default_ops::eval_divide; using default_ops::eval_divide;
eval_divide(result.backend(), number<B, et_off>::canonical_value(a), b.backend()); eval_divide(result.backend(), number<B, et_off>::canonical_value(a), b.backend());

View File

@@ -197,6 +197,20 @@ inline BOOST_MP_CXX14_CONSTEXPR void maybe_promote_precision(T* obj)
#define BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(T) if (boost::multiprecision::detail::is_variable_precision<T>::value) #define BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(T) if (boost::multiprecision::detail::is_variable_precision<T>::value)
#endif #endif
template <class T>
struct scoped_target_precision
{
variable_precision_options opts;
scoped_target_precision() : opts(T::thread_default_variable_precision_options())
{
T::thread_default_variable_precision_options(variable_precision_options::preserve_target_precision, variable_precision_options::precision_group);
}
~scoped_target_precision()
{
T::thread_default_variable_precision_options(opts);
}
};
} }
} }
} // namespace boost::multiprecision::detail } // namespace boost::multiprecision::detail

View File

@@ -562,7 +562,7 @@ struct mpc_complex_backend<0> : public detail::mpc_complex_imp<0>
} }
template <unsigned D> template <unsigned D>
mpc_complex_backend(const mpfr_float_backend<D>& val) mpc_complex_backend(const mpfr_float_backend<D>& val)
: detail::mpc_complex_imp<0>(mpfr_get_prec(val.data())) : detail::mpc_complex_imp<0>(this->preserve_source_precision() ? mpfr_get_prec(val.data()) : multiprecision::detail::digits10_2_2(this->get_default_precision()))
{ {
mpc_set_fr(this->m_data, val.data(), GMP_RNDN); mpc_set_fr(this->m_data, val.data(), GMP_RNDN);
} }
@@ -707,7 +707,8 @@ struct mpc_complex_backend<0> : public detail::mpc_complex_imp<0>
template <unsigned D> template <unsigned D>
mpc_complex_backend& operator=(const mpfr_float_backend<D>& val) mpc_complex_backend& operator=(const mpfr_float_backend<D>& val)
{ {
mpc_set_prec(this->m_data, mpfr_get_prec(val.data())); if(this->preserve_source_precision())
mpc_set_prec(this->m_data, mpfr_get_prec(val.data()));
mpc_set_fr(this->m_data, val.data(), GMP_RNDN); mpc_set_fr(this->m_data, val.data(), GMP_RNDN);
return *this; return *this;
} }
@@ -1160,10 +1161,13 @@ inline void assign_components(mpc_complex_backend<D1>& result, const mpfr_float_
// This is called from class number's constructors, so if we have variable // This is called from class number's constructors, so if we have variable
// precision, then copy the precision of the source variables. // precision, then copy the precision of the source variables.
// //
if (!D1) BOOST_IF_CONSTEXPR(!D1)
{ {
unsigned long prec = (std::max)(mpfr_get_prec(a.data()), mpfr_get_prec(b.data())); if ((result.thread_default_variable_precision_options() & variable_precision_options::precision_group) == variable_precision_options::preserve_source_precision)
mpc_set_prec(result.data(), prec); {
unsigned long prec = (std::max)(mpfr_get_prec(a.data()), mpfr_get_prec(b.data()));
mpc_set_prec(result.data(), prec);
}
} }
using default_ops::eval_fpclassify; using default_ops::eval_fpclassify;
if (eval_fpclassify(a) == (int)FP_NAN) if (eval_fpclassify(a) == (int)FP_NAN)

View File

@@ -15,6 +15,7 @@
#include <boost/math/special_functions/fpclassify.hpp> #include <boost/math/special_functions/fpclassify.hpp>
#include <boost/multiprecision/detail/big_lanczos.hpp> #include <boost/multiprecision/detail/big_lanczos.hpp>
#include <boost/multiprecision/detail/digits.hpp> #include <boost/multiprecision/detail/digits.hpp>
#include <boost/multiprecision/detail/precision.hpp>
#include <boost/multiprecision/detail/atomic.hpp> #include <boost/multiprecision/detail/atomic.hpp>
#include <boost/multiprecision/traits/max_digits10.hpp> #include <boost/multiprecision/traits/max_digits10.hpp>
#include <boost/multiprecision/mpfr.hpp> #include <boost/multiprecision/mpfr.hpp>
@@ -93,6 +94,13 @@ struct mpfi_float_imp
if (o.m_data[0].left._mpfr_d) if (o.m_data[0].left._mpfr_d)
mpfi_set(m_data, o.m_data); mpfi_set(m_data, o.m_data);
} }
template <unsigned D, mpfr_allocation_type AllocationType>
mpfi_float_imp(const mpfr_float_imp<D, AllocationType>& o)
{
mpfi_init2(m_data, preserve_source_precision() ? mpfr_get_prec(o.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
if (o.data()[0]._mpfr_d)
mpfi_set_fr(m_data, o.data());
}
// rvalue copy // rvalue copy
mpfi_float_imp(mpfi_float_imp&& o) noexcept mpfi_float_imp(mpfi_float_imp&& o) noexcept
{ {
@@ -386,6 +394,10 @@ struct mpfi_float_backend : public detail::mpfi_float_imp<digits10>
{ {
mpfi_set(this->m_data, val.data()); mpfi_set(this->m_data, val.data());
} }
template <unsigned D, mpfr_allocation_type AllocationType>
mpfi_float_backend(const mpfr_float_backend<D, AllocationType>& val, typename std::enable_if<D <= digits10>::type* = 0)
: detail::mpfi_float_imp<digits10>(val) {}
template <unsigned D> template <unsigned D>
explicit mpfi_float_backend(const mpfi_float_backend<D>& val, typename std::enable_if<!(D <= digits10)>::type* = 0) explicit mpfi_float_backend(const mpfi_float_backend<D>& val, typename std::enable_if<!(D <= digits10)>::type* = 0)
: detail::mpfi_float_imp<digits10>() : detail::mpfi_float_imp<digits10>()
@@ -463,6 +475,11 @@ struct mpfi_float_backend<0> : public detail::mpfi_float_imp<0>
mpfi_set(this->m_data, val); mpfi_set(this->m_data, val);
} }
mpfi_float_backend(const mpfi_float_backend& o) : detail::mpfi_float_imp<0>(o) {} mpfi_float_backend(const mpfi_float_backend& o) : detail::mpfi_float_imp<0>(o) {}
template <unsigned D, mpfr_allocation_type AllocationType>
mpfi_float_backend(const mpfr_float_backend<D, AllocationType>& val)
: detail::mpfi_float_imp<0>(val) {}
// rvalue copy // rvalue copy
mpfi_float_backend(mpfi_float_backend&& o) noexcept : detail::mpfi_float_imp<0>(static_cast<detail::mpfi_float_imp<0>&&>(o)) mpfi_float_backend(mpfi_float_backend&& o) noexcept : detail::mpfi_float_imp<0>(static_cast<detail::mpfi_float_imp<0>&&>(o))
{} {}
@@ -475,6 +492,7 @@ struct mpfi_float_backend<0> : public detail::mpfi_float_imp<0>
mpfi_float_backend(const V& a, const V& b, unsigned digits10) mpfi_float_backend(const V& a, const V& b, unsigned digits10)
: detail::mpfi_float_imp<0>(multiprecision::detail::digits10_2_2(digits10)) : detail::mpfi_float_imp<0>(multiprecision::detail::digits10_2_2(digits10))
{ {
boost::multiprecision::detail::scoped_target_precision<mpfi_float_backend<0> > opts;
assign_components(*this, a, b); assign_components(*this, a, b);
} }
@@ -850,6 +868,19 @@ inline void eval_convert_to(long double* result, const mpfi_float_backend<digits
template <unsigned D1, unsigned D2, mpfr_allocation_type AllocationType> template <unsigned D1, unsigned D2, mpfr_allocation_type AllocationType>
inline void assign_components(mpfi_float_backend<D1>& result, const mpfr_float_backend<D2, AllocationType>& a, const mpfr_float_backend<D2, AllocationType>& b) inline void assign_components(mpfi_float_backend<D1>& result, const mpfr_float_backend<D2, AllocationType>& a, const mpfr_float_backend<D2, AllocationType>& b)
{ {
//
// This is called from class number's constructors, so if we have variable
// precision, then copy the precision of the source variables.
//
BOOST_IF_CONSTEXPR(!D1)
{
if ((result.thread_default_variable_precision_options() & variable_precision_options::precision_group) == variable_precision_options::preserve_source_precision)
{
unsigned long prec = (std::max)(mpfr_get_prec(a.data()), mpfr_get_prec(b.data()));
mpfi_set_prec(result.data(), prec);
}
}
using default_ops::eval_fpclassify; using default_ops::eval_fpclassify;
if (eval_fpclassify(a) == (int)FP_NAN) if (eval_fpclassify(a) == (int)FP_NAN)
{ {

View File

@@ -409,6 +409,23 @@ class number
typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
BOOST_MP_CXX14_CONSTEXPR operator+=(const V& v) BOOST_MP_CXX14_CONSTEXPR operator+=(const V& v)
{ {
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
//
// If the current precision of *this differs from that of value v, 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.
//
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t(*this + v);
return *this = std::move(t);
}
using default_ops::eval_add; using default_ops::eval_add;
eval_add(m_backend, canonical_value(v)); eval_add(m_backend, canonical_value(v));
return *this; return *this;
@@ -457,6 +474,23 @@ class number
BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator-=(const V& v) operator-=(const V& v)
{ {
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
//
// If the current precision of *this differs from that of value v, 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.
//
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t(*this - v);
return *this = std::move(t);
}
using default_ops::eval_subtract; using default_ops::eval_subtract;
eval_subtract(m_backend, canonical_value(v)); eval_subtract(m_backend, canonical_value(v));
return *this; return *this;
@@ -536,6 +570,23 @@ class number
BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator*=(const V& v) operator*=(const V& v)
{ {
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
//
// If the current precision of *this differs from that of value v, 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.
//
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t(*this + v);
return *this = std::move(t);
}
using default_ops::eval_multiply; using default_ops::eval_multiply;
eval_multiply(m_backend, canonical_value(v)); eval_multiply(m_backend, canonical_value(v));
return *this; return *this;
@@ -689,6 +740,23 @@ class number
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator/=(const V& v) operator/=(const V& v)
{ {
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
//
// If the current precision of *this differs from that of value v, 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.
//
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t(*this + v);
return *this = std::move(t);
}
using default_ops::eval_divide; using default_ops::eval_divide;
eval_divide(m_backend, canonical_value(v)); eval_divide(m_backend, canonical_value(v));
return *this; return *this;

View File

@@ -101,6 +101,78 @@ void test()
BOOST_CHECK_EQUAL(a.precision(), 100); BOOST_CHECK_EQUAL(a.precision(), 100);
a = new_value<T>(); a = new_value<T>();
BOOST_CHECK_EQUAL(a.precision(), 35); BOOST_CHECK_EQUAL(a.precision(), 35);
if constexpr (!std::is_same_v<T, typename T::value_type>)
{
//
// If we have a component type: ie we are an interval or a complex number, then
// operations involving the component type should match those of T:
//
using component_t = typename T::value_type;
component_t::thread_default_precision(100);
component_t::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_source_precision);
component_t cp1("0.1"), cp2("0.3"), cp3("0.11"), cp4("0.1231");
BOOST_CHECK_EQUAL(cp1.precision(), 100);
BOOST_CHECK_EQUAL(cp2.precision(), 100);
component_t::thread_default_precision(35);
T aa(cp1);
BOOST_CHECK_EQUAL(aa.precision(), 100);
T cc(cp1, cp2);
BOOST_CHECK_EQUAL(cc.precision(), 100);
T dd(cp1, cp2, 55);
BOOST_CHECK_EQUAL(dd.precision(), 55);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
if constexpr (std::is_assignable_v<T, component_t>)
{
aa = cp1;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa = std::move(cp1);
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
}
T bb(std::move(cp2));
BOOST_CHECK_EQUAL(bb.precision(), 100);
bb = new_value<T>();
BOOST_CHECK_EQUAL(bb.precision(), 35);
if constexpr (boost::multiprecision::is_compatible_arithmetic_type<component_t, T>::value)
{
aa = bb + cp3;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa = cp3 * bb;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa += cp3;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
aa -= cp3;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa *= cp4;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
aa /= cp4;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa -= bb * cp3;
BOOST_CHECK_EQUAL(aa.precision(), 100);
aa = new_value<T>();
BOOST_CHECK_EQUAL(aa.precision(), 35);
}
}
} }
int main() int main()

View File

@@ -77,6 +77,52 @@ void test()
BOOST_CHECK_EQUAL(a.precision(), 35); BOOST_CHECK_EQUAL(a.precision(), 35);
a -= b * hp3; a -= b * hp3;
BOOST_CHECK_EQUAL(a.precision(), 35); BOOST_CHECK_EQUAL(a.precision(), 35);
if constexpr (!std::is_same_v<T, typename T::value_type>)
{
//
// If we have a component type: ie we are an interval or a complex number, then
// operations involving the component type should match those of T:
//
using component_t = typename T::value_type;
component_t::thread_default_precision(100);
component_t::thread_default_variable_precision_options(boost::multiprecision::variable_precision_options::preserve_source_precision);
component_t cp1("0.1"), cp2("0.3"), cp3("0.11"), cp4("0.1231");
BOOST_CHECK_EQUAL(cp1.precision(), 100);
BOOST_CHECK_EQUAL(cp2.precision(), 100);
T::thread_default_precision(35);
T aa(cp1);
BOOST_CHECK_EQUAL(aa.precision(), 35);
T cc(cp1, cp2);
BOOST_CHECK_EQUAL(cc.precision(), 35);
T dd(cp1, cp2, 20);
BOOST_CHECK_EQUAL(dd.precision(), 20);
aa = cp1;
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa = std::move(cp1);
BOOST_CHECK_EQUAL(aa.precision(), 35);
T bb(std::move(cp2));
BOOST_CHECK_EQUAL(bb.precision(), 35);
aa = bb + cp3;
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa = cp3 * bb;
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa += cp3;
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa -= cp3;
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa *= cp4;
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa /= cp4;
BOOST_CHECK_EQUAL(aa.precision(), 35);
aa -= bb * cp3;
BOOST_CHECK_EQUAL(aa.precision(), 35);
}
} }
int main() int main()