Skip to content

Conversation

@orien
Copy link
Member

@orien orien commented Jan 2, 2026

Context

The nCk (binomial coefficient) calculation computes combinations using an iterative approach that loops from 1 to k. When k is large (e.g., calculating C(100, 95)), this results in many unnecessary iterations. The binomial coefficient has a mathematical symmetry property: C(n,k) = C(n,n-k), meaning the same result can be obtained by using the smaller value.

The symmetry exists because:

C(n,k) = n! / (k! × (n-k)!) = n! / ((n-k)! × k!) = C(n, n-k)

Changes

Modified the nCk method in lib/zxcvbn/math.rb to use the smaller of k or (n-k):

# Use symmetry property: C(n,k) = C(n, n-k)
# Choose smaller k to minimize iterations
k = n - k if k > n - k

This reduces loop iterations for large k values:

  • C(100, 95) now calculated as C(100, 5) - 5 iterations instead of 95
  • C(52, 47) now calculated as C(52, 5) - 5 iterations instead of 47
  • C(20, 15) now calculated as C(20, 5) - 5 iterations instead of 15

Consequences

Performance improvement: 6.6x faster (1.694µs → 0.256µs per calculation) for test cases with large k values.

All 291 tests pass, including existing tests that verify the symmetry property (C(10,3) = C(10,7) and C(20,5) = C(20,15)). The optimization uses a proven mathematical property and maintains identical behaviour whilst significantly improving performance.

When k > n-k, use the smaller value (n-k) to minimize loop iterations.
This significantly improves performance for large k values.

Performance improvement: 6.6x faster (1.694µs -> 0.256µs per calculation)
for test cases with large k values.

Example benefits:
- C(100, 95) now calculates as C(100, 5) - 5 iterations instead of 95
- C(52, 47) now calculates as C(52, 5) - 5 iterations instead of 47
@orien orien merged commit ce25ad1 into master Jan 2, 2026
18 checks passed
@orien orien deleted the optimize-nck-symmetry branch January 15, 2026 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants