Microsoft.Scripting.Utils.MathUtils.Gamma C# (CSharp) Method

Gamma() public static method

public static Gamma ( double v0 ) : double
v0 double
return double
        public static double Gamma(double v0) {
            // Calculate the Gamma function using the Lanczos approximation

            if (double.IsNegativeInfinity(v0)) {
                return double.NaN;
            }
            double a = Math.Abs(v0);

            // Special-case integers
            if (a % 1.0 == 0.0) {
                // Gamma is undefined on non-positive integers
                if (v0 <= 0.0) {
                    return double.NaN;
                }

                // factorial(v0 - 1)
                if (a <= 25.0) {
                    if (a <= 2.0) {
                        return 1.0;
                    }
                    a -= 1.0;
                    v0 -= 1.0;
                    while (--v0 > 1.0) {
                        a *= v0;
                    }
                    return a;
                }
            }

            // lim(Gamma(v0)) = 1.0 / v0 as v0 approaches 0.0
            if (a < 1e-50) {
                return 1.0 / v0;
            }

            double res;
            if (v0 < -150.0) {
                // If Gamma(1 - v0) could overflow for large v0, use the duplication formula to
                // compute Gamma(1 - v0):
                //     Gamma(x) * Gamma(x + 0,5) = sqrt(pi) * 2**(1 - 2x) * Gamma(2x)
                // ==> Gamma(1 - x) = Gamma((1-x)/2) * Gamma((2-x)/2) / (2**x * sqrt(pi))
                // Then apply the reflection formula:
                //     Gamma(x) = pi / sin(pi * x) / Gamma(1 - x)
                double halfV0 = v0 / 2.0;
                res = Math.Pow(Math.PI, 1.5) / SinPi(v0);
                res *= Math.Pow(2.0, v0);
                res /= PositiveGamma(0.5 - halfV0);
                res /= PositiveGamma(1.0 - halfV0);
            } else if (v0 < 0.001) {
                // For values less than or close to zero, just use the reflection formula
                res = Math.PI / SinPi(v0);
                double v1 = 1.0 - v0;
                if (v0 == 1.0 - v1) {
                    res /= PositiveGamma(v1);
                } else {
                    // Computing v1 has resulted in a loss of precision. To avoid this, use the
                    // recurrence relation Gamma(x + 1) = x * Gamma(x).
                    res /= -v0 * PositiveGamma(-v0);
                }
            } else {
                res = PositiveGamma(v0);
            }

            return res;
        }