in commons-numbers-combinatorics/src/main/java/org/apache/commons/numbers/combinatorics/Stirling.java [183:232]
public static long stirlingS2(int n, int k) {
checkArguments(n, k);
if (n < StirlingS2Cache.MAX_N) {
// The number is in the small cache
return StirlingS2Cache.S2[n][k];
}
// Simple cases
if (k == 0) {
return 0;
} else if (k == 1 || k == n) {
return 1;
} else if (k == 2) {
checkN(n, k, 64, S2_ERROR_FORMAT);
return (1L << (n - 1)) - 1L;
} else if (k == n - 1) {
return BinomialCoefficient.value(n, 2);
} else if (k == n - 2) {
checkN(n, k, S2_OVERFLOW_K_EQUALS_NM2, S2_ERROR_FORMAT);
// (3n-5) * binom(n, 3) / 4
return productOver4(3L * n - 5, BinomialCoefficient.value(n, 3));
} else if (k == n - 3) {
checkN(n, k, S2_OVERFLOW_K_EQUALS_NM3, S2_ERROR_FORMAT);
return BinomialCoefficient.value(n - 2, 2) * BinomialCoefficient.value(n, 4);
}
// Compute using:
// S(n, k) = k * S(n - 1, k) + S(n - 1, k - 1)
// n >= 26 (MAX_N)
// 3 <= k <= n-3
// Start at the largest easily computed value: n < MAX_N or k < 3
final int reduction = Math.min(n - StirlingS2Cache.MAX_N, k - 3) + 1;
int n0 = n - reduction;
int k0 = k - reduction;
long sum = stirlingS2(n0, k0);
while (n0 < n) {
k0++;
sum = Math.addExact(
Math.multiplyExact(k0, stirlingS2(n0, k0)),
sum
);
n0++;
}
return sum;
}