in commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/BoostBeta.java [835:913]
private static double ibetaSeries(double a, double b, double x, double s0, boolean normalised, Policy pol) {
double result;
if (normalised) {
final double c = a + b;
// incomplete beta power term, combined with the Lanczos approximation:
final double agh = a + BoostGamma.Lanczos.GMH;
final double bgh = b + BoostGamma.Lanczos.GMH;
final double cgh = c + BoostGamma.Lanczos.GMH;
result = BoostGamma.Lanczos.lanczosSumExpGScaled(c) /
(BoostGamma.Lanczos.lanczosSumExpGScaled(a) * BoostGamma.Lanczos.lanczosSumExpGScaled(b));
final double l1 = Math.log(cgh / bgh) * (b - 0.5f);
final double l2 = Math.log(x * cgh / agh) * a;
//
// Check for over/underflow in the power terms:
//
if (l1 > LOG_MIN_VALUE && l1 < LOG_MAX_VALUE && l2 > LOG_MIN_VALUE && l2 < LOG_MAX_VALUE) {
if (a * b < bgh * 10) {
result *= Math.exp((b - 0.5f) * Math.log1p(a / bgh));
} else {
result *= Math.pow(cgh / bgh, b - 0.5f);
}
result *= Math.pow(x * cgh / agh, a);
result *= Math.sqrt(agh / Math.E);
} else {
//
// Oh dear, we need logs, and this *will* cancel:
//
result = Math.log(result) + l1 + l2 + (Math.log(agh) - 1) / 2;
result = Math.exp(result);
}
} else {
// Non-normalised, just compute the power:
result = Math.pow(x, a);
}
double rescale = 1.0;
if (result < Double.MIN_NORMAL) {
// Safeguard: series can't cope with denorms.
// Update:
// The entire series is only based on the magnitude of 'result'.
// If the first term can be added to s0 (e.g. if s0 == 0) then
// scale s0 and result, compute the series and then rescale.
// Intentional floating-point equality check.
if (s0 + result / a == s0) {
return s0;
}
s0 *= TWO_POW_53;
result *= TWO_POW_53;
rescale = TWO_POW_M53;
}
final double eps = pol.getEps();
final int maxIterations = pol.getMaxIterations();
// Create effectively final 'result' for initialisation
final double result1 = result;
final DoubleSupplier gen = new DoubleSupplier() {
/** Next result term. */
private double result = result1;
/** Pochhammer term. */
private final double poch = -b;
/** Iteration. */
private int n;
@Override
public double getAsDouble() {
final double r = result / (a + n);
n++;
result *= (n + poch) * x / n;
return r;
}
};
return BoostTools.sumSeries(gen, eps, maxIterations, s0) * rescale;
}