public static double LogValue(int n) { Assertion.NonNegative(nameof(n), n); if (n <= 20) { return(Math.Log(Value(n))); } return(GammaFunction.LogValue(n + 1)); }
public static double Value(int n) { Assertion.NonNegative(nameof(n), n); if (n <= 20) { long value = 1; for (long i = 1; i <= n; i++) { value *= i; } return(value); } return(GammaFunction.Value(n + 1)); }
/// <summary> /// Natural logarithm of Complete beta function B(a,b) /// </summary> public static double CompleteLogValue(double a, double b) { return(GammaFunction.LogValue(a) + GammaFunction.LogValue(b) - GammaFunction.LogValue(a + b)); }
/// <summary> /// Complete beta function B(a,b) /// </summary> public static double CompleteValue(double a, double b) { return(GammaFunction.Value(a) * GammaFunction.Value(b) / GammaFunction.Value(a + b)); }
/// <summary> /// Regularized incomplete beta function Ix(a, b) /// </summary> public static double RegularizedIncompleteValue(double a, double b, double x) { const double eps = 1e-5; if (a < -eps) { throw new ArgumentOutOfRangeException(nameof(a), "a should be positive"); } if (b < -eps) { throw new ArgumentOutOfRangeException(nameof(b), "b should be positive"); } if (x < eps) { return(0); } if (x > 1 - eps) { return(1); } if (a < eps && b < eps) { return(0.5); } if (a < eps) { return(1); } if (b < eps) { return(0); } if (a + b > 30) // For huge a+b, we use normal approximation { // We are trying to make the situation symmetric (|a-b|<1) to improve accuracy of the approximation double partialResult = 0; while (a < b - 1) { partialResult += Math.Exp(GammaFunction.LogValue(a + b) - GammaFunction.LogValue(a + 1) - GammaFunction.LogValue(b) + a * Math.Log(x) + (b - 1) * Math.Log(1 - x)); a++; b--; } while (b < a - 1) { partialResult -= Math.Exp(GammaFunction.LogValue(a + b) - GammaFunction.LogValue(b + 1) - GammaFunction.LogValue(a) + (a - 1) * Math.Log(x) + b * Math.Log(1 - x)); a--; b++; } var betaDistribution = new BetaDistribution(a, b); double normalApproximation = new NormalDistribution(betaDistribution.Mean, betaDistribution.StdDev).Cdf(x); return(partialResult + normalApproximation); } if (x > 0.5) // Accuracy is better for small x { return(1 - RegularizedIncompleteValue(b, a, 1 - x)); } double result = Math.Exp(IncompleteLogValue(a, b, x) - CompleteLogValue(a, b)); return(double.IsNaN(result) ? 0 : result.Clamp(0, 1)); }