/* rgamma.c | |
* | |
* Reciprocal Gamma function | |
* | |
* | |
* | |
* SYNOPSIS: | |
* | |
* double x, y, rgamma(); | |
* | |
* y = rgamma( x ); | |
* | |
* | |
* | |
* DESCRIPTION: | |
* | |
* Returns one divided by the Gamma function of the argument. | |
* | |
* The function is approximated by a Chebyshev expansion in | |
* the interval [0,1]. Range reduction is by recurrence | |
* for arguments between -34.034 and +34.84425627277176174. | |
* 0 is returned for positive arguments outside this | |
* range. For arguments less than -34.034 the cosecant | |
* reflection formula is applied; lograrithms are employed | |
* to avoid unnecessary overflow. | |
* | |
* The reciprocal Gamma function has no singularities, | |
* but overflow and underflow may occur for large arguments. | |
* These conditions return either INFINITY or 0 with | |
* appropriate sign. | |
* | |
* ACCURACY: | |
* | |
* Relative error: | |
* arithmetic domain # trials peak rms | |
* IEEE -30,+30 30000 1.1e-15 2.0e-16 | |
* For arguments less than -34.034 the peak error is on the | |
* order of 5e-15 (DEC), excepting overflow or underflow. | |
*/ | |
/* | |
* Cephes Math Library Release 2.0: April, 1987 | |
* Copyright 1985, 1987 by Stephen L. Moshier | |
* Direct inquiries to 30 Frost Street, Cambridge, MA 02140 | |
*/ | |
namespace xsf { | |
namespace cephes { | |
namespace detail { | |
/* Chebyshev coefficients for reciprocal Gamma function | |
* in interval 0 to 1. Function is 1/(x Gamma(x)) - 1 | |
*/ | |
constexpr double rgamma_R[] = { | |
3.13173458231230000000E-17, -6.70718606477908000000E-16, 2.20039078172259550000E-15, | |
2.47691630348254132600E-13, -6.60074100411295197440E-12, 5.13850186324226978840E-11, | |
1.08965386454418662084E-9, -3.33964630686836942556E-8, 2.68975996440595483619E-7, | |
2.96001177518801696639E-6, -8.04814124978471142852E-5, 4.16609138709688864714E-4, | |
5.06579864028608725080E-3, -6.41925436109158228810E-2, -4.98558728684003594785E-3, | |
1.27546015610523951063E-1}; | |
} // namespace detail | |
XSF_HOST_DEVICE double rgamma(double x) { | |
double w, y, z; | |
if (x == 0) { | |
// This case is separate from below to get correct sign for zero. | |
return x; | |
} | |
if (x < 0 && x == std::floor(x)) { | |
// Gamma poles. | |
return 0.0; | |
} | |
if (std::abs(x) > 4.0) { | |
return 1.0 / Gamma(x); | |
} | |
z = 1.0; | |
w = x; | |
while (w > 1.0) { /* Downward recurrence */ | |
w -= 1.0; | |
z *= w; | |
} | |
while (w < 0.0) { /* Upward recurrence */ | |
z /= w; | |
w += 1.0; | |
} | |
if (w == 0.0) /* Nonpositive integer */ | |
return (0.0); | |
if (w == 1.0) /* Other integer */ | |
return (1.0 / z); | |
y = w * (1.0 + chbevl(4.0 * w - 2.0, detail::rgamma_R, 16)) / z; | |
return (y); | |
} | |
} // namespace cephes | |
} // namespace xsf | |