Beispiel #1
0
        /// <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]);
            }
        }
Beispiel #2
0
        /// <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));
            }
        }
Beispiel #3
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);
        }
Beispiel #4
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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
 /// <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));
 }
Beispiel #8
0
 /// <summary>
 ///   Returns the log factorial of a number (ln(n!))
 /// </summary>
 ///
 public static double LogFactorial(double n)
 {
     return(Gamma.Log(n + 1.0));
 }