in commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/BoostGamma.java [757:815]
static double lgamma(double z, int[] sign) {
double result;
int sresult = 1;
if (z <= -ROOT_EPSILON) {
// reflection formula:
if (Math.rint(z) == z) {
// Pole error
return Double.NaN;
}
double t = sinpx(z);
z = -z;
if (t < 0) {
t = -t;
} else {
sresult = -sresult;
}
// This summation can have large magnitudes with opposite signs.
// Use an extended precision sum to reduce cancellation.
result = Sum.of(-lgamma(z)).add(-Math.log(t)).add(LOG_PI).getAsDouble();
} else if (z < ROOT_EPSILON) {
if (z == 0) {
// Pole error
return Double.NaN;
}
if (4 * Math.abs(z) < EPSILON) {
result = -Math.log(Math.abs(z));
} else {
result = Math.log(Math.abs(1 / z - EULER));
}
if (z < 0) {
sresult = -1;
}
} else if (z < 15) {
result = lgammaSmall(z, z - 1, z - 2);
// The z > 3 condition is always true
//} else if (z > 3 && z < 100) {
} else if (z < 100) {
// taking the log of tgamma reduces the error, no danger of overflow here:
result = Math.log(tgamma(z));
} else {
// regular evaluation:
final double zgh = z + Lanczos.GMH;
result = Math.log(zgh) - 1;
result *= z - 0.5f;
//
// Only add on the lanczos sum part if we're going to need it:
//
if (result * EPSILON < 20) {
result += Math.log(Lanczos.lanczosSumExpGScaled(z));
}
}
if (nonZeroLength(sign)) {
sign[0] = sresult;
}
return result;
}