Skip to content

Commit 036cf85

Browse files
committed
Merge branch 'mydevelop' of https://github.com/cohomology/math into integrate_1251
2 parents aecd335 + 0d6ff71 commit 036cf85

File tree

3 files changed

+165
-21
lines changed

3 files changed

+165
-21
lines changed

include/boost/math/special_functions/gamma.hpp

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,7 @@ BOOST_MATH_GPU_ENABLED T full_igamma_prefix(T a, T z, const Policy& pol)
934934
{
935935
BOOST_MATH_STD_USING
936936

937-
if (z > tools::max_value<T>())
937+
if (z > tools::max_value<T>() || (a > 0 && z == 0))
938938
return 0;
939939

940940
T alz = a * log(z);
@@ -992,7 +992,7 @@ template <class T, class Policy, class Lanczos>
992992
BOOST_MATH_GPU_ENABLED T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l)
993993
{
994994
BOOST_MATH_STD_USING
995-
if (z >= tools::max_value<T>())
995+
if (z >= tools::max_value<T>() || (a > 0 && z == 0))
996996
return 0;
997997
T agh = a + static_cast<T>(Lanczos::g()) - T(0.5);
998998
T prefix{};
@@ -1321,7 +1321,11 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b
13211321

13221322
int eval_method;
13231323

1324-
if(is_int && (x > 0.6))
1324+
if (x == 0)
1325+
{
1326+
eval_method = 2;
1327+
}
1328+
else if(is_int && (x > 0.6))
13251329
{
13261330
// calculate Q via finite sum:
13271331
invert = !invert;
@@ -1501,14 +1505,14 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b
15011505
#ifdef BOOST_MATH_HAS_NVRTC
15021506
if (boost::math::is_same_v<T, float>)
15031507
{
1504-
init_value = (normalised ? 1 : ::tgammaf(a));
1508+
init_value = (normalised ? T(1) : ::tgammaf(a));
15051509
}
15061510
else
15071511
{
1508-
init_value = (normalised ? 1 : ::tgamma(a));
1512+
init_value = (normalised ? T(1) : ::tgamma(a));
15091513
}
15101514
#else
1511-
init_value = (normalised ? 1 : boost::math::tgamma(a, pol));
1515+
init_value = (normalised ? T(1) : boost::math::tgamma(a, pol));
15121516
#endif
15131517

15141518
if(normalised || (result >= 1) || (tools::max_value<T>() * result > init_value))
@@ -1640,32 +1644,26 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, b
16401644
T gam;
16411645
if (boost::math::is_same_v<T, float>)
16421646
{
1643-
gam = normalised ? 1 : ::tgammaf(a);
1647+
gam = normalised ? T(1) : ::tgammaf(a);
16441648
}
16451649
else
16461650
{
1647-
gam = normalised ? 1 : ::tgamma(a);
1651+
gam = normalised ? T(1) : ::tgamma(a);
16481652
}
16491653
#else
1650-
T gam = normalised ? 1 : boost::math::tgamma(a, pol);
1654+
T gam = normalised ? T(1) : boost::math::tgamma(a, pol);
16511655
#endif
16521656
result = gam - result;
16531657
}
16541658
if(p_derivative)
16551659
{
1656-
/*
1657-
* We can never reach this:
1658-
if((x < 1) && (tools::max_value<T>() * x < *p_derivative))
1660+
if((x == 0) || ((x < 1) && (tools::max_value<T>() * x < *p_derivative)))
16591661
{
16601662
// overflow, just return an arbitrarily large value:
16611663
*p_derivative = tools::max_value<T>() / 2;
16621664
}
1663-
*/
1664-
BOOST_MATH_ASSERT((x >= 1) || (tools::max_value<T>() * x >= *p_derivative));
1665-
//
1666-
// Need to convert prefix term to derivative:
1667-
//
1668-
*p_derivative /= x;
1665+
else
1666+
*p_derivative /= x;
16691667
}
16701668

16711669
return result;
@@ -1687,7 +1685,7 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp(T a, T x, bool normalised, bool in
16871685

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

1690-
if(a >= max_factorial<T>::value && !normalised)
1688+
if(x > 0 && a >= max_factorial<T>::value && !normalised)
16911689
{
16921690
//
16931691
// When we're computing the non-normalized incomplete gamma
@@ -2143,8 +2141,8 @@ BOOST_MATH_GPU_ENABLED T gamma_p_derivative_imp(T a, T x, const Policy& pol)
21432141
//
21442142
if(x == 0)
21452143
{
2146-
return (a > 1) ? 0 :
2147-
(a == 1) ? 1 : policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
2144+
return (a > 1) ? T(0) :
2145+
(a == 1) ? T(1) : policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
21482146
}
21492147
//
21502148
// Normal case:

test/Jamfile.v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ test-suite special_fun :
196196
[ run git_issue_1139.cpp ]
197197
[ run git_issue_1175.cpp ]
198198
[ run git_issue_1194.cpp ]
199+
[ run git_issue_1249.cpp /boost/test//boost_unit_test_framework ]
199200
[ run git_issue_1255.cpp ]
200201
[ run git_issue_1247.cpp ]
201202
[ run special_functions_test.cpp /boost/test//boost_unit_test_framework ]

test/git_issue_1249.cpp

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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+
#include <boost/multiprecision/cpp_bin_float.hpp>
14+
15+
using namespace std;
16+
using namespace boost::math;
17+
using namespace boost::math::policies;
18+
using namespace boost::multiprecision;
19+
20+
typedef policy<
21+
policies::domain_error<errno_on_error>,
22+
policies::pole_error<errno_on_error>,
23+
policies::overflow_error<errno_on_error>,
24+
policies::evaluation_error<errno_on_error>
25+
> c_policy;
26+
27+
template<typename T>
28+
struct test_lower
29+
{
30+
T operator()(T a, T x) const
31+
{
32+
return tgamma_lower(a, x, c_policy());
33+
}
34+
35+
T expected(T a) const
36+
{
37+
return T(0.0);
38+
}
39+
};
40+
41+
template<typename T>
42+
struct test_upper
43+
{
44+
T operator()(T a, T x) const
45+
{
46+
return tgamma(a, x, c_policy());
47+
}
48+
T expected(T a) const
49+
{
50+
return tgamma(a, c_policy());
51+
}
52+
};
53+
54+
template<typename T>
55+
struct test_gamma_p
56+
{
57+
T operator()(T a, T x) const
58+
{
59+
return gamma_p(a, x, c_policy());
60+
}
61+
T expected(T) const
62+
{
63+
return T(0.0);
64+
}
65+
};
66+
67+
template<typename T>
68+
struct test_gamma_q
69+
{
70+
T operator()(T a, T x) const
71+
{
72+
return gamma_q(a, x, c_policy());
73+
}
74+
T expected(T) const
75+
{
76+
return T(1.0);
77+
}
78+
};
79+
80+
template<typename T, template<typename> class Fun>
81+
void test_impl(T a)
82+
{
83+
Fun<T> fn;
84+
errno = 0;
85+
T x = T(0.0);
86+
T result = fn(a, x);
87+
int saveErrno = errno;
88+
89+
errno = 0;
90+
91+
T expected = fn.expected(a);
92+
93+
BOOST_CHECK(errno == saveErrno);
94+
BOOST_CHECK_EQUAL(result, expected);
95+
}
96+
97+
template<template<typename> class Fun, typename T>
98+
void test_type_dispatch(T val)
99+
{
100+
if (val <= (std::numeric_limits<float>::max)())
101+
test_impl<float, Fun>(static_cast<float>(val));
102+
if (val <= (std::numeric_limits<double>::max)())
103+
test_impl<double, Fun>(static_cast<double>(val));
104+
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
105+
test_impl<long double, Fun>(static_cast<long double>(val));
106+
#endif
107+
test_impl<cpp_bin_float_50, Fun>(static_cast<cpp_bin_float_50>(val));
108+
}
109+
110+
template<template<typename> class Fun>
111+
void test_impl()
112+
{
113+
test_type_dispatch<Fun, double>(1.0);
114+
test_type_dispatch<Fun, double>(0.1);
115+
test_type_dispatch<Fun, double>(0.5);
116+
test_type_dispatch<Fun, double>(0.6);
117+
test_type_dispatch<Fun, double>(1.3);
118+
test_type_dispatch<Fun, double>(1.5);
119+
test_type_dispatch<Fun, double>(2);
120+
test_type_dispatch<Fun, double>(100);
121+
test_type_dispatch<Fun, double>((std::numeric_limits<float>::max)());
122+
test_type_dispatch<Fun, double>((std::numeric_limits<double>::max)());
123+
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
124+
test_type_dispatch<Fun, long double>((std::numeric_limits<long double>::max)());
125+
#endif
126+
}
127+
128+
void test_derivative()
129+
{
130+
using namespace boost::math::detail;
131+
double derivative = 0;
132+
double result = gamma_incomplete_imp(1.0, 0.0, true, false, c_policy(), &derivative);
133+
BOOST_CHECK(errno == 0);
134+
BOOST_CHECK_EQUAL(derivative, tools::max_value<double>() / 2);
135+
BOOST_CHECK_EQUAL(result, 0);
136+
}
137+
138+
BOOST_AUTO_TEST_CASE( test_main )
139+
{
140+
test_impl<test_lower>();
141+
test_impl<test_upper>();
142+
test_impl<test_gamma_p>();
143+
test_impl<test_gamma_q>();
144+
test_derivative();
145+
}

0 commit comments

Comments
 (0)