/// <summary> /// Computes the factorial of a number (n!) /// </summary> public static double Factorial(int n) { if (fcache == null) { // Initialize factorial cache fcache = new double[33]; fcache[0] = 1; fcache[1] = 1; fcache[2] = 2; fcache[3] = 6; fcache[4] = 24; ftop = 4; } if (n < 0) { // Factorial is not defined for negative numbers throw new ArgumentException("Argument can not be negative", "n"); } if (n > 32) { // Return Gamma approximation using exp(gammaln(n+1)), // which for some reason is faster than gamma(n+1). return(Math.Exp(Gamma.Log(n + 1.0))); } else { // Compute in the standard way, but use the // factorial cache to speed up computations. while (ftop < n) { int j = ftop++; fcache[ftop] = fcache[j] * ftop; } return(fcache[n]); } }
/// <summary> /// Returns the log factorial of a number (ln(n!)) /// </summary> /// public static double LogFactorial(int n) { if (lnfcache == null) { lnfcache = new double[101]; } if (n < 0) { // Factorial is not defined for negative numbers. throw new ArgumentException("Argument cannot be negative.", "n"); } if (n <= 1) { // Factorial for n between 0 and 1 is 1, so log(factorial(n)) is 0. return(0.0); } if (n <= 100) { // Compute the factorial using ln(gamma(n)) approximation, using the cache // if the value has been previously computed. return((lnfcache[n] > 0) ? lnfcache[n] : (lnfcache[n] = Gamma.Log(n + 1.0))); } else { // Just compute the factorial using ln(gamma(n)) approximation. return(Gamma.Log(n + 1.0)); } }
/// <summary> /// Power series for incomplete beta integral. Use when b*x /// is small and x not too close to 1. /// </summary> /// /// <example> /// Please see <see cref="Beta"/> /// </example> /// public static double PowerSeries(double a, double b, double x) { double s, t, u, v, n, t1, z, ai; ai = 1.0 / a; u = (1.0 - b) * x; v = u / (a + 1.0); t1 = v; t = u; n = 2.0; s = 0.0; z = Constants.DoubleEpsilon * ai; while (System.Math.Abs(v) > z) { u = (n - b) * x / n; t *= u; v = t / (a + n); s += v; n += 1.0; } s += t1; s += ai; u = a * System.Math.Log(x); if ((a + b) < Gamma.GammaMax && System.Math.Abs(u) < Constants.LogMax) { t = Gamma.Function(a + b) / (Gamma.Function(a) * Gamma.Function(b)); s = s * t * System.Math.Pow(x, a); } else { t = Gamma.Log(a + b) - Gamma.Log(a) - Gamma.Log(b) + u + System.Math.Log(s); if (t < Constants.LogMin) { s = 0.0; } else { s = System.Math.Exp(t); } } return(s); }
/// <summary> /// Returns the log factorial of a number (ln(n!)) /// </summary> /// public static double LogFactorial(double n) { return(Gamma.Log(n + 1.0)); }
private static double inverse(double a, double y) { // bound the solution double x0 = Double.MaxValue; double yl = 0; double x1 = 0; double yh = 1.0; double dithresh = 5.0 * Constants.DoubleEpsilon; // approximation to inverse function double d = 1.0 / (9.0 * a); double yy = (1.0 - d - Normal.Inverse(y) * Math.Sqrt(d)); double x = a * yy * yy * yy; double lgm = Gamma.Log(a); for (int i = 0; i < 10; i++) { if (x > x0 || x < x1) { goto ihalve; } yy = Gamma.UpperIncomplete(a, x); if (yy < yl || yy > yh) { goto ihalve; } if (yy < y) { x0 = x; yl = yy; } else { x1 = x; yh = yy; } // compute the derivative of the function at this point d = (a - 1.0) * Math.Log(x) - x - lgm; if (d < -Constants.LogMax) { goto ihalve; } d = -Math.Exp(d); // compute the step to the next approximation of x d = (yy - y) / d; if (Math.Abs(d / x) < Constants.DoubleEpsilon) { return(x); } x = x - d; } // Resort to interval halving if Newton iteration did not converge. ihalve: d = 0.0625; if (x0 == Double.MaxValue) { if (x <= 0.0) { x = 1.0; } while (x0 == Double.MaxValue && !Double.IsNaN(x)) { x = (1.0 + d) * x; yy = Gamma.UpperIncomplete(a, x); if (yy < y) { x0 = x; yl = yy; break; } d = d + d; } } d = 0.5; double dir = 0; for (int i = 0; i < 400; i++) { double t = x1 + d * (x0 - x1); if (Double.IsNaN(t)) { break; } x = t; yy = Gamma.UpperIncomplete(a, x); lgm = (x0 - x1) / (x1 + x0); if (Math.Abs(lgm) < dithresh) { break; } lgm = (yy - y) / y; if (Math.Abs(lgm) < dithresh) { break; } if (x <= 0.0) { break; } if (yy >= y) { x1 = x; yh = yy; if (dir < 0) { dir = 0; d = 0.5; } else if (dir > 1) { d = 0.5 * d + 0.5; } else { d = (y - yl) / (yh - yl); } dir += 1; } else { x0 = x; yl = yy; if (dir > 0) { dir = 0; d = 0.5; } else if (dir < -1) { d = 0.5 * d; } else { d = (y - yl) / (yh - yl); } dir -= 1; } } if (x == 0.0 || Double.IsNaN(x)) { throw new ArithmeticException(); } return(x); }
/// <summary> /// Inverse of incomplete beta integral. /// </summary> /// /// <example> /// Please see <see cref="Beta"/> /// </example> /// public static double IncompleteInverse(double aa, double bb, double yy0) { double a, b, y0, d, y, x, x0, x1, lgm, yp, di, dithresh, yl, yh; int i, dir; bool nflg; bool rflg; if (yy0 <= 0) { return(0.0); } if (yy0 >= 1.0) { return(1.0); } if (aa <= 1.0 || bb <= 1.0) { nflg = true; dithresh = 4.0 * Constants.DoubleEpsilon; rflg = false; a = aa; b = bb; y0 = yy0; x = a / (a + b); y = Incomplete(a, b, x); goto ihalve; } else { nflg = false; dithresh = 1.0e-4; } /* approximation to inverse function */ yp = -Normal.Inverse(yy0); if (yy0 > 0.5) { rflg = true; a = bb; b = aa; y0 = 1.0 - yy0; yp = -yp; } else { rflg = false; a = aa; b = bb; y0 = yy0; } lgm = (yp * yp - 3.0) / 6.0; x0 = 2.0 / (1.0 / (2.0 * a - 1.0) + 1.0 / (2.0 * b - 1.0)); y = yp * Math.Sqrt(x0 + lgm) / x0 - (1.0 / (2.0 * b - 1.0) - 1.0 / (2.0 * a - 1.0)) * (lgm + 5.0 / 6.0 - 2.0 / (3.0 * x0)); y = 2.0 * y; if (y < Constants.LogMin) { x0 = 1.0; throw new ArithmeticException("underflow"); } x = a / (a + b * Math.Exp(y)); y = Incomplete(a, b, x); yp = (y - y0) / y0; if (Math.Abs(yp) < 1.0e-2) { goto newt; } ihalve: /* Resort to interval halving if not close enough */ x0 = 0.0; yl = 0.0; x1 = 1.0; yh = 1.0; di = 0.5; dir = 0; for (i = 0; i < 400; i++) { if (i != 0) { x = x0 + di * (x1 - x0); if (x == 1.0) { x = 1.0 - Constants.DoubleEpsilon; } y = Incomplete(a, b, x); yp = (x1 - x0) / (x1 + x0); if (Math.Abs(yp) < dithresh) { x0 = x; goto newt; } } if (y < y0) { x0 = x; yl = y; if (dir < 0) { dir = 0; di = 0.5; } else if (dir > 1) { di = 0.5 * di + 0.5; } else { di = (y0 - y) / (yh - yl); } dir += 1; if (x0 > 0.75) { if (rflg) { rflg = false; a = aa; b = bb; y0 = yy0; } else { rflg = true; a = bb; b = aa; y0 = 1.0 - yy0; } x = 1.0 - x; y = Incomplete(a, b, x); goto ihalve; } } else { x1 = x; if (rflg && x1 < Constants.DoubleEpsilon) { x0 = 0.0; goto done; } yh = y; if (dir > 0) { dir = 0; di = 0.5; } else if (dir < -1) { di = 0.5 * di; } else { di = (y - y0) / (yh - yl); } dir -= 1; } } if (x0 >= 1.0) { x0 = 1.0 - Constants.DoubleEpsilon; goto done; } if (x == 0.0) { throw new ArithmeticException("underflow"); } newt: if (nflg) { goto done; } x0 = x; lgm = Gamma.Log(a + b) - Gamma.Log(a) - Gamma.Log(b); for (i = 0; i < 10; i++) { /* Compute the function at this point. */ if (i != 0) { y = Incomplete(a, b, x0); } /* Compute the derivative of the function at this point. */ d = (a - 1.0) * Math.Log(x0) + (b - 1.0) * Math.Log(1.0 - x0) + lgm; if (d < Constants.LogMin) { throw new ArithmeticException("underflow"); } d = Math.Exp(d); /* compute the step to the next approximation of x */ d = (y - y0) / d; x = x0; x0 = x0 - d; if (x0 <= 0.0) { throw new ArithmeticException("underflow"); } if (x0 >= 1.0) { x0 = 1.0 - Constants.DoubleEpsilon; goto done; } if (Math.Abs(d / x0) < 64.0 * Constants.DoubleEpsilon) { goto done; } } done: if (rflg) { if (x0 <= Double.Epsilon) { x0 = 1.0 - Double.Epsilon; } else { x0 = 1.0 - x0; } } return(x0); }
/// <summary> /// Incomplete (regularized) Beta function Ix(a, b). /// </summary> /// /// <example> /// Please see <see cref="Beta"/> /// </example> /// public static double Incomplete(double a, double b, double x) { double aa, bb, t, xx, xc, w, y; bool flag; if (a <= 0.0) { throw new ArgumentOutOfRangeException("a", "Lower limit must be greater than zero."); } if (b <= 0.0) { throw new ArgumentOutOfRangeException("b", "Upper limit must be greater than zero."); } if ((x <= 0.0) || (x >= 1.0)) { if (x == 0.0) { return(0.0); } if (x == 1.0) { return(1.0); } throw new ArgumentOutOfRangeException("x", "Value must be between 0 and 1."); } flag = false; if ((b * x) <= 1.0 && x <= 0.95) { t = PowerSeries(a, b, x); return(t); } w = 1.0 - x; if (x > (a / (a + b))) { flag = true; aa = b; bb = a; xc = x; xx = w; } else { aa = a; bb = b; xc = w; xx = x; } if (flag && (bb * xx) <= 1.0 && xx <= 0.95) { t = PowerSeries(aa, bb, xx); if (t <= Constants.DoubleEpsilon) { t = 1.0 - Constants.DoubleEpsilon; } else { t = 1.0 - t; } return(t); } y = xx * (aa + bb - 2.0) - (aa - 1.0); if (y < 0.0) { w = Incbcf(aa, bb, xx); } else { w = Incbd(aa, bb, xx) / xc; } y = aa * System.Math.Log(xx); t = bb * System.Math.Log(xc); if ((aa + bb) < Gamma.GammaMax && System.Math.Abs(y) < Constants.LogMax && System.Math.Abs(t) < Constants.LogMax) { t = System.Math.Pow(xc, bb); t *= System.Math.Pow(xx, aa); t /= aa; t *= w; t *= Gamma.Function(aa + bb) / (Gamma.Function(aa) * Gamma.Function(bb)); if (flag) { if (t <= Constants.DoubleEpsilon) { t = 1.0 - Constants.DoubleEpsilon; } else { t = 1.0 - t; } } return(t); } y += t + Gamma.Log(aa + bb) - Gamma.Log(aa) - Gamma.Log(bb); y += System.Math.Log(w / aa); if (y < Constants.LogMin) { t = 0.0; } else { t = System.Math.Exp(y); } if (flag) { if (t <= Constants.DoubleEpsilon) { t = 1.0 - Constants.DoubleEpsilon; } else { t = 1.0 - t; } } return(t); }
/// <summary> /// Natural logarithm of the Beta function. /// </summary> /// /// <example> /// Please see <see cref="Beta"/> /// </example> /// public static double Log(double a, double b) { return(Gamma.Log(a) + Gamma.Log(b) - Gamma.Log(a + b)); }
/// <summary> /// Lower incomplete regularized gamma function P. /// </summary> /// public static double LowerIncomplete(double a, double x) { #region Copyright information // Copyright (c) 2009-2010 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. #endregion const double eps = 0.000000000000001; const double big = 4503599627370496.0; const double biginv = 2.22044604925031308085e-16; if (a < 0) { throw new ArgumentOutOfRangeException("a"); } if (x < 0) { throw new ArgumentOutOfRangeException("x"); } if (a == 0.0) { if (x == 0.0) { return(Double.NaN); } return(1d); } if (x == 0.0) { return(0d); } double ax = (a * Math.Log(x)) - x - Gamma.Log(a); if (ax < -709.78271289338399) { return(1.0); } if (x <= 1 || x <= a) { double r2 = a; double c2 = 1; double ans2 = 1; do { r2 = r2 + 1; c2 = c2 * x / r2; ans2 += c2; }while ((c2 / ans2) > eps); return(Math.Exp(ax) * ans2 / a); } int c = 0; double y = 1 - a; double z = x + y + 1; double p3 = 1; double q3 = x; double p2 = x + 1; double q2 = z * x; double ans = p2 / q2; double error = 0; do { c++; y += 1; z += 2; double yc = y * c; double p = (p2 * z) - (p3 * yc); double q = (q2 * z) - (q3 * yc); if (q != 0) { double nextans = p / q; error = Math.Abs((ans - nextans) / nextans); ans = nextans; } else { // zero div, skip error = 1; } // shift p3 = p2; p2 = p; q3 = q2; q2 = q; // normalize fraction when the numerator becomes large if (Math.Abs(p) > big) { p3 *= biginv; p2 *= biginv; q3 *= biginv; q2 *= biginv; } }while (error > eps); return(1.0 - (Math.Exp(ax) * ans)); }