From f400fcff5572f06246bed003dea686a072b83547 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Sat, 3 Jan 2026 14:12:31 +0000 Subject: [PATCH] Simplify lgamma_q internal selection logic. Add more tests where the logic changes method for large a,x. --- include/boost/math/special_functions/gamma.hpp | 2 +- test/test_igamma.hpp | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/boost/math/special_functions/gamma.hpp b/include/boost/math/special_functions/gamma.hpp index dede0dbf4..3e2642abe 100644 --- a/include/boost/math/special_functions/gamma.hpp +++ b/include/boost/math/special_functions/gamma.hpp @@ -1787,7 +1787,7 @@ T lgamma_incomplete_imp(T a, T x, const Policy& pol) if(x < 0) return policies::raise_domain_error(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol); - if (((x > 1000) && ((a < x) || (fabs(a - 50) / x < 1))) || ((x > tools::log_max_value() - 10) && (x > a))) + if (((x > 1000) || (x > tools::log_max_value() - 10)) && (a + 50 < x)) { // // Take the logarithmic version of the asymtotic expansion: diff --git a/test/test_igamma.hpp b/test/test_igamma.hpp index 93ffce2cb..c72cd962c 100644 --- a/test/test_igamma.hpp +++ b/test/test_igamma.hpp @@ -265,7 +265,22 @@ void test_spots(T) BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(20), static_cast(0.25)), static_cast(-2.946458104491857816330873290969917497748067639461638294404e-31L), tolerance); BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(40), static_cast(0.75)), static_cast(-5.930604927955460343652485525435087275997461623988991819824e-54L), tolerance); BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(50), static_cast(2)), static_cast(-5.214301903317168085381693412994550732094621576607843973832e-51L), tolerance); - BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(20), static_cast(999)), static_cast(-907.0923609280941476865481041233627829242287760441299044050137514L), tolerance); + // Pairs of tests that bisect the crossover condition in our code at double and then quad precision: + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(10), static_cast(698.75)), static_cast(-652.5952453102824132865663191324423994628428404928732148525545721L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(10), static_cast(699.25)), static_cast(-653.0888168445921483147208556398158677077537551419551652934287016L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(10), static_cast(999.75)), static_cast(-950.3752463850600415679327136010171192193400042422096029239012176L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(10), static_cast(1000.25)), static_cast(-950.8707509166152482936275883547176592196662090187561681198668099L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(50), static_cast(698.75)), static_cast(-522.3277960730837166223131189587863209730608668858212533099139269L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(50), static_cast(699.25)), static_cast(-522.7927997457481265511084805522296021540768033975669071565674196L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(50), static_cast(999.75)), static_cast(-805.7977867938474339107474131612354353193501692041340771552419902L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(50), static_cast(1000.25)), static_cast(-806.2733124989172792095030711884568388681331032891850662521501582L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(800), static_cast(999.75)), static_cast(-24.33274293617739453303937714319703386675839030466670622049929011L), tolerance); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(800), static_cast(1000.25)), static_cast(-24.43514173634027477093666725985191846106997808357863808910970142L), tolerance); + // Once we get large a,x then error start to accumulate no matter what we do: + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(1200), static_cast(1249.75)), static_cast(-2.565496161584661216769813239648606145255794643472303927896044375L), tolerance * (std::is_floating_point::value ? 1 : 2)); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(1200), static_cast(1250.25)), static_cast(-2.591934862117586205519309712218581885256650074210410262843591453L), tolerance * (std::is_same::value ? 1 : 50)); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(2200), static_cast(2249.75)), static_cast(-1.933779894897391651410597618307863427927461116308937004149240320L), tolerance * (std::is_floating_point::value ? 1 : 10)); + BOOST_CHECK_CLOSE(::boost::math::lgamma_q(static_cast(2200), static_cast(2250.25)), static_cast(-1.950346484067948344620463026377077515919992808640737320057812268L), tolerance * (std::is_same::value ? 1 : (std::is_floating_point::value ? 50 : 100))); // // Coverage: //