Skip to content

Commit

Permalink
Merge pull request #1135 from boostorg/issue1132
Browse files Browse the repository at this point in the history
Correct float_next(+INF) and float_prior(-INF)
  • Loading branch information
jzmaddock authored May 18, 2024
2 parents d1d59cd + 7048e7c commit 52be1ad
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 14 deletions.
32 changes: 24 additions & 8 deletions include/boost/math/special_functions/next.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,14 @@ T float_next_imp(const T& val, const std::true_type&, const Policy& pol)

int fpclass = (boost::math::fpclassify)(val);

if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
if (fpclass == (int)FP_INFINITE)
{
if(val < 0)
if (val < 0)
return -tools::max_value<T>();
return val; // +INF
}
else if (fpclass == (int)FP_NAN)
{
return policies::raise_domain_error<T>(
function,
"Argument must be finite, but got %1%", val, pol);
Expand Down Expand Up @@ -243,10 +247,14 @@ T float_next_imp(const T& val, const std::false_type&, const Policy& pol)

int fpclass = (boost::math::fpclassify)(val);

if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
if (fpclass == (int)FP_INFINITE)
{
if(val < 0)
if (val < 0)
return -tools::max_value<T>();
return val; // +INF
}
else if (fpclass == (int)FP_NAN)
{
return policies::raise_domain_error<T>(
function,
"Argument must be finite, but got %1%", val, pol);
Expand Down Expand Up @@ -328,10 +336,14 @@ T float_prior_imp(const T& val, const std::true_type&, const Policy& pol)

int fpclass = (boost::math::fpclassify)(val);

if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
if (fpclass == (int)FP_INFINITE)
{
if(val > 0)
if (val > 0)
return tools::max_value<T>();
return val; // -INF
}
else if (fpclass == (int)FP_NAN)
{
return policies::raise_domain_error<T>(
function,
"Argument must be finite, but got %1%", val, pol);
Expand Down Expand Up @@ -378,10 +390,14 @@ T float_prior_imp(const T& val, const std::false_type&, const Policy& pol)

int fpclass = (boost::math::fpclassify)(val);

if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
if (fpclass == (int)FP_INFINITE)
{
if(val > 0)
if (val > 0)
return tools::max_value<T>();
return val; // -INF
}
else if (fpclass == (int)FP_NAN)
{
return policies::raise_domain_error<T>(
function,
"Argument must be finite, but got %1%", val, pol);
Expand Down
11 changes: 8 additions & 3 deletions test/test_next.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,12 @@ void test_values(const T& val, const char* name)
BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1);
BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2);
}
if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
BOOST_IF_CONSTEXPR(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
{
BOOST_CHECK_EQUAL(boost::math::float_prior(std::numeric_limits<T>::infinity()), (std::numeric_limits<T>::max)());
BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits<T>::infinity()), -(std::numeric_limits<T>::max)());
BOOST_MATH_CHECK_THROW(boost::math::float_prior(-std::numeric_limits<T>::infinity()), std::domain_error);
BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits<T>::infinity()), std::domain_error);
BOOST_CHECK_EQUAL(boost::math::float_prior(-std::numeric_limits<T>::infinity()), -std::numeric_limits<T>::infinity());
BOOST_CHECK_EQUAL(boost::math::float_next(std::numeric_limits<T>::infinity()), std::numeric_limits<T>::infinity());
if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error)
{
BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits<T>::max)()), std::overflow_error);
Expand All @@ -188,6 +188,11 @@ void test_values(const T& val, const char* name)
BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits<T>::max)()), std::numeric_limits<T>::infinity());
}
}
BOOST_IF_CONSTEXPR(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_quiet_NaN))
{
BOOST_MATH_CHECK_THROW(boost::math::float_prior((std::numeric_limits<T>::quiet_NaN)()), std::domain_error);
BOOST_MATH_CHECK_THROW(boost::math::float_next((std::numeric_limits<T>::quiet_NaN)()), std::domain_error);
}
//
// We need to test float_distance over multiple orders of magnitude,
// the only way to get an accurate true result is to count the representations
Expand Down
11 changes: 8 additions & 3 deletions test/test_next_decimal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,12 @@ void test_values(const T& val, const char* name)
BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1);
BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2);
}
if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
BOOST_IF_CONSTEXPR(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
{
BOOST_CHECK_EQUAL(boost::math::float_prior(std::numeric_limits<T>::infinity()), (std::numeric_limits<T>::max)());
BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits<T>::infinity()), -(std::numeric_limits<T>::max)());
BOOST_MATH_CHECK_THROW(boost::math::float_prior(-std::numeric_limits<T>::infinity()), std::domain_error);
BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits<T>::infinity()), std::domain_error);
BOOST_CHECK_EQUAL(boost::math::float_prior(-std::numeric_limits<T>::infinity()), -std::numeric_limits<T>::infinity());
BOOST_CHECK_EQUAL(boost::math::float_next(std::numeric_limits<T>::infinity()), std::numeric_limits<T>::infinity());
if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error)
{
BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits<T>::max)()), std::overflow_error);
Expand All @@ -193,6 +193,11 @@ void test_values(const T& val, const char* name)
BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits<T>::max)()), std::numeric_limits<T>::infinity());
}
}
BOOST_IF_CONSTEXPR(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_quiet_NaN))
{
BOOST_MATH_CHECK_THROW(boost::math::float_prior(std::numeric_limits<T>::quiet_NaN()), std::domain_error);
BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits<T>::quiet_NaN()), std::domain_error);
}
}

BOOST_AUTO_TEST_CASE( test_main )
Expand Down

0 comments on commit 52be1ad

Please sign in to comment.