diff --git a/include/boost/math/special_functions/gamma.hpp b/include/boost/math/special_functions/gamma.hpp index 41c85936dd..4a15782c01 100644 --- a/include/boost/math/special_functions/gamma.hpp +++ b/include/boost/math/special_functions/gamma.hpp @@ -197,25 +197,30 @@ BOOST_MATH_GPU_ENABLED BOOST_MATH_FORCEINLINE T gamma_imp(T z, const Policy& pol { BOOST_MATH_STD_USING - if(z <= -20) - { - constexpr auto function = "boost::math::tgamma<%1%>(%1%)"; - T result = gamma_imp_final(T(-z), pol, l) * sinpx(z); - BOOST_MATH_INSTRUMENT_VARIABLE(result); - if((fabs(result) < 1) && (tools::max_value() * fabs(result) < boost::math::constants::pi())) - return -boost::math::sign(result) * policies::raise_overflow_error(function, "Result of tgamma is too large to represent.", pol); - result = -boost::math::constants::pi() / result; - if(result == 0) - return policies::raise_underflow_error(function, "Result of tgamma is too small to represent.", pol); - if((boost::math::fpclassify)(result) == (int)BOOST_MATH_FP_SUBNORMAL) - return policies::raise_denorm_error(function, "Result of tgamma is denormalized.", result, pol); - BOOST_MATH_INSTRUMENT_VARIABLE(result); - return result; - } - else + T result = 1; + constexpr auto function = "boost::math::tgamma<%1%>(%1%)"; + + if(z <= 0) { - return gamma_imp_final(T(z), pol, l); + if(floor(z) == z) + return policies::raise_pole_error(function, "Evaluation of tgamma at a negative integer %1%.", z, pol); + if(z <= -20) + { + result = gamma_imp_final(T(-z), pol, l) * sinpx(z); + BOOST_MATH_INSTRUMENT_VARIABLE(result); + if((fabs(result) < 1) && (tools::max_value() * fabs(result) < boost::math::constants::pi())) + return -boost::math::sign(result) * policies::raise_overflow_error(function, "Result of tgamma is too large to represent.", pol); + result = -boost::math::constants::pi() / result; + if(result == 0) + return policies::raise_underflow_error(function, "Result of tgamma is too small to represent.", pol); + if((boost::math::fpclassify)(result) == BOOST_MATH_FP_SUBNORMAL) + return policies::raise_denorm_error(function, "Result of tgamma is denormalized.", result, pol); + BOOST_MATH_INSTRUMENT_VARIABLE(result); + return result; + } } + + return gamma_imp_final(T(z), pol, l); } #ifdef BOOST_MATH_ENABLE_CUDA diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e19957777e..4adb29d160 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -193,6 +193,7 @@ test-suite special_fun : [ run git_issue_1137.cpp ] [ run git_issue_1139.cpp ] [ run git_issue_1175.cpp ] + [ run git_issue_1194.cpp ] [ 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_1194.cpp b/test/git_issue_1194.cpp new file mode 100644 index 0000000000..1c364a0c4d --- /dev/null +++ b/test/git_issue_1194.cpp @@ -0,0 +1,41 @@ +// (C) Copyright Matt Borland 2024. +// 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) + +#include "math_unit_test.hpp" +#include +#include + +int main() +{ + using c99_error_policy = ::boost::math::policies::policy< + ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>, + ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>, + ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>, + ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>, + ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error> >; + + double val = -std::numeric_limits::infinity(); + + val = boost::math::tgamma(val, c99_error_policy()); + CHECK_EQUAL(errno, EDOM); + + val = std::numeric_limits::quiet_NaN(); + val = boost::math::tgamma(val, c99_error_policy()); + CHECK_EQUAL(errno, EDOM); + + val = std::numeric_limits::infinity(); + val = boost::math::tgamma(val, c99_error_policy()); + CHECK_EQUAL(errno, ERANGE); + + val = 0; + val = boost::math::tgamma(val, c99_error_policy()); + CHECK_EQUAL(errno, EDOM); // OK + + val = -2; + val = boost::math::tgamma(val, c99_error_policy()); + CHECK_EQUAL(errno, EDOM); // OK + + return boost::math::test::report_errors(); +}