combinations.js 1.2 KB

123456789101112131415161718192021222324252627282930313233
  1. import { isInteger } from '../../utils/number.js';
  2. import { product } from '../../utils/product.js';
  3. export function combinationsNumber(n, k) {
  4. if (!isInteger(n) || n < 0) {
  5. throw new TypeError('Positive integer value expected in function combinations');
  6. }
  7. if (!isInteger(k) || k < 0) {
  8. throw new TypeError('Positive integer value expected in function combinations');
  9. }
  10. if (k > n) {
  11. throw new TypeError('k must be less than or equal to n');
  12. }
  13. var nMinusk = n - k;
  14. var answer = 1;
  15. var firstnumerator = k < nMinusk ? nMinusk + 1 : k + 1;
  16. var nextdivisor = 2;
  17. var lastdivisor = k < nMinusk ? k : nMinusk;
  18. // balance multiplications and divisions to try to keep intermediate values
  19. // in exact-integer range as long as possible
  20. for (var nextnumerator = firstnumerator; nextnumerator <= n; ++nextnumerator) {
  21. answer *= nextnumerator;
  22. while (nextdivisor <= lastdivisor && answer % nextdivisor === 0) {
  23. answer /= nextdivisor;
  24. ++nextdivisor;
  25. }
  26. }
  27. // for big n, k, floating point may have caused weirdness in remainder
  28. if (nextdivisor <= lastdivisor) {
  29. answer /= product(nextdivisor, lastdivisor);
  30. }
  31. return answer;
  32. }
  33. combinationsNumber.signature = 'number, number';