このバージョンはBigInteger
、浮動小数点演算を必要とせずn
、62 未満のすべてのオーバーフロー エラーなしで動作します。28 を超える 62 は、オーバーフローが発生する最初のペアです。
public static long nChooseK(int n, int k) {
k = Math.min(k, n - k);
if (n < 0 || k < 0)
throw new IllegalArgumentException();
if (k == 0)
return 1;
long value = n--;
for (int i = 2; i <= k; i++) {
value = Math.multiplyExact(value, n--);
value /= i;
}
return value;
}
次のテストは、これが正しいことを証明しています。
@Test
void nChooseKLongVsBigInt() {
for (int n = 0; n < 62; n++) {
for (int k = 0; k <= n; k++) {
assertEquals(nChooseKBigInt(n, k), BigInteger.valueOf(nChooseK(n, k)));
}
}
}
private BigInteger nChooseKBigInt(int n, int k) {
return factorial(n).divide(factorial(k).multiply(factorial(n - k)));
}
private BigInteger factorial(int number) {
BigInteger result = BigInteger.ONE;
for (int factor = 2; factor <= number; factor++) {
result = result.multiply(BigInteger.valueOf(factor));
}
return result;
}