/// <summary> /// Gamma function as computed by Stirling's formula. /// </summary> public static double Stirling(double x) { double[] STIR = { 7.87311395793093628397E-4, -2.29549961613378126380E-4, -2.68132617805781232825E-3, 3.47222221605458667310E-3, 8.33333333333482257126E-2 }; double MAXSTIR = 143.01608; double w = 1.0 / x; double y = Math.Exp(x); w = 1.0 + w * Special.Polevl(w, STIR, 4); if (x > MAXSTIR) { double v = Math.Pow(x, 0.5 * x - 0.25); if (Double.IsPositiveInfinity(v) && Double.IsPositiveInfinity(y)) { // lim x -> inf { (x^(0.5*x - 0.25)) * (x^(0.5*x - 0.25) / exp(x)) } y = Double.PositiveInfinity; } else { y = v * (v / y); } } else { y = Math.Pow(x, x - 0.5) / y; } y = Constants.Sqrt2PI * y * w; return(y); }
/// <summary> /// Normal (Gaussian) inverse cumulative distribution function. /// </summary> /// <remarks> /// <para> /// For small arguments <c>0 < y < exp(-2)</c>, the program computes /// <c> /// z = /// sqrt( -2.0 * log(y) ) /// </c> /// ; then the approximation is /// <c> /// x = z - log(z)/z - /// (1/z) P(1/z) / Q(1/z) /// </c> /// . /// </para> /// <para> /// There are two rational functions P/Q, one for <c>0 < y < exp(-32)</c> and /// the other for <c>y</c> up to <c>exp(-2)</c>. For larger arguments, <c>w = y - 0.5</c>, /// and <c>x/sqrt(2pi) = w + w^3 * R(w^2)/S(w^2))</c>. /// </para> /// </remarks> /// <returns> /// Returns the value, <c>x</c>, for which the area under the Normal (Gaussian) /// probability density function (integrated from minus infinity to <c>x</c>) is /// equal to the argument <c>y</c> (assumes mean is zero, variance is one). /// </returns> public static double Inverse(double y0) { if (y0 <= 0.0) { if (y0 == 0) { return(Double.NegativeInfinity); } throw new ArgumentOutOfRangeException("y0"); } if (y0 >= 1.0) { if (y0 == 1) { return(Double.PositiveInfinity); } throw new ArgumentOutOfRangeException("y0"); } double s2pi = Math.Sqrt(2.0 * Math.PI); int code = 1; double y = y0; double x; double[] P0 = { -59.963350101410789, 98.001075418599967, -56.676285746907027, 13.931260938727968, -1.2391658386738125 }; double[] Q0 = { 1.9544885833814176, 4.6762791289888153, 86.360242139089053, -225.46268785411937, 200.26021238006066, -82.037225616833339, 15.90562251262117, -1.1833162112133 }; double[] P1 = { 4.0554489230596245, 31.525109459989388, 57.162819224642128, 44.080507389320083, 14.684956192885803, 2.1866330685079025, -0.14025607917135449, -0.035042462682784818, -0.00085745678515468545 }; double[] Q1 = { 15.779988325646675, 45.390763512887922, 41.317203825467203, 15.04253856929075, 2.5046494620830941, -0.14218292285478779, -0.038080640769157827, -0.00093325948089545744 }; double[] P2 = { 3.2377489177694603, 6.9152288906898418, 3.9388102529247444, 1.3330346081580755, 0.20148538954917908, 0.012371663481782003, 0.00030158155350823543, 2.6580697468673755E-06, 6.2397453918498331E-09 }; double[] Q2 = { 6.02427039364742, 3.6798356385616087, 1.3770209948908132, 0.21623699359449663, 0.013420400608854318, 0.00032801446468212774, 2.8924786474538068E-06, 6.7901940800998127E-09 }; if (y > 0.8646647167633873) { y = 1.0 - y; code = 0; } if (y > 0.1353352832366127) { y -= 0.5; double y2 = y * y; x = y + y * ((y2 * Special.Polevl(y2, P0, 4)) / Special.P1evl(y2, Q0, 8)); x *= s2pi; return(x); } x = Math.Sqrt(-2.0 * Math.Log(y)); double x0 = x - Math.Log(x) / x; double z = 1.0 / x; double x1; if (x < 8.0) { x1 = (z * Special.Polevl(z, P1, 8)) / Special.P1evl(z, Q1, 8); } else { x1 = (z * Special.Polevl(z, P2, 8)) / Special.P1evl(z, Q2, 8); } x = x0 - x1; if (code != 0) { x = -x; } return(x); }
/// <summary> /// Gamma function of the specified value. /// </summary> public static double Function(double x) { double[] P = { 1.60119522476751861407E-4, 1.19135147006586384913E-3, 1.04213797561761569935E-2, 4.76367800457137231464E-2, 2.07448227648435975150E-1, 4.94214826801497100753E-1, 9.99999999999999996796E-1 }; double[] Q = { -2.31581873324120129819E-5, 5.39605580493303397842E-4, -4.45641913851797240494E-3, 1.18139785222060435552E-2, 3.58236398605498653373E-2, -2.34591795718243348568E-1, 7.14304917030273074085E-2, 1.00000000000000000320E0 }; double p, z; double q = Math.Abs(x); if (q > 33.0) { if (x < 0.0) { p = Math.Floor(q); if (p == q) { throw new OverflowException(); } z = q - p; if (z > 0.5) { p += 1.0; z = q - p; } z = q * Math.Sin(Math.PI * z); if (z == 0.0) { throw new OverflowException(); } z = Math.Abs(z); z = Math.PI / (z * Stirling(q)); return(-z); } return(Stirling(x)); } z = 1.0; while (x >= 3.0) { x -= 1.0; z *= x; } while (x < 0.0) { if (x == 0.0) { throw new ArithmeticException(); } if (x > -1.0E-9) { return(z / ((1.0 + 0.5772156649015329 * x) * x)); } z /= x; x += 1.0; } while (x < 2.0) { if (x == 0.0) { throw new ArithmeticException(); } if (x < 1.0E-9) { return(z / ((1.0 + 0.5772156649015329 * x) * x)); } z /= x; x += 1.0; } if ((x == 2.0) || (x == 3.0)) { return(z); } x -= 2.0; p = Special.Polevl(x, P, 6); q = Special.Polevl(x, Q, 7); return(z * p / q); }
/// <summary> /// Natural logarithm of the gamma function. /// </summary> public static double Log(double x) { if (x == 0) { return(Double.PositiveInfinity); } double p, q, w, z; double[] A = { 8.11614167470508450300E-4, -5.95061904284301438324E-4, 7.93650340457716943945E-4, -2.77777777730099687205E-3, 8.33333333333331927722E-2 }; double[] B = { -1.37825152569120859100E3, -3.88016315134637840924E4, -3.31612992738871184744E5, -1.16237097492762307383E6, -1.72173700820839662146E6, -8.53555664245765465627E5 }; double[] C = { -3.51815701436523470549E2, -1.70642106651881159223E4, -2.20528590553854454839E5, -1.13933444367982507207E6, -2.53252307177582951285E6, -2.01889141433532773231E6 }; if (x < -34.0) { q = -x; w = Log(q); p = Math.Floor(q); if (p == q) { throw new OverflowException(); } z = q - p; if (z > 0.5) { p += 1.0; z = p - q; } z = q * Math.Sin(Math.PI * z); if (z == 0.0) { throw new OverflowException(); } z = Constants.LogPI - Math.Log(z) - w; return(z); } if (x < 13.0) { z = 1.0; while (x >= 3.0) { x -= 1.0; z *= x; } while (x < 2.0) { if (x == 0.0) { throw new OverflowException(); } z /= x; x += 1.0; } if (z < 0.0) { z = -z; } if (x == 2.0) { return(Math.Log(z)); } x -= 2.0; p = x * Special.Polevl(x, B, 5) / Special.P1evl(x, C, 6); return(Math.Log(z) + p); } if (x > 2.556348e305) { throw new OverflowException(); } q = (x - 0.5) * Math.Log(x) - x + 0.91893853320467274178; if (x > 1.0e8) { return(q); } p = 1.0 / (x * x); if (x >= 1000.0) { q += ((7.9365079365079365079365e-4 * p - 2.7777777777777777777778e-3) * p + 0.0833333333333333333333) / x; } else { q += Special.Polevl(p, A, 4) / x; } return(q); }