mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-02-27 17:12:26 +00:00
Test and fix mixed precision arithmetic with component types.
This commit is contained in:
@@ -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());
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user