boost/boost-1.83-math-Correct-float_next-INF-and-float_prior-INF.patch
Kefu Chai e13a584ab7 Add patch for addressing a Boost.Math bug
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>
2024-05-25 12:58:19 +08:00

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