Example #1
0
        FactorialLn(int value)
        {
            //if(value < 0)
            //{
            //    throw new ArgumentOutOfRangeException("value", Properties.LocalStrings.ArgumentPositive);
            //}

            if (value <= 1)
            {
                return(0.0d);
            }

            if (value >= FactorialLnCacheSize)
            {
                return(GammaAlgorithm.GammaLn(value + 1.0));
            }

            if (factorialLnCache == null)
            {
                factorialLnCache = new double[FactorialLnCacheSize];
            }

            return(factorialLnCache[value] != 0.0
                ? factorialLnCache[value]
                : (factorialLnCache[value] = GammaAlgorithm.GammaLn(value + 1.0)));
        }
        BetaRegularized(
            double a,
            double b,
            double x)
        {
            //if(a < 0.0)
            //{
            //    throw new ArgumentOutOfRangeException("a", Properties.LocalStrings.ArgumentNotNegative);
            //}

            //if(b < 0.0)
            //{
            //    throw new ArgumentOutOfRangeException("b", Properties.LocalStrings.ArgumentNotNegative);
            //}

            //if(x < 0.0 || x > 1.0)
            //{
            //    throw new ArgumentOutOfRangeException("x", Properties.LocalStrings.ArgumentInIntervalXYInclusive(0, 1));
            //}

            double bt = (x == 0.0 || x == 1.0)
                ? 0.0
                : Math.Exp(GammaAlgorithm.GammaLn(a + b) - GammaAlgorithm.GammaLn(a) - GammaAlgorithm.GammaLn(b) + (a * Math.Log(x)) + (b * Math.Log(1.0 - x)));

            bool symmetryTransformation = (x >= (a + 1.0) / (a + b + 2.0));

            /* Continued fraction representation */

            const int MaxIterations = 100;
            double    eps           = Number.RelativeAccuracy;
            double    fpmin         = Number.SmallestNumberGreaterThanZero / eps;

            if (symmetryTransformation)
            {
                x = 1.0 - x;
                double swap = a;
                a = b;
                b = swap;
            }

            double qab = a + b;
            double qap = a + 1.0;
            double qam = a - 1.0;
            double c   = 1.0;
            double d   = 1.0 - (qab * x / qap);

            if (Math.Abs(d) < fpmin)
            {
                d = fpmin;
            }

            d = 1.0 / d;
            double h = d;

            for (int m = 1, m2 = 2; m <= MaxIterations; m++, m2 += 2)
            {
                double aa = m * (b - m) * x / ((qam + m2) * (a + m2));
                d = 1.0 + (aa * d);

                if (Math.Abs(d) < fpmin)
                {
                    d = fpmin;
                }

                c = 1.0 + (aa / c);
                if (Math.Abs(c) < fpmin)
                {
                    c = fpmin;
                }

                d  = 1.0 / d;
                h *= d * c;
                aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
                d  = 1.0 + (aa * d);

                if (Math.Abs(d) < fpmin)
                {
                    d = fpmin;
                }

                c = 1.0 + (aa / c);

                if (Math.Abs(c) < fpmin)
                {
                    c = fpmin;
                }

                d = 1.0 / d;
                double del = d * c;
                h *= del;

                if (Math.Abs(del - 1.0) <= eps)
                {
                    if (symmetryTransformation)
                    {
                        return(1.0 - (bt * h / a));
                    }

                    return(bt * h / a);
                }
            }

            throw new ArgumentException(Properties.LocalStrings.ArgumentTooLargeForIterationLimit, "a,b");
        }
Example #3
0
        GammaRegularized(double a, double x)
        {
            const double Epsilon          = 0.000000000000001;
            const double BigNumber        = 4503599627370496.0;
            const double BigNumberInverse = 2.22044604925031308085e-16;

            //if(a < 0.0)
            //{
            //    throw new ArgumentOutOfRangeException("a", Properties.LocalStrings.ArgumentNotNegative);
            //}

            //if(x < 0.0)
            //{
            //    throw new ArgumentOutOfRangeException("x", Properties.LocalStrings.ArgumentNotNegative);
            //}

            if (Number.AlmostZero(a))
            {
                if (Number.AlmostZero(x))
                {
                    // either 0 or 1, depending on the limit direction
                    return(Double.NaN);
                }

                return(1d);
            }

            if (Number.AlmostZero(x))
            {
                return(0d);
            }

            double ax = (a * Math.Log(x)) - x - GammaAlgorithm.GammaLn(a);

            if (ax < -709.78271289338399)
            {
                return(1d);
            }

            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) > Epsilon);

                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;

            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) > BigNumber)
                {
                    p3 *= BigNumberInverse;
                    p2 *= BigNumberInverse;
                    q3 *= BigNumberInverse;
                    q2 *= BigNumberInverse;
                }
            }while(error > Epsilon);

            return(1d - (Math.Exp(ax) * ans));
        }
