/// <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; 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(System.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(System.Math.Log(z)); } x -= 2.0; p = x * Polynomial.Evaluate(x, log_B, 5) / Polynomial.EvaluateSpecial(x, log_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 += Polynomial.Evaluate(p, log_A, 4) / x; } return(q); }
/// <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; 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 * Polynomial.Evaluate(y2, inverse_P0, 4)) / Polynomial.EvaluateSpecial(y2, inverse_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 * Polynomial.Evaluate(z, inverse_P1, 8)) / Polynomial.EvaluateSpecial(z, inverse_Q1, 8); } else { x1 = (z * Polynomial.Evaluate(z, inverse_P2, 8)) / Polynomial.EvaluateSpecial(z, inverse_Q2, 8); } x = x0 - x1; if (code != 0) { x = -x; } return(x); }