in commons-numbers-combinatorics/src/main/java/org/apache/commons/numbers/combinatorics/Stirling.java [115:167]
public static long stirlingS1(int n, int k) {
checkArguments(n, k);
if (n < StirlingS1Cache.MAX_N) {
// The number is in the small cache
return StirlingS1Cache.S1[n][k];
}
// Simple cases
// https://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind#Simple_identities
if (k == 0) {
return 0;
} else if (k == n) {
return 1;
} else if (k == 1) {
checkN(n, k, S1_OVERFLOW_K_EQUALS_1, S1_ERROR_FORMAT);
// Note: Only occurs for n=21 so avoid computing the sign with pow(-1, n-1) * (n-1)!
return Factorial.value(n - 1);
} else if (k == n - 1) {
return -BinomialCoefficient.value(n, 2);
} else if (k == n - 2) {
checkN(n, k, S1_OVERFLOW_K_EQUALS_NM2, S1_ERROR_FORMAT);
// (3n-1) * binom(n, 3) / 4
return productOver4(3L * n - 1, BinomialCoefficient.value(n, 3));
} else if (k == n - 3) {
checkN(n, k, S1_OVERFLOW_K_EQUALS_NM3, S1_ERROR_FORMAT);
return -BinomialCoefficient.value(n, 2) * BinomialCoefficient.value(n, 4);
}
// Compute using:
// s(n + 1, k) = s(n, k - 1) - n * s(n, k)
// s(n, k) = s(n - 1, k - 1) - (n - 1) * s(n - 1, k)
// n >= 21 (MAX_N)
// 2 <= k <= n-4
// Start at the largest easily computed value: n < MAX_N or k < 2
final int reduction = Math.min(n - StirlingS1Cache.MAX_N, k - 2) + 1;
int n0 = n - reduction;
int k0 = k - reduction;
long sum = stirlingS1(n0, k0);
while (n0 < n) {
k0++;
sum = Math.subtractExact(
sum,
Math.multiplyExact(n0, stirlingS1(n0, k0))
);
n0++;
}
return sum;
}