Accord.Math.Gamma.UpperIncomplete C# (CSharp) Method

UpperIncomplete() public static method

Upper incomplete regularized Gamma function Q (a.k.a the incomplete complemented Gamma function)
This function is equivalent to Q(x) = Γ(s, x) / Γ(s).
public static UpperIncomplete ( double a, double x ) : double
a double
x double
return double
        public static double UpperIncomplete(double a, double x)
        {
            const double big = 4.503599627370496e15;
            const double biginv = 2.22044604925031308085e-16;
            double ans, ax, c, yc, r, t, y, z;
            double pk, pkm1, pkm2, qk, qkm1, qkm2;

            if (x <= 0 || a <= 0)
                return 1.0;

            if (x < 1.0 || x < a)
                return 1.0 - LowerIncomplete(a, x);

            if (Double.IsPositiveInfinity(x))
                return 0;

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

            if (ax < -Constants.LogMax)
                return 0.0;

            ax = Math.Exp(ax);

            // continued fraction
            y = 1.0 - a;
            z = x + y + 1.0;
            c = 0.0;
            pkm2 = 1.0;
            qkm2 = x;
            pkm1 = x + 1.0;
            qkm1 = z * x;
            ans = pkm1 / qkm1;

            do
            {
                c += 1.0;
                y += 1.0;
                z += 2.0;
                yc = y * c;
                pk = pkm1 * z - pkm2 * yc;
                qk = qkm1 * z - qkm2 * yc;
                if (qk != 0)
                {
                    r = pk / qk;
                    t = Math.Abs((ans - r) / r);
                    ans = r;
                }
                else
                    t = 1.0;

                pkm2 = pkm1;
                pkm1 = pk;
                qkm2 = qkm1;
                qkm1 = qk;
                if (Math.Abs(pk) > big)
                {
                    pkm2 *= biginv;
                    pkm1 *= biginv;
                    qkm2 *= biginv;
                    qkm1 *= biginv;
                }
            } while (t > Constants.DoubleEpsilon);

            return ans * ax;
        }

Usage Example

コード例 #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);
        }