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;
}