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

inverse() private static method

private static inverse ( double a, double y ) : double
a double
y double
return double
        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;
        }