in commons-numbers-combinatorics/src/main/java/org/apache/commons/numbers/combinatorics/BinomialCoefficient.java [61:116]
public static long value(int n, int k) {
final int m = checkBinomial(n, k);
if (m == 0) {
return 1;
}
if (m == 1) {
return n;
}
// We use the formulae:
// (n choose m) = n! / (n-m)! / m!
// (n choose m) = ((n-m+1)*...*n) / (1*...*m)
// which can be written
// (n choose m) = (n-1 choose m-1) * n / m
long result = 1;
if (n <= SMALL_N) {
// For n <= 61, the naive implementation cannot overflow.
int i = n - m + 1;
for (int j = 1; j <= m; j++) {
result = result * i / j;
i++;
}
} else if (n <= LIMIT_N) {
// For n > 61 but n <= 66, the result cannot overflow,
// but we must take care not to overflow intermediate values.
int i = n - m + 1;
for (int j = 1; j <= m; j++) {
// We know that (result * i) is divisible by j,
// but (result * i) may overflow, so we split j:
// Filter out the gcd, d, so j/d and i/d are integer.
// result is divisible by (j/d) because (j/d)
// is relative prime to (i/d) and is a divisor of
// result * (i/d).
final long d = ArithmeticUtils.gcd(i, j);
result = (result / (j / d)) * (i / d);
++i;
}
} else {
if (m > MAX_M) {
throw new ArithmeticException(n + " choose " + k);
}
// For n > 66, a result overflow might occur, so we check
// the multiplication, taking care to not overflow
// unnecessary.
int i = n - m + 1;
for (int j = 1; j <= m; j++) {
final long d = ArithmeticUtils.gcd(i, j);
result = Math.multiplyExact(result / (j / d), i / d);
++i;
}
}
return result;
}