This change addresses the issue of
https://github.com/boostorg/math/issues/1132
the patch addresses the issue where float_next() and float_prior() return
a domain error instead +INF or -INF. this issue is a regression in
Boost 1.79.
Signed-off-by: Kefu Chai <tchaikov@gmail.com>
(cherry picked from commit e13a584ab7)
118 lines
5 KiB
Diff
118 lines
5 KiB
Diff
From f3e0cde514e444c2e25a3522d05a6e244fb2f23a Mon Sep 17 00:00:00 2001
|
|
From: jzmaddock <john@johnmaddock.co.uk>
|
|
Date: Fri, 17 May 2024 19:17:04 +0100
|
|
Subject: [PATCH 1/2] Correct float_next(+INF) and float_prior(-INF) Fixes
|
|
https://github.com/boostorg/math/issues/1132
|
|
|
|
---
|
|
include/boost/math/special_functions/next.hpp | 32 ++++++++++++++-----
|
|
test/test_next.cpp | 11 +++++--
|
|
2 files changed, 32 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp
|
|
index c696b97b5..02a208e4e 100644
|
|
--- a/boost/math/special_functions/next.hpp
|
|
+++ b/boost/math/special_functions/next.hpp
|
|
@@ -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);
|
|
@@ -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);
|
|
@@ -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);
|
|
@@ -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);
|
|
diff --git a/test/test_next.cpp b/test/test_next.cpp
|
|
index b4f05b437..8bb5f8d99 100644
|
|
--- a/libs/math/test/test_next.cpp
|
|
+++ b/libs/math/test/test_next.cpp
|
|
@@ -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);
|
|
@@ -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
|
|
--
|
|
2.45.1
|
|
|