2
0
mirror of https://github.com/boostorg/math.git synced 2026-02-24 16:12:15 +00:00

Merge pull request #1349 from JacobHass8/log-lower-incomplete-gamma

Implementation of the log of the lower incomplete gamma function
This commit is contained in:
jzmaddock
2026-01-25 17:52:43 +00:00
committed by GitHub
9 changed files with 346 additions and 2 deletions

View File

@@ -1290,7 +1290,6 @@ BOOST_MATH_GPU_ENABLED T incomplete_tgamma_large_x(const T& a, const T& x, const
return result;
}
//
// Main incomplete gamma entry point, handles all four incomplete gamma's:
//
@@ -1813,6 +1812,46 @@ BOOST_MATH_GPU_ENABLED T lgamma_incomplete_imp(T a, T x, const Policy& pol)
return log(gamma_q(a, x, pol));
}
// Calculate log of incomplete gamma function
template <class T, class Policy>
BOOST_MATH_GPU_ENABLED T lgamma_incomplete_lower_imp(T a, T x, const Policy& pol)
{
using namespace boost::math; // temporary until we're in the right namespace
BOOST_MATH_STD_USING_CORE
// Check for invalid inputs (a < 0 or x < 0)
constexpr auto function = "boost::math::lgamma_p<%1%>(%1%, %1%)";
if(a <= 0)
return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
if(x < 0)
return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
// Taken from conditions on Line 1709. There are also
// conditions on Line 1368, but didn't implement that one here.
// The second condition ensures floats do not return -inf for small
// values of x.
if (((a > 4 * x) && (a >= max_factorial<T>::value)) || ((T(-0.4) / log(x) < a) && (x < T(1.0)))){
return log(detail::lower_gamma_series(a, x, pol)) - log(a) + a * log(x) - x - lgamma(a, pol);
}
//
// Can't do better than taking the log of P, but...
//
// Figure out whether we need P or Q, since if we calculate P and it's too close to unity
// we will lose precision in the result, selection logic here is extracted from gamma_incomplete_imp_final:
//
bool need_p = false;
if ((x < 1.1) && (x >= 0.5) && (x * 0.75f < a))
need_p = true;
else if ((x < a) && (x >= 1.1))
need_p = true;
if (need_p)
return log(gamma_p(a, x, pol));
return log1p(-gamma_q(a, x, pol), pol);
}
//
// Ratios of two gamma functions:
//
@@ -2454,6 +2493,29 @@ BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2> lgamma_q(T1 a, T2 z)
{
return lgamma_q(a, z, policies::policy<>());
}
template <class T1, class T2, class Policy>
BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2> lgamma_p(T1 a, T2 z, const Policy& /* pol */)
{
typedef tools::promote_args_t<T1, T2> result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::lgamma_incomplete_lower_imp(static_cast<value_type>(a),
static_cast<value_type>(z), forwarding_policy()), "lgamma_p<%1%>(%1%, %1%)");
}
template <class T1, class T2>
BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2> lgamma_p(T1 a, T2 z)
{
return lgamma_p(a, z, policies::policy<>());
}
//
// Regularised lower incomplete gamma:
//

View File

@@ -567,6 +567,12 @@ namespace boost
template <class RT1, class RT2, class Policy>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> lgamma_q(RT1 a, RT2 z, const Policy&);
template <class RT1, class RT2>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> lgamma_p(RT1 a, RT2 z);
template <class RT1, class RT2, class Policy>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> lgamma_p(RT1 a, RT2 z, const Policy&);
template <class RT1, class RT2>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> gamma_p(RT1 a, RT2 z);
@@ -1525,6 +1531,9 @@ namespace boost
\
template <class RT1, class RT2>\
BOOST_MATH_GPU_ENABLED inline boost::math::tools::promote_args_t<RT1, RT2> lgamma_q(RT1 a, RT2 z){ return boost::math::lgamma_q(a, z, Policy()); }\
\
template <class RT1, class RT2>\
BOOST_MATH_GPU_ENABLED inline boost::math::tools::promote_args_t<RT1, RT2> lgamma_p(RT1 a, RT2 z){ return boost::math::lgamma_p(a, z, Policy()); }\
\
template <class RT1, class RT2>\
BOOST_MATH_GPU_ENABLED inline boost::math::tools::promote_args_t<RT1, RT2> gamma_p(RT1 a, RT2 z){ return boost::math::gamma_p(a, z, Policy()); }\