Skip to main content

malachite_nz/natural/arithmetic/
binomial_coefficient.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Contributed to the GNU project by Torbjörn Granlund and Marco Bodrato.
6//
7//      Copyright © 1998-2012, 2013, 2015-2018 Free Software Foundation, Inc.
8//
9// This file is part of Malachite.
10//
11// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
12// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
13// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
14
15use crate::natural::arithmetic::div::limbs_hensel_div_limb_in_place;
16use crate::natural::arithmetic::div_exact::{
17    limbs_modular_div_schoolbook_in_place, limbs_modular_invert_limb,
18};
19use crate::natural::arithmetic::div_round::double_cmp;
20use crate::natural::arithmetic::factorial::{bit_to_n, limbs_odd_factorial, log_n_max};
21use crate::natural::arithmetic::mul::limb::limbs_slice_mul_limb_in_place;
22use crate::natural::arithmetic::mul::limbs_mul;
23use crate::natural::arithmetic::mul::product_of_limbs::limbs_product;
24use crate::natural::arithmetic::neg::limbs_neg_in_place;
25use crate::natural::arithmetic::shl::limbs_slice_shl_in_place;
26use crate::natural::{Natural, bit_to_limb_count_floor};
27use crate::platform::{
28    CENTRAL_BINOMIAL_2FAC_TABLE, Limb, ODD_CENTRAL_BINOMIAL_OFFSET,
29    ODD_CENTRAL_BINOMIAL_TABLE_LIMIT, ODD_FACTORIAL_EXTTABLE_LIMIT, ODD_FACTORIAL_TABLE_LIMIT,
30    ODD_FACTORIAL_TABLE_MAX, ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE,
31    ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE, ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE,
32    ONE_LIMB_ODD_FACTORIAL_TABLE, TABLE_2N_MINUS_POPC_2N,
33};
34use alloc::vec::Vec;
35use core::cmp::{Ordering::*, max, min};
36use malachite_base::num::arithmetic::traits::{
37    AddMulAssign, BinomialCoefficient, DivAssignMod, DivExact, Parity, PowerOf2, Square,
38    WrappingAddAssign,
39};
40use malachite_base::num::basic::integers::PrimitiveInt;
41use malachite_base::num::basic::traits::{One, Zero};
42use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
43#[cfg(feature = "32_bit_limbs")]
44use malachite_base::num::factorization::prime_sieve::limbs_prime_sieve_u32;
45#[cfg(not(feature = "32_bit_limbs"))]
46use malachite_base::num::factorization::prime_sieve::limbs_prime_sieve_u64;
47use malachite_base::num::factorization::prime_sieve::{id_to_n, limbs_prime_sieve_size, n_to_bit};
48use malachite_base::num::logic::traits::{CountOnes, LeadingZeros, SignificantBits};
49
50// This is similar to `mulfunc` from `mpz/bin_uiui.c`, GMP 6.2.1.
51const fn apply_mul_func(n: Limb, m: Limb) -> Limb {
52    match n {
53        1 => m,
54        2 => (m | 1) * ((m + 1) >> 1),
55        3 => {
56            let m01 = (m * (m + 1)) >> 1;
57            let m2 = m + 2;
58            m01 * m2
59        }
60        4 => {
61            let m03 = (m * (m + 3)) >> 1;
62            m03 * (m03 + 1)
63        }
64        5 => {
65            let m03 = (m * (m + 3)) >> 1;
66            let m034 = m03 * (m + 4);
67            (m03 + 1) * m034
68        }
69        6 => {
70            let m05 = m * (m + 5);
71            let m1234 = ((m05 + 5) * (m05 + 5)) >> 3;
72            m1234 * (m05 >> 1)
73        }
74        7 => {
75            let m05 = m * (m + 5);
76            let m1234 = ((m05 + 5) * (m05 + 5)) >> 3;
77            let m056 = (m05 * (m + 6)) >> 1;
78            m1234 * m056
79        }
80        8 => {
81            let m07 = m * (m + 7);
82            let m0257 = (m07 * (m07 + 10)) >> 3;
83            let m1346 = m07 + 9 + m0257;
84            m0257 * m1346
85        }
86        _ => panic!(),
87    }
88}
89
90const M: Limb = 8;
91
92const SOME_THRESHOLD: usize = 20;
93
94// This is equivalent to `mpz_bdiv_bin_uiui` from `mpz/bin_uiui.c`, GMP 6.2.1, where a `Vec` of
95// limbs is returned.
96pub_test! {limbs_binomial_coefficient_limb_limb_bdiv(n: Limb, k: Limb) -> Vec<Limb> {
97    assert!(k > Limb::wrapping_from(ODD_FACTORIAL_TABLE_LIMIT));
98    let max_n = 1 + usize::exact_from(n >> Limb::LOG_WIDTH);
99    let alloc = min(
100        SOME_THRESHOLD - 1 + max((3 * max_n) >> 1, SOME_THRESHOLD),
101        usize::exact_from(k),
102    ) + 1;
103    let mut big_scratch = vec![0; alloc + SOME_THRESHOLD + 1];
104    let (ns, ks) = big_scratch.split_at_mut(alloc);
105    let n_max = Limb::wrapping_from(log_n_max(n));
106    assert!(n_max <= M);
107    let mut k_max = Limb::wrapping_from(log_n_max(k));
108    assert!(k_max <= M);
109    assert!(k >= M);
110    assert!(n >= k);
111    let mut i = n - k + 1;
112    ns[0] = 1;
113    let mut n_len = 1;
114    let mut num_fac = 1;
115    let mut j = Limb::wrapping_from(ODD_FACTORIAL_TABLE_LIMIT + 1);
116    let mut jjj = ODD_FACTORIAL_TABLE_MAX;
117    assert_eq!(
118        ONE_LIMB_ODD_FACTORIAL_TABLE[ODD_FACTORIAL_TABLE_LIMIT],
119        ODD_FACTORIAL_TABLE_MAX
120    );
121    loop {
122        ks[0] = jjj;
123        let mut k_len = 1;
124        let mut t = k + 1 - j;
125        k_max = min(k_max, t);
126        while k_max != 0 && k_len < SOME_THRESHOLD {
127            jjj = apply_mul_func(k_max, j);
128            j += k_max;
129            jjj >>= jjj.trailing_zeros();
130            let cy = limbs_slice_mul_limb_in_place(&mut ks[..k_len], jjj);
131            ks[k_len] = cy;
132            if cy != 0 {
133                k_len += 1;
134            }
135            t = k + 1 - j;
136            k_max = min(k_max, t);
137        }
138        num_fac = j - num_fac;
139        while num_fac != 0 {
140            let n_max_now = min(n_max, num_fac);
141            let mut iii = apply_mul_func(n_max_now, i);
142            i.wrapping_add_assign(n_max_now);
143            iii >>= iii.trailing_zeros();
144            let carry = limbs_slice_mul_limb_in_place(&mut ns[..n_len], iii);
145            ns[n_len] = carry;
146            if carry != 0 {
147                n_len += 1;
148            }
149            num_fac -= n_max_now;
150        }
151        if ns[n_len - 1] >= ks[k_len - 1] {
152            n_len += 1;
153        }
154        n_len -= k_len;
155        let d_inv = limbs_modular_invert_limb(ks[0]);
156        limbs_modular_div_schoolbook_in_place(ns, &ks[..min(k_len, n_len)], d_inv.wrapping_neg());
157        limbs_neg_in_place(&mut ns[..n_len]);
158        if k_max == 0 {
159            break;
160        }
161        num_fac = j;
162        jjj = apply_mul_func(k_max, j);
163        j += k_max;
164        jjj >>= jjj.trailing_zeros();
165    }
166    // Put back the right number of factors of 2.
167    let ones = CountOnes::count_ones(n - k) + CountOnes::count_ones(k) - CountOnes::count_ones(n);
168    if ones != 0 {
169        assert!(ones < Limb::WIDTH);
170        let carry = limbs_slice_shl_in_place(&mut ns[..n_len], ones);
171        ns[n_len] = carry;
172        if carry != 0 {
173            n_len += 1;
174        }
175    }
176    if ns[n_len - 1] == 0 {
177        n_len -= 1;
178    }
179    let mut ns = big_scratch;
180    ns.truncate(n_len);
181    ns
182}}
183
184// Number of factors-of-2 removed by the corresponding mulN function.
185//
186// This is equivalent to `tcnttab` from `mpz/bin_uiui.c`, GMP 6.2.1.
187const TCNT_TAB: [u8; 8] = [0, 1, 1, 2, 2, 4, 4, 6];
188
189// This is equivalent to `mpz_smallk_bin_uiui` from `mpz/bin_uiui.c`, GMP 6.2.1, where a `Vec` of
190// limbs is returned.
191pub_test! {limbs_binomial_coefficient_limb_limb_small_k(n: Limb, k: Limb) -> Vec<Limb> {
192    let n_max = Limb::wrapping_from(log_n_max(n));
193    let mut n_max = min(n_max, M);
194    let mut i = n - k + 1;
195    let k_u = usize::exact_from(k);
196    assert!(k_u <= ODD_FACTORIAL_TABLE_LIMIT);
197    let mut i2_count = TABLE_2N_MINUS_POPC_2N[(k_u >> 1) - 1];
198    let factorial_inverse = ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE[k_u - 2];
199    if n_max >= k {
200        return vec![
201            (apply_mul_func(k, i).wrapping_mul(factorial_inverse))
202                >> (i2_count - TCNT_TAB[k_u - 1]),
203        ];
204    }
205    let alloc =
206        bit_to_limb_count_floor(n.significant_bits() * u64::exact_from(k)) + 3;
207    let mut out = vec![0; alloc];
208    out[0] = apply_mul_func(n_max, i);
209    let mut out_len = 1;
210    i += n_max;
211    i2_count -= TCNT_TAB[usize::exact_from(n_max - 1)];
212    let mut num_fac = k - n_max;
213    while num_fac != 0 {
214        n_max = min(n_max, num_fac);
215        let iii = apply_mul_func(n_max, i);
216        i.wrapping_add_assign(n_max);
217        i2_count -= TCNT_TAB[usize::exact_from(n_max - 1)];
218        let carry = limbs_slice_mul_limb_in_place(&mut out[..out_len], iii);
219        out[out_len] = carry;
220        if carry != 0 {
221            out_len += 1;
222        }
223        num_fac -= n_max;
224    }
225    assert!(out_len < alloc);
226    limbs_hensel_div_limb_in_place(
227        &mut out[..out_len],
228        ONE_LIMB_ODD_FACTORIAL_TABLE[k_u],
229        factorial_inverse,
230        u64::from(i2_count),
231    );
232    while *out.last().unwrap() == 0 {
233        out.pop();
234    }
235    out
236}}
237
238// Tabulate factorials (k!/2^t)^(-1) mod B (where t is chosen such that k!/2^t is odd).
239//
240// This is equivalent to `bc_bin_uiui` from `mpz/bin_uiui.c`, GMP 6.2.1, where a single limb is
241// returned.
242pub_test! {limbs_binomial_coefficient_limb_limb_basecase(n: Limb, k: Limb) -> Limb {
243    assert!(n <= ODD_FACTORIAL_EXTTABLE_LIMIT as Limb);
244    assert!(n >= k + 2);
245    assert!(k >= 2);
246    let n = usize::wrapping_from(n);
247    let k = usize::wrapping_from(k);
248    let diff = n - k;
249    (ONE_LIMB_ODD_FACTORIAL_TABLE[n]
250        .wrapping_mul(ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE[k - 2])
251        .wrapping_mul(ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE[diff - 2]))
252        << (TABLE_2N_MINUS_POPC_2N[(n >> 1) - 1]
253            - TABLE_2N_MINUS_POPC_2N[(k >> 1) - 1]
254            - TABLE_2N_MINUS_POPC_2N[(diff >> 1) - 1])
255}}
256
257pub(crate) const BIN_UIUI_RECURSIVE_SMALLDC: bool = Limb::WIDTH > u32::WIDTH;
258
259// Recursively exploit the relation bin(n, k) = bin(n, k >> 1) * bin(n - k >> 1, k - k >> 1) /
260// bin(k, k >> 1).
261//
262// Values for binomial(k, k >> 1) that fit in a limb are precomputed (with inverses).
263//
264// This is equivalent to `mpz_smallkdc_bin_uiui` from `mpz/bin_uiui.c`, GMP 6.2.1, where a `Vec` of
265// limbs is returned.
266pub_test! {limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(
267    mut n: Limb,
268    mut k: Limb,
269) -> Vec<Limb> {
270    let half_k = k >> 1;
271    let mut out = if !BIN_UIUI_RECURSIVE_SMALLDC || half_k <= ODD_FACTORIAL_TABLE_LIMIT as Limb {
272        limbs_binomial_coefficient_limb_limb_small_k(n, half_k)
273    } else {
274        limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(n, half_k)
275    };
276    k -= half_k;
277    n -= half_k;
278    let mut out_len = out.len();
279    if n <= ODD_FACTORIAL_EXTTABLE_LIMIT as Limb {
280        out.push(0);
281        let carry = limbs_slice_mul_limb_in_place(
282            &mut out[..out_len],
283            limbs_binomial_coefficient_limb_limb_basecase(n, k),
284        );
285        out[out_len] = carry;
286        if carry != 0 {
287            out_len += 1;
288        }
289    } else {
290        let t = if !BIN_UIUI_RECURSIVE_SMALLDC || k <= ODD_FACTORIAL_TABLE_LIMIT as Limb {
291            limbs_binomial_coefficient_limb_limb_small_k(n, k)
292        } else {
293            limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(n, k)
294        };
295        let out_copy = out[..out_len].to_vec();
296        out = limbs_mul(&out_copy, &t);
297        out_len = out.len();
298    }
299    let k_u = usize::exact_from(k);
300    let mut shift = CENTRAL_BINOMIAL_2FAC_TABLE[k_u - ODD_CENTRAL_BINOMIAL_OFFSET];
301    if k != half_k {
302        // k was odd
303        shift -= 1;
304    }
305    let k_offset = k_u - ODD_CENTRAL_BINOMIAL_OFFSET;
306    limbs_hensel_div_limb_in_place(
307        &mut out[..out_len],
308        ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE[k_offset],
309        ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE[k_offset],
310        shift,
311    );
312    while *out.last().unwrap() == 0 {
313        out.pop();
314    }
315    out
316}}
317
318// Returns an approximation of the square root of x. It gives:
319// ```
320//   limb_apprsqrt (x) ^ 2 <= x < (limb_apprsqrt (x)+1) ^ 2
321// ```
322// or
323// ```
324// x <= limb_apprsqrt (x) ^ 2 <= x * 9/8
325// ```
326fn limbs_approx_sqrt(x: Limb) -> Limb {
327    assert!(x > 2);
328    let s = (Limb::WIDTH - LeadingZeros::leading_zeros(x)) >> 1;
329    (Limb::power_of_2(s) + (x >> s)) >> 1
330}
331
332pub(crate) const BIN_GOETGHELUCK_THRESHOLD: Limb = 512;
333
334// Implementation of the algorithm by P. Goetgheluck, "Computing Binomial Coefficients", The
335// American Mathematical Monthly, Vol. 94, No. 4 (April 1987), pp. 360-365.
336//
337// This is equivalent to `mpz_goetgheluck_bin_uiui` from `mpz/bin_uiui.c`, GMP 6.2.1, where a `Vec`
338// of limbs is returned.
339pub_test! {
340#[allow(clippy::useless_conversion)]
341limbs_binomial_coefficient_limb_limb_goetgheluck(n: Limb, k: Limb) -> Vec<Limb> {
342    assert!(BIN_GOETGHELUCK_THRESHOLD >= 13);
343    assert!(n >= 25);
344    let n_64 = u64::from(n);
345    let k_64 = u64::from(k);
346    let mut sieve = vec![0; limbs_prime_sieve_size::<Limb>(n_64)];
347    #[cfg(feature = "32_bit_limbs")]
348    let count = limbs_prime_sieve_u32(&mut sieve, n_64) + 1;
349    #[cfg(not(feature = "32_bit_limbs"))]
350    let count = limbs_prime_sieve_u64(&mut sieve, n) + 1;
351    let mut factors = vec![0; usize::exact_from(count / log_n_max(n) + 1)];
352    let mut max_prod = Limb::MAX / n;
353    // Handle primes = 2, 3 separately.
354    let mut prod = Limb::power_of_2(
355        CountOnes::count_ones(n - k) + CountOnes::count_ones(k) - CountOnes::count_ones(n),
356    );
357    let mut j = 0;
358    let mut a = n;
359    let mut b = k;
360    let mut mb = 0;
361    if prod > max_prod {
362        // would only happen for very large outputs
363        factors[j] = prod;
364        j += 1;
365        prod = 1;
366    }
367    while a >= 3 {
368        mb += b.div_assign_mod(3);
369        let ma = a.div_assign_mod(3);
370        if ma < mb {
371            mb = 1;
372            prod *= 3;
373        } else {
374            mb = 0;
375        }
376    }
377    // Accumulate prime factors from 5 to n / 2
378    let s = n_to_bit(u64::from(limbs_approx_sqrt(n)));
379    assert!(bit_to_n(s + 1).square() > n_64);
380    let half_n_bit = n_to_bit(n_64 >> 1);
381    assert!(s <= half_n_bit);
382    let mut index = 0;
383    let mut mask = 1;
384    for i in 1..=s + 1 {
385        if sieve[index] & mask == 0 {
386            let prime = Limb::exact_from(id_to_n(i));
387            let mut a = n;
388            let mut b = k;
389            let mut mb = 0;
390            if prod > max_prod {
391                factors[j] = prod;
392                j += 1;
393                prod = 1;
394            }
395            while a >= prime {
396                mb += b.div_assign_mod(prime);
397                let ma = a.div_assign_mod(prime);
398                if ma < mb {
399                    mb = 1;
400                    prod *= prime;
401                } else {
402                    mb = 0;
403                }
404            }
405        }
406        mask <<= 1;
407        if mask == 0 {
408            mask = 1;
409            index += 1;
410        }
411    }
412    assert!(max_prod <= Limb::MAX >> 1);
413    max_prod <<= 1;
414    for i in s + 2..=half_n_bit + 1 {
415        if sieve[index] & mask == 0 {
416            let prime = Limb::exact_from(id_to_n(i));
417            if n % prime < k % prime {
418                if prod > max_prod {
419                    factors[j] = prod;
420                    j += 1;
421                    prod = prime;
422                } else {
423                    prod *= prime;
424                }
425            }
426        }
427        mask <<= 1;
428        if mask == 0 {
429            mask = 1;
430            index += 1;
431        }
432    }
433    max_prod >>= 1;
434    // Store primes from (n-k)+1 to n
435    let n_bit = n_to_bit(n_64);
436    let n_minus_k_bit = n_to_bit(n_64 - k_64);
437    assert!(n_minus_k_bit < n_bit);
438    let i = n_minus_k_bit + 1;
439    let mut index = bit_to_limb_count_floor(i);
440    let mut mask = Limb::power_of_2(i & Limb::WIDTH_MASK);
441    for i in i + 1..=n_bit + 1 {
442        if sieve[index] & mask == 0 {
443            let prime = Limb::exact_from(id_to_n(i));
444            if prod > max_prod {
445                factors[j] = prod;
446                j += 1;
447                prod = prime;
448            } else {
449                prod *= prime;
450            }
451        }
452        mask <<= 1;
453        if mask == 0 {
454            mask = 1;
455            index += 1;
456        }
457    }
458    assert_ne!(j, 0);
459    factors[j] = Limb::wrapping_from(prod);
460    j += 1;
461    let mut r = Vec::new();
462    let (size, new_r) = limbs_product(&mut r, &mut factors[..j]);
463    r = new_r.unwrap();
464    r.truncate(size);
465    r
466}}
467
468const BIN_UIUI_ENABLE_SMALLDC: bool = true;
469
470// This is equivalent to `mpz_bin_uiui` from `mpz/bin_uiui.c`, GMP 6.2.1, where a `Natural` is
471// returned.
472pub_test! {binomial_coefficient_limb_limb(n: Limb, mut k: Limb) -> Natural {
473    if n < k {
474        Natural::ZERO
475    } else {
476        // Rewrite bin(n, k) as bin(n, n - k) if that is smaller.
477        k = min(k, n - k);
478        if k == 0 {
479            Natural::ONE
480        } else if k == 1 {
481            Natural::from(n)
482        } else if n <= ODD_FACTORIAL_EXTTABLE_LIMIT as Limb {
483            // k >= 2, n >= 4
484            Natural::from(limbs_binomial_coefficient_limb_limb_basecase(n, k))
485        } else if k <= ODD_FACTORIAL_TABLE_LIMIT as Limb {
486            Natural::from_owned_limbs_asc(limbs_binomial_coefficient_limb_limb_small_k(n, k))
487        } else if BIN_UIUI_ENABLE_SMALLDC
488            && k <= (if BIN_UIUI_RECURSIVE_SMALLDC {
489                ODD_CENTRAL_BINOMIAL_TABLE_LIMIT
490            } else {
491                ODD_FACTORIAL_TABLE_LIMIT
492            } as Limb)
493                << 1
494        {
495            Natural::from_owned_limbs_asc(
496                limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(n, k),
497            )
498        } else if k >= BIN_GOETGHELUCK_THRESHOLD && k > n >> 4 {
499            // k > ODD_FACTORIAL_TABLE_LIMIT
500            Natural::from_owned_limbs_asc(limbs_binomial_coefficient_limb_limb_goetgheluck(n, k))
501        } else {
502            Natural::from_owned_limbs_asc(limbs_binomial_coefficient_limb_limb_bdiv(n, k))
503        }
504    }
505}}
506
507// Computes r = n * (n + (2 * k - 1)) / 2.
508//
509// It uses a square instead of a product, computing r = ((n + k - 1) ^ 2 + n - (k - 1) ^ 2) / 2 As a
510// side effect, sets t = n + k - 1.
511//
512// This is equivalent to `mpz_hmul_nbnpk` from `mpz/bin_ui.c`, GMP 6.2.1.
513fn binomial_coefficient_hmul_nbnpk(n: &Natural, mut k: Limb) -> Natural {
514    assert_ne!(k, 0);
515    assert_ne!(*n, 0u32);
516    k -= 1;
517    (((n + Natural::from(k)).square() + n) >> 1u32)
518        - Natural::from(k + (k & 1)) * Natural::from(k >> 1)
519}
520
521// This is equivalent to `rek_raising_fac4` from `mpz/bin_ui.c`, GMP 6.2.1.
522fn binomial_coefficient_raising_factorial_4_rec(
523    r: &mut Natural,
524    p: &mut Natural,
525    big_p: &mut Natural,
526    k: Limb,
527    lk: Limb,
528) {
529    assert!(k >= lk);
530    if k - lk < 5 {
531        for i in (lk + 1..=k).rev() {
532            let four_i = i << 2;
533            *p += Natural::from(four_i + 2);
534            big_p.add_mul_assign(&*p, Natural::from(four_i));
535            *big_p -= Natural::from(i);
536            *r *= &*big_p;
537        }
538    } else {
539        let m = ((k + lk) >> 1) + 1;
540        binomial_coefficient_raising_factorial_4_rec(r, p, big_p, k, m);
541        let four_m = m << 2;
542        *p += Natural::from(four_m + 2);
543        big_p.add_mul_assign(&*p, Natural::from(four_m));
544        *big_p -= Natural::from(m);
545        let mut t = big_p.clone();
546        binomial_coefficient_raising_factorial_4_rec(&mut t, p, big_p, m - 1, lk);
547        *r *= t;
548    }
549}
550
551// This is equivalent to `mpz_raising_fac4` from `mpz/bin_ui.c`, GMP 6.2.1, where r is returned.
552fn binomial_coefficient_raising_factorial_4(mut n: Natural, mut k: Limb) -> Natural {
553    assert!(k >= 2);
554    n += Natural::ONE;
555    let mut r = Natural::ZERO;
556    if k.odd() {
557        r = n.clone();
558        n += Natural::ONE;
559    }
560    k >>= 1;
561    let mut p = binomial_coefficient_hmul_nbnpk(&n, k);
562    if k.odd() {
563        if r != 0u32 {
564            r *= &p;
565        } else {
566            r = p.clone();
567        }
568        p += Natural::from(k - 1);
569    }
570    k >>= 1;
571    if k == 0 {
572        return r;
573    }
574    let mut t = binomial_coefficient_hmul_nbnpk(&p, k);
575    if r != 0u32 {
576        r *= &t;
577    } else {
578        r = t.clone();
579    }
580    if k > 1 {
581        p -= Natural::from(k);
582        binomial_coefficient_raising_factorial_4_rec(&mut r, &mut p, &mut t, k - 1, 0);
583    }
584    r
585}
586
587// This is equivalent to `mpz_bin_ui` from `mpz/bin_ui.c`, GMP 6.2.1, where n is non-negative, n >=
588// k, k <= n - k, and r is returned.
589fn binomial_coefficient_helper(n: Natural, k: Limb) -> Natural {
590    assert_ne!(k, 0);
591    if k < 2 {
592        n
593    } else if let Ok(small_n) = Limb::try_from(&n) {
594        binomial_coefficient_limb_limb(small_n, k)
595    } else {
596        (binomial_coefficient_raising_factorial_4(n - Natural::from(k), k)
597            >> (k - (k >> 1) - (k >> 2))
598                .checked_sub(Limb::wrapping_from(CountOnes::count_ones(k)))
599                .unwrap())
600        .div_exact(Natural::from_owned_limbs_asc(limbs_odd_factorial(
601            usize::exact_from(k),
602            false,
603        )))
604    }
605}
606
607impl BinomialCoefficient for Natural {
608    /// Computes the binomial coefficient of two [`Natural`]s, taking both by value.
609    ///
610    /// $$
611    /// f(n, k) =binom{n}{k} =frac{n!}{k!(n-k)!}.
612    /// $$
613    ///
614    /// # Worst-case complexity
615    /// TODO
616    ///
617    /// # Examples
618    /// ```
619    /// use malachite_base::num::arithmetic::traits::BinomialCoefficient;
620    /// use malachite_nz::natural::Natural;
621    ///
622    /// assert_eq!(
623    ///     Natural::binomial_coefficient(Natural::from(4u32), Natural::from(0u32)),
624    ///     1
625    /// );
626    /// assert_eq!(
627    ///     Natural::binomial_coefficient(Natural::from(4u32), Natural::from(1u32)),
628    ///     4
629    /// );
630    /// assert_eq!(
631    ///     Natural::binomial_coefficient(Natural::from(4u32), Natural::from(2u32)),
632    ///     6
633    /// );
634    /// assert_eq!(
635    ///     Natural::binomial_coefficient(Natural::from(4u32), Natural::from(3u32)),
636    ///     4
637    /// );
638    /// assert_eq!(
639    ///     Natural::binomial_coefficient(Natural::from(4u32), Natural::from(4u32)),
640    ///     1
641    /// );
642    /// assert_eq!(
643    ///     Natural::binomial_coefficient(Natural::from(10u32), Natural::from(5u32)),
644    ///     252
645    /// );
646    /// assert_eq!(
647    ///     Natural::binomial_coefficient(Natural::from(100u32), Natural::from(50u32)).to_string(),
648    ///     "100891344545564193334812497256"
649    /// );
650    /// ```
651    fn binomial_coefficient(n: Self, mut k: Self) -> Self {
652        if k > n {
653            return Self::ZERO;
654        }
655        if k == 0u32 || n == k {
656            return Self::ONE;
657        }
658        if double_cmp(&k, &n) == Greater {
659            k = &n - &k;
660        }
661        binomial_coefficient_helper(n, Limb::try_from(&k).expect("k is too large"))
662    }
663}
664
665impl<'a> BinomialCoefficient<&'a Self> for Natural {
666    /// Computes the binomial coefficient of two [`Natural`]s, taking both by reference.
667    ///
668    /// $$
669    /// f(n, k) =binom{n}{k} =frac{n!}{k!(n-k)!}.
670    /// $$
671    ///
672    /// # Worst-case complexity
673    /// TODO
674    ///
675    /// # Examples
676    /// ```
677    /// use malachite_base::num::arithmetic::traits::BinomialCoefficient;
678    /// use malachite_nz::natural::Natural;
679    ///
680    /// assert_eq!(
681    ///     Natural::binomial_coefficient(&Natural::from(4u32), &Natural::from(0u32)),
682    ///     1
683    /// );
684    /// assert_eq!(
685    ///     Natural::binomial_coefficient(&Natural::from(4u32), &Natural::from(1u32)),
686    ///     4
687    /// );
688    /// assert_eq!(
689    ///     Natural::binomial_coefficient(&Natural::from(4u32), &Natural::from(2u32)),
690    ///     6
691    /// );
692    /// assert_eq!(
693    ///     Natural::binomial_coefficient(&Natural::from(4u32), &Natural::from(3u32)),
694    ///     4
695    /// );
696    /// assert_eq!(
697    ///     Natural::binomial_coefficient(&Natural::from(4u32), &Natural::from(4u32)),
698    ///     1
699    /// );
700    /// assert_eq!(
701    ///     Natural::binomial_coefficient(&Natural::from(10u32), &Natural::from(5u32)),
702    ///     252
703    /// );
704    /// assert_eq!(
705    ///     Natural::binomial_coefficient(&Natural::from(100u32), &Natural::from(50u32))
706    ///         .to_string(),
707    ///     "100891344545564193334812497256"
708    /// );
709    /// ```
710    fn binomial_coefficient(n: &'a Self, k: &'a Self) -> Self {
711        if k > n {
712            return Self::ZERO;
713        }
714        if *k == 0u32 || n == k {
715            return Self::ONE;
716        }
717        let k = if double_cmp(k, n) == Greater {
718            Limb::try_from(&(n - k))
719        } else {
720            Limb::try_from(k)
721        }
722        .expect("k is too large");
723        binomial_coefficient_helper(n.clone(), k)
724    }
725}