Consider rational types separately when figuring out precision.

Update precision guards to account for the precision of *this.
This commit is contained in:
jzmaddock
2021-04-05 19:01:40 +01:00
parent 1c8fcaea68
commit 8c49dfd5e9
2 changed files with 55 additions and 27 deletions

View File

@@ -13,12 +13,12 @@
namespace boost { namespace multiprecision { namespace detail {
template <class B, boost::multiprecision::expression_template_option ET>
inline constexpr unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>&, const std::integral_constant<bool, false>&)
inline constexpr unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>&, const std::integral_constant<int, 0>&)
{
return std::numeric_limits<boost::multiprecision::number<B, ET> >::digits10;
}
template <class B, boost::multiprecision::expression_template_option ET>
inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>& val, const std::integral_constant<bool, true>&)
inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>& val, const std::integral_constant<int, 1>&)
{
//
// We have an arbitrary precision integer, take it's "precision" as the
@@ -28,6 +28,15 @@ inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_last_chance_imp(co
//
return val.is_zero() ? 1 : digits2_2_10(msb(abs(val)) - lsb(abs(val)) + 1);
}
template <class B, boost::multiprecision::expression_template_option ET>
inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>& val, const std::integral_constant<int, 2>&)
{
//
// We have an arbitrary precision rational, take it's "precision" as the
// the larger of the "precision" of numerator and denominator:
//
return (std::max)(current_precision_of_last_chance_imp(numerator(val), std::integral_constant<int, 1>()), current_precision_of_last_chance_imp(denominator(val), std::integral_constant<int, 1>()));
}
template <class B, boost::multiprecision::expression_template_option ET>
inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& n, const std::integral_constant<bool, true>&)
@@ -37,10 +46,15 @@ inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_imp(const boost::m
template <class B, boost::multiprecision::expression_template_option ET>
inline constexpr unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& val, const std::integral_constant<bool, false>&)
{
return current_precision_of_last_chance_imp(val,
std::integral_constant<bool,
std::numeric_limits<boost::multiprecision::number<B, ET> >::is_specialized &&
std::numeric_limits<boost::multiprecision::number<B, ET> >::is_integer && std::numeric_limits<boost::multiprecision::number<B, ET> >::is_exact && !std::numeric_limits<boost::multiprecision::number<B, ET> >::is_modulo > ());
using tag = std::integral_constant<int,
std::numeric_limits<boost::multiprecision::number<B, ET> >::is_specialized &&
std::numeric_limits<boost::multiprecision::number<B, ET> >::is_integer &&
std::numeric_limits<boost::multiprecision::number<B, ET> >::is_exact &&
!std::numeric_limits<boost::multiprecision::number<B, ET> >::is_modulo
? 1
: boost::multiprecision::number_category<boost::multiprecision::number<B, ET> >::value == boost::multiprecision::number_kind_rational ? 2
: 0>;
return current_precision_of_last_chance_imp(val, tag());
}
template <class Terminal>

View File

@@ -121,7 +121,8 @@ class number
typename std::enable_if<(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value && !std::is_same<typename component_type<self_type>::type, self_type>::value)>::type* = 0)
{
using default_ops::assign_components;
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2, *this);
detail::scoped_default_precision<typename component_type<self_type>::type> component_precision_guard(v1, v2, *this);
assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
}
template <class V, class U>
@@ -130,7 +131,8 @@ class number
(std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<typename component_type<self_type>::type, self_type>::value && !std::is_same<V, self_type>::value && !(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value)>::type* = 0)
{
using default_ops::assign_components;
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2, this);
detail::scoped_default_precision<typename component_type<self_type>::type> component_precision_guard(v1, v2, *this);
assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
}
#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
@@ -193,11 +195,14 @@ class number
// 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))
BOOST_IF_CONSTEXPR (std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
{
number t(e);
return *this = std::move(t);
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t(e);
return *this = std::move(t);
}
}
do_assign(e, tag_type());
return *this;
@@ -216,12 +221,15 @@ class number
// 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))
BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
{
number t;
t.assign(e);
return *this = std::move(t);
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t;
t.assign(e);
return *this = std::move(t);
}
}
do_assign(e, tag_type());
return *this;
@@ -264,8 +272,8 @@ class number
// Attempt a generic interconvertion:
//
using detail::generic_interconvert;
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v);
detail::scoped_default_precision<number<Other, ET> > precision_guard2(v);
detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
detail::scoped_default_precision<number<Other, ET> > precision_guard2(*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)
@@ -380,11 +388,14 @@ class number
// 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))
BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
{
number t(*this + e);
return *this = std::move(t);
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t(*this + e);
return *this = std::move(t);
}
}
//
// Fused multiply-add:
@@ -464,11 +475,14 @@ class number
// 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))
BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
{
number t(*this - e);
return *this = std::move(t);
BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
{
number t(*this - e);
return *this = std::move(t);
}
}
//
// Fused multiply-subtract: