public static UpperIncomplete ( double a, double x ) : double | ||
a | double | |
x | double | |
Résultat | 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;
}
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); }