Esempio n. 1
0
        private static double inverse(double a, double y)
        {
            // bound the solution
            var    x0       = double.MaxValue;
            double yl       = 0;
            double x1       = 0;
            var    yh       = 1.0;
            var    dithresh = 5.0 * Constants.DoubleEpsilon;

            // approximation to inverse function
            var d  = 1.0 / (9.0 * a);
            var yy = 1.0 - d - Normal.Inverse(y) * Math.Sqrt(d);
            var x  = a * yy * yy * yy;

            var lgm = Log(a);

            for (var i = 0; i < 10; i++)
            {
                if (x > x0 || x < x1)
                {
                    goto ihalve;
                }

                yy = 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 = UpperIncomplete(a, x);
                    if (yy < y)
                    {
                        x0 = x;
                        yl = yy;
                        break;
                    }

                    d = d + d;
                }
            }

            d = 0.5;
            double dir = 0;

            for (var i = 0; i < 400; i++)
            {
                var t = x1 + d * (x0 - x1);

                if (double.IsNaN(t))
                {
                    break;
                }

                x   = t;
                yy  = 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);
        }