Fix handling of NaN's and Infinities in basic arithmetic.

Added more test cases to catch bugs.
See issue: https://svn.boost.org/trac/boost/ticket/12090.
This commit is contained in:
jzmaddock
2016-03-24 10:13:01 +00:00
parent d3c6beb721
commit c4e847b9fd
3 changed files with 76 additions and 2 deletions

View File

@@ -581,8 +581,8 @@ inline void do_eval_subtract(cpp_bin_float<Digits, DigitBase, Allocator, Exponen
res = a;
return;
case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan;
res.sign() = false;
res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
res.sign() = true;
res.bits() = static_cast<limb_type>(0u);
return; // result is a NaN.
case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:

View File

@@ -662,6 +662,12 @@ cpp_dec_float<Digits10, ExponentType, Allocator>& cpp_dec_float<Digits10, Expone
return operator=(v);
}
if((v.isnan)() || (v.isinf)())
{
*this = v;
return *this;
}
// Get the offset for the add/sub operation.
static const ExponentType max_delta_exp = static_cast<ExponentType>((cpp_dec_float_elem_number - 1) * cpp_dec_float_elem_digits10);

View File

@@ -993,6 +993,74 @@ void test_float_ops(const boost::mpl::int_<boost::multiprecision::number_kind_fl
}
}
//
// Operations involving NaN's as one argument:
//
if(std::numeric_limits<Real>::has_quiet_NaN)
{
v = 20.25;
r = std::numeric_limits<Real>::quiet_NaN();
BOOST_CHECK((boost::math::isnan)(v + r));
BOOST_CHECK((boost::math::isnan)(r + v));
BOOST_CHECK((boost::math::isnan)(r - v));
BOOST_CHECK((boost::math::isnan)(v - r));
BOOST_CHECK((boost::math::isnan)(r * v));
BOOST_CHECK((boost::math::isnan)(v * r));
BOOST_CHECK((boost::math::isnan)(r / v));
BOOST_CHECK((boost::math::isnan)(v / r));
Real t = v;
BOOST_CHECK((boost::math::isnan)(t += r));
t = r;
BOOST_CHECK((boost::math::isnan)(t += v));
t = r;
BOOST_CHECK((boost::math::isnan)(t -= v));
t = v;
BOOST_CHECK((boost::math::isnan)(t -= r));
t = r;
BOOST_CHECK((boost::math::isnan)(t *= v));
t = v;
BOOST_CHECK((boost::math::isnan)(t *= r));
t = r;
BOOST_CHECK((boost::math::isnan)(t /= v));
t = v;
BOOST_CHECK((boost::math::isnan)(t /= r));
}
//
// Operations involving infinities as one argument:
//
if(std::numeric_limits<Real>::has_infinity)
{
v = 20.25;
r = std::numeric_limits<Real>::infinity();
BOOST_CHECK((boost::math::isinf)(v + r));
BOOST_CHECK((boost::math::isinf)(r + v));
BOOST_CHECK((boost::math::isinf)(r - v));
BOOST_CHECK((boost::math::isinf)(v - r));
BOOST_CHECK_LT(v - r, 0);
BOOST_CHECK((boost::math::isinf)(r * v));
BOOST_CHECK((boost::math::isinf)(v * r));
BOOST_CHECK((boost::math::isinf)(r / v));
BOOST_CHECK_EQUAL(v / r, 0);
Real t = v;
BOOST_CHECK((boost::math::isinf)(t += r));
t = r;
BOOST_CHECK((boost::math::isinf)(t += v));
t = r;
BOOST_CHECK((boost::math::isinf)(t -= v));
t = v;
BOOST_CHECK((boost::math::isinf)(t -= r));
t = v;
BOOST_CHECK(t -= r < 0);
t = r;
BOOST_CHECK((boost::math::isinf)(t *= v));
t = v;
BOOST_CHECK((boost::math::isinf)(t *= r));
t = r;
BOOST_CHECK((boost::math::isinf)(t /= v));
t = v;
BOOST_CHECK((t /= r) == 0);
}
test_float_funcs<Real>(boost::mpl::bool_<std::numeric_limits<Real>::is_specialized>());
}