/// <summary> /// Calculates the specified Gamma function when <paramref name="a"/> is a half integer /// </summary> /// <param name="r"></param> /// <param name="a"></param> /// <param name="x"></param> /// <returns></returns> static double HalfIntegerA(Routine r, double a, double x) { Debug.Assert(a - Math.Floor(a) == 0.5); double sum = 0; if (a > 1) { sum = 1.0; double term = 1.0; for (int n = 2; n < a; ++n) { term *= x / (n - 0.5); sum += term; } } double result; double mult = 2.0 * Constants.RecipSqrtPI * Math.Sqrt(x); if (r == Routine.Q || r == Routine.Upper) { result = Math2.Erfc(Math.Sqrt(x)) + sum * mult * Math.Exp(-x); return((r == Routine.Q) ? result : result *Math2.Tgamma(a)); } else { result = Math2.Erf(Math.Sqrt(x)) - sum * mult * Math.Exp(-x); return((r == Routine.P) ? result : result *Math2.Tgamma(a)); } }
public static double TgammaLowerImp(double a, double x) { const Routine routine = Routine.Lower; // special values if (x == 0.0) { return(0.0); } if (double.IsInfinity(x)) { return(Math2.Tgamma(a)); } if (a == 1.0) { return(-Math2.Expm1(-x)); // 1.0 - Math.Exp(-x); } if (a == 0.5) { return(Constants.SqrtPI * Math2.Erf(Math.Sqrt(x))); } // Process small a, large x with asymptotic series, which is faster than CF if (x >= Asym_MinLargeZ(a)) { return(Math2.Tgamma(a) - Asym_SeriesLargeZ(a, x) * Prefix(a, x) / x); } // is a small if ((a < 30) && (x >= a + 1) && (x < DoubleLimits.MaxLogValue)) { double frac = a - Math.Floor(a); if (frac == 0) { return(IntegerA(routine, a, x)); } else if (frac == 0.5) { return(HalfIntegerA(routine, a, x)); } } if (x < (a + 1)) { if (a < 1) { return(SmallA(routine, a, x)); } return(Prefix(a, x, 1 / a) * LowerSeries(a, x)); } // Use CF for x > a+1 return(TgammaMinusUpperFraction(a, x)); }
public static double GammaPImp(double a, double x) { const Routine routine = Routine.P; // special values if (x == 0.0) { return(0.0); } if (double.IsInfinity(x)) { return(1.0); } if (a == 0) { return(1); } if (a == 1.0) { return(-Math2.Expm1(-x)); // 1.0 - Math.Exp(-x) } if (a == 0.5) { return(Math2.Erf(Math.Sqrt(x))); } // Process small a, large x with asymptotic series, which is faster than CF if (x >= Asym_MinLargeZ(a)) { return(1 - Asym_SeriesLargeZ(a, x) * PrefixRegularized(a, x) / x); } // is a small if ((a < 30) && (x >= a + 1) && (x < DoubleLimits.MaxLogValue)) { double frac = a - Math.Floor(a); if (frac == 0) { return(IntegerA(routine, a, x)); } else if (frac == 0.5) { return(HalfIntegerA(routine, a, x)); } } // // Begin by testing whether we're in the "bad" zone // where the result will be near 0.5 and the usual // series and continued fractions are slow to converge: // if (a > 20) { // This second limit below is chosen so that we use Temme's expansion // only if the result would be larger than about 10^-6. // Below that the regular series and continued fractions // converge OK, and if we use Temme's method we get increasing // errors from the dominant erfc term as it's (inexact) argument // increases in magnitude. double sigma = Math.Abs((x - a) / a); if (sigma < 0.4 || (a > 200 && 20 / a > sigma * sigma)) { double t = TemmeSymmetricAsym.GammaP(a, x); return((x >= a) ? 1 - t : t); } } if (x < (a + 1)) { if (a < 1) { return(SmallA(routine, a, x)); } return(PrefixRegularized(a, x) * LowerSeries(a, x) / a); } // Use CF for x > a+1 return(1.0 - PrefixRegularized(a, x) * UpperFraction(a, x)); }