in commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/BoostBeta.java [108:158]
static double beta(double p, double q) {
if (!(p > 0 && q > 0)) {
// Domain error
return Double.NaN;
}
final double c = p + q;
// Special cases:
if (c == p && q < EPSILON) {
return 1 / q;
} else if (c == q && p < EPSILON) {
return 1 / p;
}
if (q == 1) {
return 1 / p;
} else if (p == 1) {
return 1 / q;
} else if (c < EPSILON) {
return (c / p) / q;
}
// Create input a > b
final double a = p < q ? q : p;
final double b = p < q ? p : q;
// Lanczos calculation:
final double agh = a + BoostGamma.Lanczos.GMH;
final double bgh = b + BoostGamma.Lanczos.GMH;
final double cgh = c + BoostGamma.Lanczos.GMH;
double result = BoostGamma.Lanczos.lanczosSumExpGScaled(a) *
(BoostGamma.Lanczos.lanczosSumExpGScaled(b) / BoostGamma.Lanczos.lanczosSumExpGScaled(c));
final double ambh = a - 0.5f - b;
if (Math.abs(b * ambh) < cgh * 100 && a > 100) {
// Special case where the base of the power term is close to 1
// compute (1+x)^y instead:
result *= Math.exp(ambh * Math.log1p(-b / cgh));
} else {
result *= Math.pow(agh / cgh, ambh);
}
if (cgh > 1e10f) {
// this avoids possible overflow, but appears to be marginally less accurate:
result *= Math.pow((agh / cgh) * (bgh / cgh), b);
} else {
result *= Math.pow((agh * bgh) / (cgh * cgh), b);
}
result *= Math.sqrt(Math.E / bgh);
return result;
}