Skip to content

Commit 9086171

Browse files
committed
Implemented large a series expansion
1 parent 1d670c8 commit 9086171

File tree

1 file changed

+66
-0
lines changed
  • include/boost/math/special_functions

1 file changed

+66
-0
lines changed

include/boost/math/special_functions/gamma.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,33 @@ BOOST_MATH_GPU_ENABLED T incomplete_tgamma_large_x(const T& a, const T& x, const
12901290
return result;
12911291
}
12921292

1293+
template <class T>
1294+
struct incomplete_tgamma_lower_large_a_series
1295+
{
1296+
typedef T result_type;
1297+
BOOST_MATH_GPU_ENABLED incomplete_tgamma_lower_large_a_series(const T& a, const T& x)
1298+
: a_poch(a + 1), z(x), term(1 / a) {}
1299+
BOOST_MATH_GPU_ENABLED T operator()()
1300+
{
1301+
T result = term;
1302+
term *= z / a_poch;
1303+
a_poch += 1;
1304+
return result;
1305+
}
1306+
T a_poch, z, term;
1307+
};
1308+
1309+
template <class T, class Policy>
1310+
T incomplete_tgamma_lower_large_a(const T& a, const T&x, const Policy & pol)
1311+
{
1312+
BOOST_MATH_STD_USING
1313+
incomplete_tgamma_lower_large_a_series<T> s(a, x);
1314+
boost::math::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
1315+
T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
1316+
boost::math::policies::check_series_iterations<T>("boost::math::tgamma_p<%1%>(%1%,%1%)", max_iter, pol);
1317+
return result;
1318+
}
1319+
12931320

12941321
//
12951322
// Main incomplete gamma entry point, handles all four incomplete gamma's:
@@ -1813,6 +1840,45 @@ BOOST_MATH_GPU_ENABLED T lgamma_incomplete_imp(T a, T x, const Policy& pol)
18131840
return log(gamma_q(a, x, pol));
18141841
}
18151842

1843+
// Calculate log of incomplete gamma function
1844+
template <class T, class Policy>
1845+
BOOST_MATH_GPU_ENABLED T lgamma_incomplete_lower_imp(T a, T x, const Policy& pol)
1846+
{
1847+
using namespace boost::math; // temporary until we're in the right namespace
1848+
1849+
BOOST_MATH_STD_USING_CORE
1850+
1851+
// Check for invalid inputs (a < 0 or x < 0)
1852+
constexpr auto function = "boost::math::lgamma_p<%1%>(%1%, %1%)";
1853+
if(a <= 0)
1854+
return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
1855+
if(x < 0)
1856+
return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
1857+
1858+
// Need to change this to be more appropriate!
1859+
if (a > 100){
1860+
return log(detail::incomplete_tgamma_lower_large_a(a, x, pol)) + a * log(x) - x - lgamma(a, pol);
1861+
}
1862+
1863+
//
1864+
// Can't do better than taking the log of P, but...
1865+
//
1866+
// Figure out whether we need P or Q, since if we calculate P and it's too close to unity
1867+
// we will lose precision in the result, selection logic here is extracted from gamma_incomplete_imp_final:
1868+
//
1869+
bool need_p = false;
1870+
if ((x < 0.5) && (T(-0.4) / log(x) < a))
1871+
need_p = true;
1872+
else if ((x < 1.1) && (x >= 0.5) && (x * 0.75f < a))
1873+
need_p = true;
1874+
else if ((x < a) && (x >= 1.1))
1875+
need_p = true;
1876+
1877+
if (need_p)
1878+
return log(gamma_p(a, x, pol));
1879+
return log1p(-gamma_q(a, x, pol), pol);
1880+
}
1881+
18161882
//
18171883
// Ratios of two gamma functions:
18181884
//

0 commit comments

Comments
 (0)