static double tgamma()

in commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/BoostGamma.java [595:690]


    static double tgamma(double z) {
        // Handle integers
        if (Math.rint(z) == z) {
            if (z <= 0) {
                // Pole error
                return Double.NaN;
            }
            if (z <= MAX_GAMMA_Z) {
                // Gamma(n) = (n-1)!
                return FACTORIAL[(int) z - 1];
            }
            // Overflow
            return Double.POSITIVE_INFINITY;
        }

        if (Math.abs(z) <= LANCZOS_THRESHOLD) {
            // Small z
            // NSWC Library of Mathematics Subroutines
            // Note:
            // This does not benefit from using extended precision to track the sum (t).
            // Extended precision on the product reduces the error but the majority
            // of error remains in InvGamma1pm1.

            if (z >= 1) {
                /*
                 * From the recurrence relation
                 * Gamma(x) = (x - 1) * ... * (x - n) * Gamma(x - n),
                 * then
                 * Gamma(t) = 1 / [1 + InvGamma1pm1.value(t - 1)],
                 * where t = x - n. This means that t must satisfy
                 * -0.5 <= t - 1 <= 1.5.
                 */
                double prod = 1;
                double t = z;
                while (t > 2.5) {
                    t -= 1;
                    prod *= t;
                }
                return prod / (1 + InvGamma1pm1.value(t - 1));
            }
            /*
             * From the recurrence relation
             * Gamma(x) = Gamma(x + n + 1) / [x * (x + 1) * ... * (x + n)]
             * then
             * Gamma(x + n + 1) = 1 / [1 + InvGamma1pm1.value(x + n)],
             * which requires -0.5 <= x + n <= 1.5.
             */
            double prod = z;
            double t = z;
            while (t < -0.5) {
                t += 1;
                prod *= t;
            }
            return 1 / (prod * (1 + InvGamma1pm1.value(t)));
        }

        // Large non-integer z
        // Boost C++ tgamma implementation

        if (z < 0) {
            /*
             * From the reflection formula
             * Gamma(x) * Gamma(1 - x) * sin(pi * x) = pi,
             * and the recurrence relation
             * Gamma(1 - x) = -x * Gamma(-x),
             * it is found
             * Gamma(x) = -pi / [x * sin(pi * x) * Gamma(-x)].
             */
            return -Math.PI / (sinpx(z) * tgamma(-z));
        } else if (z > MAX_GAMMA_Z + 1) {
            // Addition to the Boost code: Simple overflow detection
            return Double.POSITIVE_INFINITY;
        }

        double result = Lanczos.lanczosSum(z);
        final double zgh = z + Lanczos.GMH;
        final double lzgh = Math.log(zgh);
        if (z * lzgh > LOG_MAX_VALUE) {
            // we're going to overflow unless this is done with care:

            // Updated
            // Check for overflow removed:
            // if (lzgh * z / 2 > LOG_MAX_VALUE) ... overflow
            // This is replaced by checking z > MAX_FACTORIAL + 2

            final double hp = Math.pow(zgh, (z / 2) - 0.25);
            result *= hp / Math.exp(zgh);
            // Check for overflow has been removed:
            // if (Double.MAX_VALUE / hp < result) ... overflow
            result *= hp;
        } else {
            result *= Math.pow(zgh, z - 0.5) / Math.exp(zgh);
        }

        return result;
    }