From 613911ab54dd98e60265169e6c692bf84b66c4b8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 16 Dec 2024 09:36:30 -0500 Subject: [PATCH 1/2] Update library version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7965bd1ea9..e26692741a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.5...3.16) -project(boost_math VERSION 1.87.0 LANGUAGES CXX) +project(boost_math VERSION 1.88.0 LANGUAGES CXX) add_library(boost_math INTERFACE) From 6e5ba9afbbabd275206a08f0126f6249ebe01886 Mon Sep 17 00:00:00 2001 From: Kilian Kilger Date: Tue, 1 Apr 2025 21:18:02 +0200 Subject: [PATCH 2/2] Fix lower incomplete gamma functions with x = 0 In this case, the errno error handling did not work correctly, as internal functions where accidently setting it, although no overflow happens. Fixes #1249. --- .../boost/math/special_functions/gamma.hpp | 19 ++- test/Jamfile.v2 | 1 + test/git_issue_1249.cpp | 123 ++++++++++++++++++ 3 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 test/git_issue_1249.cpp diff --git a/include/boost/math/special_functions/gamma.hpp b/include/boost/math/special_functions/gamma.hpp index 809d610c18..aeb5c499fc 100644 --- a/include/boost/math/special_functions/gamma.hpp +++ b/include/boost/math/special_functions/gamma.hpp @@ -908,7 +908,7 @@ BOOST_MATH_GPU_ENABLED T full_igamma_prefix(T a, T z, const Policy& pol) { BOOST_MATH_STD_USING - if (z > tools::max_value()) + if (z > tools::max_value() || (a > 0 && z == 0)) return 0; T alz = a * log(z); @@ -962,7 +962,7 @@ template BOOST_MATH_GPU_ENABLED T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l) { BOOST_MATH_STD_USING - if (z >= tools::max_value()) + if (z >= tools::max_value() || (a > 0 && z == 0)) return 0; T agh = a + static_cast(Lanczos::g()) - T(0.5); T prefix; @@ -1297,7 +1297,11 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b int eval_method; - if(is_int && (x > 0.6)) + if (x == 0) + { + eval_method = 8; // do nothing + } + else if(is_int && (x > 0.6)) { // calculate Q via finite sum: invert = !invert; @@ -1606,6 +1610,11 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b result *= incomplete_tgamma_large_x(a, x, pol); break; } + case 8: + // x is zero, result is zero. + if (p_derivative) + *p_derivative = 0; + break; } if(normalised && (result > 1)) @@ -1627,7 +1636,7 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b #endif result = gam - result; } - if(p_derivative) + if(p_derivative && x > 0) { // // Need to convert prefix term to derivative: @@ -1660,7 +1669,7 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp(T a, T x, bool normalised, bool in T result = 0; // Just to avoid warning C4701: potentially uninitialized local variable 'result' used - if(a >= max_factorial::value && !normalised) + if(x > 0 && a >= max_factorial::value && !normalised) { // // When we're computing the non-normalized incomplete gamma diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4adb29d160..8a4ffb3725 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -194,6 +194,7 @@ test-suite special_fun : [ run git_issue_1139.cpp ] [ run git_issue_1175.cpp ] [ run git_issue_1194.cpp ] + [ run git_issue_1249.cpp /boost/test//boost_unit_test_framework ] [ run special_functions_test.cpp /boost/test//boost_unit_test_framework ] [ run test_airy.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ] [ run test_bessel_j.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ] diff --git a/test/git_issue_1249.cpp b/test/git_issue_1249.cpp new file mode 100644 index 0000000000..84451a1839 --- /dev/null +++ b/test/git_issue_1249.cpp @@ -0,0 +1,123 @@ +// (C) Copyright Kilian Kilger 2025. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MAIN + +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost::math; +using namespace boost::math::policies; + +typedef policy< + policies::domain_error, + policies::pole_error, + policies::overflow_error, + policies::evaluation_error +> c_policy; + +template +struct test_lower +{ + T operator()(T a, T x) const + { + return tgamma_lower(a, x, c_policy()); + } + + T expected(T a) const + { + return T(0.0); + } +}; + +template +struct test_upper +{ + T operator()(T a, T x) const + { + return tgamma(a, x, c_policy()); + } + T expected(T a) const + { + return tgamma(a, c_policy()); + } +}; + +template +struct test_gamma_p +{ + T operator()(T a, T x) const + { + return gamma_p(a, x, c_policy()); + } + T expected(T) const + { + return T(0.0); + } +}; + +template +struct test_gamma_q +{ + T operator()(T a, T x) const + { + return gamma_q(a, x, c_policy()); + } + T expected(T) const + { + return T(1.0); + } +}; + +template class Fun> +void test_impl(T a) +{ + Fun fn; + errno = 0; + T x = T(0.0); + T result = fn(a, x); + int saveErrno = errno; + + errno = 0; + + T expected = fn.expected(a); + + BOOST_CHECK(errno == saveErrno); + BOOST_CHECK_EQUAL(result, expected); +} + +template class Fun> +void test_type_dispatch(float a) +{ + test_impl(a); + test_impl(double(a)); + test_impl(static_cast(a)); +} + +template class Fun> +void test_impl() +{ + test_type_dispatch(1.0); + test_type_dispatch(0.1); + test_type_dispatch(0.5); + test_type_dispatch(0.6); + test_type_dispatch(1.3); + test_type_dispatch(1.5); + test_type_dispatch(2); + test_type_dispatch(100); + test_type_dispatch(std::numeric_limits::max()); +} + +BOOST_AUTO_TEST_CASE( test_main ) +{ + test_impl(); + test_impl(); + test_impl(); + test_impl(); +} \ No newline at end of file