Example #4
0
        GammaRegularizedInverse(double a, double y0)
        {
            const double Epsilon   = 0.000000000000001;
            const double BigNumber = 4503599627370496.0;
            const double Threshold = 5 * Epsilon;

            // TODO: Consider to throw an out-of-range exception instead of NaN
            if (a < 0 || Number.AlmostZero(a) || y0 < 0 || y0 > 1)
            {
                return(Double.NaN);
            }

            if (Number.AlmostZero(y0))
            {
                return(0d);
            }

            if (Number.AlmostEqual(y0, 1))
            {
                return(Double.PositiveInfinity);
            }

            y0 = 1 - y0;

            double xUpper = BigNumber;
            double xLower = 0;
            double yUpper = 1;
            double yLower = 0;

            // Initial Guess
            double d   = 1 / (9 * a);
            double y   = 1 - d - (0.98 * Constants.Sqrt2 * ErrorFunctionAlgorithm.ErfInverse((2.0 * y0) - 1.0) * Math.Sqrt(d));
            double x   = a * y * y * y;
            double lgm = GammaAlgorithm.GammaLn(a);

            for (int i = 0; i < 10; i++)
            {
                if (x < xLower || x > xUpper)
                {
                    d = 0.0625;
                    break;
                }

                y = 1 - GammaRegularized(a, x);
                if (y < yLower || y > yUpper)
                {
                    d = 0.0625;
                    break;
                }

                if (y < y0)
                {
                    xUpper = x;
                    yLower = y;
                }
                else
                {
                    xLower = x;
                    yUpper = y;
                }

                d = ((a - 1) * Math.Log(x)) - x - lgm;
                if (d < -709.78271289338399)
                {
                    d = 0.0625;
                    break;
                }

                d = -Math.Exp(d);
                d = (y - y0) / d;
                if (Math.Abs(d / x) < Epsilon)
                {
                    return(x);
                }

                if ((d > (x / 4)) && (y0 < 0.05))
                {
                    // Naive heuristics for cases near the singularity
                    d = x / 10;
                }

                x -= d;
            }

            if (xUpper == BigNumber)
            {
                if (x <= 0)
                {
                    x = 1;
                }

                while (xUpper == BigNumber)
                {
                    x = (1 + d) * x;
                    y = 1 - GammaRegularized(a, x);
                    if (y < y0)
                    {
                        xUpper = x;
                        yLower = y;
                        break;
                    }

                    d = d + d;
                }
            }

            int dir = 0;

            d = 0.5;
            for (int i = 0; i < 400; i++)
            {
                x   = xLower + (d * (xUpper - xLower));
                y   = 1 - GammaRegularized(a, x);
                lgm = (xUpper - xLower) / (xLower + xUpper);
                if (Math.Abs(lgm) < Threshold)
                {
                    return(x);
                }

                lgm = (y - y0) / y0;
                if (Math.Abs(lgm) < Threshold)
                {
                    return(x);
                }

                if (x <= 0d)
                {
                    return(0d);
                }

                if (y >= y0)
                {
                    xLower = x;
                    yUpper = y;
                    if (dir < 0)
                    {
                        dir = 0;
                        d   = 0.5;
                    }
                    else
                    {
                        if (dir > 1)
                        {
                            d = (0.5 * d) + 0.5;
                        }
                        else
                        {
                            d = (y0 - yLower) / (yUpper - yLower);
                        }
                    }

                    dir = dir + 1;
                }
                else
                {
                    xUpper = x;
                    yLower = y;
                    if (dir > 0)
                    {
                        dir = 0;
                        d   = 0.5;
                    }
                    else
                    {
                        if (dir < -1)
                        {
                            d = 0.5 * d;
                        }
                        else
                        {
                            d = (y0 - yLower) / (yUpper - yLower);
                        }
                    }

                    dir = dir - 1;
                }
            }

            return(x);
        }