// R file: lgammacor.c private static double lgammacor(double x) { double tmp; /* For IEEE double precision DBL_EPSILON = 2^-52 = 2.220446049250313e-16 : * xbig = 2 ^ 26.5 * xmax = DBL_MAX / 48 = 2^1020 / 3 */ int nalgm = 5; double xbig = 94906265.62425156, xmax = 3.745194030963158e306; if (x < 10) { // ML_ERR_return_NAN return(RVaria.R_NaN); } else if (x >= xmax) { // ML_ERROR(ME_UNDERFLOW, "lgammacor"); /* allow to underflow below */ } else if (x < xbig) { tmp = 10 / x; return(RVaria.chebyshev_eval(tmp * tmp * 2 - 1, algmcs, nalgm) / x); } return(1 / (x * 12)); }
/* R file: gamma.c * name used in R: gammafn */ public static double Gamma(double x) { int i, n; double y; double sinpiy, value; const double xmin = -170.5674972726612, xmax = 171.61447887182298, xsml = 2.2474362225598545e-308, dxrel = 1.490116119384765696e-8; const int ngam = 22; if (double.IsNaN(x)) { return(x); } /* If the argument is exactly zero or a negative integer * then return NaN. */ if (x == 0 || (x < 0 && x == Math.Round(x))) { // ML_ERROR(ME_DOMAIN, "gammafn"); return(double.NaN); } y = Math.Abs(x); if (y <= 10) { /* Compute gamma(x) for -10 <= x <= 10 * Reduce the interval and find gamma(1 + y) for 0 <= y < 1 * first of all. */ n = (int)x; if (x < 0) { --n; } y = x - n;/* n = floor(x) ==> y in [ 0, 1 ) */ --n; value = RVaria.chebyshev_eval(y * 2 - 1, gamcs, ngam) + .9375; if (n == 0) { return(value);/* x = 1.dddd = 1+y */ } if (n < 0) { /* compute gamma(x) for -10 <= x < 1 */ /* exact 0 or "-n" checked already above */ /* The answer is less than half precision */ /* because x too near a negative integer. */ if ((x < -0.5) && (Math.Abs(x - (int)(x - 0.5) / x) < dxrel)) { // ML_ERROR(ME_PRECISION, "gammafn"); } /* The argument is so close to 0 that the result would overflow. */ if (y < xsml) { // ML_ERROR(ME_RANGE, "gammafn"); if (x > 0) { return(double.PositiveInfinity); } else { return(double.NegativeInfinity); } } n = -n; for (i = 0; i < n; i++) { value /= (x + i); } return(value); } else { /* gamma(x) for 2 <= x <= 10 */ for (i = 1; i <= n; i++) { value *= (y + i); } return(value); } } else { /* gamma(x) for y = |x| > 10. */ if (x > xmax) { /* Overflow */ // ML_ERROR(ME_RANGE, "gammafn"); return(double.PositiveInfinity); } if (x < xmin) { /* Underflow */ // ML_ERROR(ME_UNDERFLOW, "gammafn"); return(0.0); } if (y <= 50 && y == (int)y) { /* compute (n - 1)! */ value = 1.0; for (i = 2; i < y; i++) { value *= i; } } else { /* normal case */ value = Math.Exp((y - 0.5) * Math.Log(y) - y + RVaria.M_LN_SQRT_2PI + ((2 * y == (int)2 * y) ? StirlingError(y) : lgammacor(y))); } if (x > 0) { return(value); } if (Math.Abs((x - (int)(x - 0.5)) / x) < dxrel) { /* The answer is less than half precision because */ /* the argument is too near a negative integer. */ // ML_ERROR(ME_PRECISION, "gammafn"); } sinpiy = RVaria.sinpi(y); if (sinpiy == 0) { /* Negative integer arg - overflow */ // ML_ERROR(ME_RANGE, "gammafn"); return(double.PositiveInfinity); } return(-RVaria.M_PI / (y * sinpiy * value)); } }