From 729986d13b802f5dec501304840bc3b77222f9f3 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Mon, 31 Aug 2026 22:34:16 -0700 Subject: [PATCH 1/4] Fix hang in 1F1 --- include/boost/math/special_functions/hypergeometric_1F1.hpp | 3 ++- test/test_1F1.cpp | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/boost/math/special_functions/hypergeometric_1F1.hpp b/include/boost/math/special_functions/hypergeometric_1F1.hpp index 5b24c58cd9..ee857183a0 100644 --- a/include/boost/math/special_functions/hypergeometric_1F1.hpp +++ b/include/boost/math/special_functions/hypergeometric_1F1.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -637,7 +638,7 @@ namespace boost { namespace math { namespace detail { static const thread_local long long max_scaling = lltrunc(boost::math::tools::log_max_value()) - 2; static const thread_local T max_scale_factor = exp(T(max_scaling)); - while (log_scaling > max_scaling) + while (!(boost::math::isinf)(result) && (log_scaling > max_scaling)) { result *= max_scale_factor; log_scaling -= max_scaling; diff --git a/test/test_1F1.cpp b/test/test_1F1.cpp index 8ffd7aad40..4a26657033 100644 --- a/test/test_1F1.cpp +++ b/test/test_1F1.cpp @@ -196,6 +196,10 @@ BOOST_AUTO_TEST_CASE( test_main ) #endif #endif #if !defined(TEST) || (TEST == 3) + // https://github.com/boostorg/math/issues/1288 + BOOST_CHECK_EQUAL(boost::math::hypergeometric_1F1(2.0, 3.0, 1e30), + (std::numeric_limits::infinity)()); + test_spots(0.0, "double"); #endif #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS From a35457a862b92ae672120cec2a8c2498659e241f Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 2 Sep 2026 14:02:58 +0100 Subject: [PATCH 2/4] 1F1: move fix higher up the evaluation chain. Add extra test case. Move existing test case next to the other bug cases. --- .../math/special_functions/detail/hypergeometric_asym.hpp | 4 +++- test/test_1F1.cpp | 4 ---- test/test_1F1.hpp | 7 +++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/boost/math/special_functions/detail/hypergeometric_asym.hpp b/include/boost/math/special_functions/detail/hypergeometric_asym.hpp index e603957180..41a565854d 100644 --- a/include/boost/math/special_functions/detail/hypergeometric_asym.hpp +++ b/include/boost/math/special_functions/detail/hypergeometric_asym.hpp @@ -44,8 +44,10 @@ } else { - e = z > static_cast((std::numeric_limits::max)()) ? (std::numeric_limits::max)() : lltrunc(z, pol); + e = z >= static_cast((std::numeric_limits::max)()) ? (std::numeric_limits::max)() : lltrunc(z, pol); log_scaling += e; + if (z - e > tools::log_max_value()) + return policies::raise_overflow_error(function, nullptr, pol); prefix = exp(z - e); } if ((fabs(a) < 10) && (fabs(b) < 10)) diff --git a/test/test_1F1.cpp b/test/test_1F1.cpp index 4a26657033..8ffd7aad40 100644 --- a/test/test_1F1.cpp +++ b/test/test_1F1.cpp @@ -196,10 +196,6 @@ BOOST_AUTO_TEST_CASE( test_main ) #endif #endif #if !defined(TEST) || (TEST == 3) - // https://github.com/boostorg/math/issues/1288 - BOOST_CHECK_EQUAL(boost::math::hypergeometric_1F1(2.0, 3.0, 1e30), - (std::numeric_limits::infinity)()); - test_spots(0.0, "double"); #endif #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS diff --git a/test/test_1F1.hpp b/test/test_1F1.hpp index b4c67faf1a..527acb9d81 100644 --- a/test/test_1F1.hpp +++ b/test/test_1F1.hpp @@ -420,6 +420,13 @@ void test_spots6(T, const char* type_name) T val = boost::math::hypergeometric_1F1(hypergeometric_1F1_big_bugs[i][0], hypergeometric_1F1_big_bugs[i][1], hypergeometric_1F1_big_bugs[i][2]); BOOST_CHECK((boost::math::isinf)(val)); } + // https://github.com/boostorg/math/issues/1288 + BOOST_CHECK_EQUAL(boost::math::hypergeometric_1F1(SC_(2.0), SC_(3.0), SC_(1e30)), + (std::numeric_limits::infinity)()); + // This is the largest log_hypergeometric_1F1 we can currently compute, beyond this the fix for the above + // bug causes premature overflow. However, there is no easy fix and Wolfram also fails in this case. It's **hard** :( + BOOST_CHECK_CLOSE_FRACTION(boost::math::log_hypergeometric_1F1(SC_(2.0), SC_(3.0), SC_(std::numeric_limits::max())), + SC_(9223372036854775765.02487480528339082), boost::math::tools::epsilon() * 10); } } From d09a87151e59207fd6921f00fdac7c8693a4817c Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 2 Sep 2026 16:00:28 +0100 Subject: [PATCH 3/4] 1F1: Correct macro usage. --- test/test_1F1.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_1F1.hpp b/test/test_1F1.hpp index 527acb9d81..abaeffb547 100644 --- a/test/test_1F1.hpp +++ b/test/test_1F1.hpp @@ -425,7 +425,7 @@ void test_spots6(T, const char* type_name) (std::numeric_limits::infinity)()); // This is the largest log_hypergeometric_1F1 we can currently compute, beyond this the fix for the above // bug causes premature overflow. However, there is no easy fix and Wolfram also fails in this case. It's **hard** :( - BOOST_CHECK_CLOSE_FRACTION(boost::math::log_hypergeometric_1F1(SC_(2.0), SC_(3.0), SC_(std::numeric_limits::max())), + BOOST_CHECK_CLOSE_FRACTION(boost::math::log_hypergeometric_1F1(SC_(2.0), SC_(3.0), static_cast(std::numeric_limits::max())), SC_(9223372036854775765.02487480528339082), boost::math::tools::epsilon() * 10); } } From c2da3c644b8236ecdba15011ac71d1bfb07e5e2d Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 2 Sep 2026 19:12:57 +0100 Subject: [PATCH 4/4] 1F1 tests: Fix min/max usage. --- test/test_1F1.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_1F1.hpp b/test/test_1F1.hpp index abaeffb547..9333480245 100644 --- a/test/test_1F1.hpp +++ b/test/test_1F1.hpp @@ -425,7 +425,7 @@ void test_spots6(T, const char* type_name) (std::numeric_limits::infinity)()); // This is the largest log_hypergeometric_1F1 we can currently compute, beyond this the fix for the above // bug causes premature overflow. However, there is no easy fix and Wolfram also fails in this case. It's **hard** :( - BOOST_CHECK_CLOSE_FRACTION(boost::math::log_hypergeometric_1F1(SC_(2.0), SC_(3.0), static_cast(std::numeric_limits::max())), + BOOST_CHECK_CLOSE_FRACTION(boost::math::log_hypergeometric_1F1(SC_(2.0), SC_(3.0), static_cast((std::numeric_limits::max)())), SC_(9223372036854775765.02487480528339082), boost::math::tools::epsilon() * 10); } }