Skip to content

Commit 6e5ba9a

Browse files
cohomologydedekindring
authored andcommitted
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 boostorg#1249.
1 parent 529f3a7 commit 6e5ba9a

File tree

3 files changed

+138
-5
lines changed

3 files changed

+138
-5
lines changed

include/boost/math/special_functions/gamma.hpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ BOOST_MATH_GPU_ENABLED T full_igamma_prefix(T a, T z, const Policy& pol)
908908
{
909909
BOOST_MATH_STD_USING
910910

911-
if (z > tools::max_value<T>())
911+
if (z > tools::max_value<T>() || (a > 0 && z == 0))
912912
return 0;
913913

914914
T alz = a * log(z);
@@ -962,7 +962,7 @@ template <class T, class Policy, class Lanczos>
962962
BOOST_MATH_GPU_ENABLED T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l)
963963
{
964964
BOOST_MATH_STD_USING
965-
if (z >= tools::max_value<T>())
965+
if (z >= tools::max_value<T>() || (a > 0 && z == 0))
966966
return 0;
967967
T agh = a + static_cast<T>(Lanczos::g()) - T(0.5);
968968
T prefix;
@@ -1297,7 +1297,11 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b
12971297

12981298
int eval_method;
12991299

1300-
if(is_int && (x > 0.6))
1300+
if (x == 0)
1301+
{
1302+
eval_method = 8; // do nothing
1303+
}
1304+
else if(is_int && (x > 0.6))
13011305
{
13021306
// calculate Q via finite sum:
13031307
invert = !invert;
@@ -1606,6 +1610,11 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b
16061610
result *= incomplete_tgamma_large_x(a, x, pol);
16071611
break;
16081612
}
1613+
case 8:
1614+
// x is zero, result is zero.
1615+
if (p_derivative)
1616+
*p_derivative = 0;
1617+
break;
16091618
}
16101619

16111620
if(normalised && (result > 1))
@@ -1627,7 +1636,7 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b
16271636
#endif
16281637
result = gam - result;
16291638
}
1630-
if(p_derivative)
1639+
if(p_derivative && x > 0)
16311640
{
16321641
//
16331642
// 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
16601669

16611670
T result = 0; // Just to avoid warning C4701: potentially uninitialized local variable 'result' used
16621671

1663-
if(a >= max_factorial<T>::value && !normalised)
1672+
if(x > 0 && a >= max_factorial<T>::value && !normalised)
16641673
{
16651674
//
16661675
// When we're computing the non-normalized incomplete gamma

test/Jamfile.v2

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ test-suite special_fun :
194194
[ run git_issue_1139.cpp ]
195195
[ run git_issue_1175.cpp ]
196196
[ run git_issue_1194.cpp ]
197+
[ run git_issue_1249.cpp /boost/test//boost_unit_test_framework ]
197198
[ run special_functions_test.cpp /boost/test//boost_unit_test_framework ]
198199
[ run test_airy.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ]
199200
[ run test_bessel_j.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ]

test/git_issue_1249.cpp

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// (C) Copyright Kilian Kilger 2025.
2+
// Use, modification and distribution are subject to the
3+
// Boost Software License, Version 1.0. (See accompanying file
4+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#define BOOST_TEST_MAIN
7+
8+
#include <boost/test/unit_test.hpp>
9+
#include <boost/test/tools/floating_point_comparison.hpp>
10+
#include <boost/test/unit_test.hpp>
11+
#include <boost/test/results_collector.hpp>
12+
#include <boost/math/special_functions/gamma.hpp>
13+
14+
using namespace std;
15+
using namespace boost::math;
16+
using namespace boost::math::policies;
17+
18+
typedef policy<
19+
policies::domain_error<errno_on_error>,
20+
policies::pole_error<errno_on_error>,
21+
policies::overflow_error<errno_on_error>,
22+
policies::evaluation_error<errno_on_error>
23+
> c_policy;
24+
25+
template<typename T>
26+
struct test_lower
27+
{
28+
T operator()(T a, T x) const
29+
{
30+
return tgamma_lower(a, x, c_policy());
31+
}
32+
33+
T expected(T a) const
34+
{
35+
return T(0.0);
36+
}
37+
};
38+
39+
template<typename T>
40+
struct test_upper
41+
{
42+
T operator()(T a, T x) const
43+
{
44+
return tgamma(a, x, c_policy());
45+
}
46+
T expected(T a) const
47+
{
48+
return tgamma(a, c_policy());
49+
}
50+
};
51+
52+
template<typename T>
53+
struct test_gamma_p
54+
{
55+
T operator()(T a, T x) const
56+
{
57+
return gamma_p(a, x, c_policy());
58+
}
59+
T expected(T) const
60+
{
61+
return T(0.0);
62+
}
63+
};
64+
65+
template<typename T>
66+
struct test_gamma_q
67+
{
68+
T operator()(T a, T x) const
69+
{
70+
return gamma_q(a, x, c_policy());
71+
}
72+
T expected(T) const
73+
{
74+
return T(1.0);
75+
}
76+
};
77+
78+
template<typename T, template<typename> class Fun>
79+
void test_impl(T a)
80+
{
81+
Fun<T> fn;
82+
errno = 0;
83+
T x = T(0.0);
84+
T result = fn(a, x);
85+
int saveErrno = errno;
86+
87+
errno = 0;
88+
89+
T expected = fn.expected(a);
90+
91+
BOOST_CHECK(errno == saveErrno);
92+
BOOST_CHECK_EQUAL(result, expected);
93+
}
94+
95+
template<template<typename> class Fun>
96+
void test_type_dispatch(float a)
97+
{
98+
test_impl<float, Fun>(a);
99+
test_impl<double, Fun>(double(a));
100+
test_impl<long double, Fun>(static_cast<long double>(a));
101+
}
102+
103+
template<template<typename> class Fun>
104+
void test_impl()
105+
{
106+
test_type_dispatch<Fun>(1.0);
107+
test_type_dispatch<Fun>(0.1);
108+
test_type_dispatch<Fun>(0.5);
109+
test_type_dispatch<Fun>(0.6);
110+
test_type_dispatch<Fun>(1.3);
111+
test_type_dispatch<Fun>(1.5);
112+
test_type_dispatch<Fun>(2);
113+
test_type_dispatch<Fun>(100);
114+
test_type_dispatch<Fun>(std::numeric_limits<float>::max());
115+
}
116+
117+
BOOST_AUTO_TEST_CASE( test_main )
118+
{
119+
test_impl<test_lower>();
120+
test_impl<test_upper>();
121+
test_impl<test_gamma_p>();
122+
test_impl<test_gamma_q>();
123+
}

0 commit comments

Comments
 (0)