a/math/numbers/factorial.rs
1//! Factorials and binomial coefficients: [`Number::factorial`] and [`Number::binomial`].
2//!
3//! Factorials of up to 34, and binomial coefficients below `2^128`, are computed in registers: the
4//! former from a table, the latter as the product of the odd parts of their factors modulo
5//! `2^128`, times a tabulated inverse (see [`binomial`]). Longer ones are computed on limbs of
6//! eight bytes, native `u64`s, the least significant first: many small factors are multiplied
7//! together into each limb first, and the limbs then by balanced product trees on the
8//! multiplication, so that the longest products take Karatsuba's and Toom-Cook's methods (see
9//! [`product`]).
10//!
11//! `n!` is `2^(n - popcount(n))` times its odd part, which Luschny's method computes from the
12//! prime factors of the swinging factorials (see [`odd`]), as GMP's `mpz_fac_ui` does. A binomial
13//! coefficient `C(n, k)` with a small `k` is a product of `k` consecutive numbers divided exactly
14//! by the odd part of `k!`; with a large one, it is the product of its prime factors, whose
15//! exponents Kummer's theorem gives, as GMP's `mpz_bin_uiui` does (see [`binomial`]). Either way
16//! the power of two is counted apart, and the result is written shifted, in the byte order asked
17//! for, in the shortest form.
18
19mod binomial;
20mod odd;
21mod primes;
22mod product;
23
24use super::mul::Product;
25use super::root::{lshift, small_number};
26use super::{ByteOrder, Number};
27
28/// The limbs of a magnitude, the least significant first, without zero limbs at the top.
29type Limbs = Vec<u64>;
30
31/// `n!` for `n` up to 34, the last below `2^128`.
32const FACTORIALS: [u128; 35] = {
33 let mut t = [1u128; 35];
34 let mut i = 1;
35 while i < 35 {
36 t[i] = t[i - 1] * i as u128;
37 i += 1;
38 }
39 t
40};
41
42impl Number {
43 /// Returns `n!`, the product of the integers from 1 to `n`, in the byte order `byte_order`, in
44 /// the shortest form, in one new vector; `0!` is 1.
45 ///
46 /// Up to 34, from a table; beyond, `2^(n - popcount(n))` times the odd part of `n!`, computed
47 /// by Luschny's method from the prime factors of the swinging factorials, with balanced
48 /// product trees on the multiplication, as GMP's `mpz_fac_ui` does.
49 ///
50 /// # Panics
51 ///
52 /// Only when the result or its working memory cannot be allocated, as for any vector: with
53 /// `capacity overflow` beyond `isize::MAX` bytes, and otherwise as the allocator fails.
54 ///
55 /// # Examples
56 ///
57 /// ```
58 /// use a::math::numbers::{ByteOrder, Number};
59 ///
60 /// assert_eq!(Number::factorial(5, ByteOrder::BigEndian).value, [120]);
61 /// // 25! = 15,511,210,043,330,985,984,000,000 = 0x0C_D4A0_619F_B090_7BC0_0000.
62 /// assert_eq!(
63 /// Number::factorial(25, ByteOrder::BigEndian).value,
64 /// [0x0C, 0xD4, 0xA0, 0x61, 0x9F, 0xB0, 0x90, 0x7B, 0xC0, 0x00, 0x00]
65 /// );
66 /// ```
67 pub fn factorial(n: u64, byte_order: ByteOrder) -> Number {
68 if n < FACTORIALS.len() as u64 {
69 return small_number(byte_order, FACTORIALS[n as usize], false);
70 }
71 long_factorial(n, byte_order)
72 }
73
74 /// Returns the binomial coefficient `C(n, k) = n! / (k! (n - k)!)`, the number of ways to
75 /// choose `k` things out of `n`, in the byte order `byte_order`, in the shortest form, in one
76 /// new vector; 0 for `k > n`.
77 ///
78 /// Coefficients below `2^128` are computed in registers. Beyond, for a `k` much smaller than
79 /// `n`, as the product of the `k` numbers from `n - k + 1` to `n` divided exactly by the odd
80 /// part of `k!`, and otherwise as the product of the coefficient's prime factors, whose
81 /// exponents are counted by Kummer's theorem, as GMP's `mpz_bin_uiui` does.
82 ///
83 /// # Panics
84 ///
85 /// Only when the result or its working memory cannot be allocated, as for any vector: with
86 /// `capacity overflow` beyond `isize::MAX` bytes, and otherwise as the allocator fails.
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// use a::math::numbers::{ByteOrder, Number};
92 ///
93 /// assert_eq!(Number::binomial(5, 2, ByteOrder::BigEndian).value, [10]);
94 /// assert_eq!(Number::binomial(2, 5, ByteOrder::BigEndian).value, [0]);
95 /// // C(100, 50) = 100,891,344,545,564,193,334,812,497,256
96 /// // = 0x01_45FF_5D3B_1070_380D_C808_5568.
97 /// assert_eq!(
98 /// Number::binomial(100, 50, ByteOrder::LittleEndian).value,
99 /// [0x68, 0x55, 0x08, 0xC8, 0x0D, 0x38, 0x70, 0x10, 0x3B, 0x5D, 0xFF, 0x45, 0x01]
100 /// );
101 /// ```
102 pub fn binomial(n: u64, k: u64, byte_order: ByteOrder) -> Number {
103 if k > n {
104 return small_number(byte_order, 0, false);
105 }
106 let k = k.min(n - k);
107 if let Some(c) = binomial::small(n, k) {
108 return small_number(byte_order, c, false);
109 }
110 long_binomial(n, k, byte_order)
111 }
112}
113
114/// `n!` for `n` above 34: the odd part shifted left by `n - popcount(n)` bits; on the stack below
115/// [`odd::SWING`].
116#[inline(never)]
117fn long_factorial(n: u64, order: ByteOrder) -> Number {
118 let shift = n - u64::from(n.count_ones());
119 if n < odd::SWING {
120 let mut x = [0u64; odd::SMALL_LIMBS + 1];
121 let mut small = [0u64; odd::SMALL_LIMBS];
122 let len = odd::small_odd_factorial(n, &mut small);
123 x[..len].copy_from_slice(&small[..len]);
124 return shifted_number(&mut x, len, shift, order);
125 }
126 let mut x = odd::odd_factorial(n);
127 let len = x.len();
128 x.push(0);
129 shifted_number(&mut x, len, shift, order)
130}
131
132/// `C(n, k)` for `k <= n - k`, above `2^128`.
133#[inline(never)]
134fn long_binomial(n: u64, k: u64, order: ByteOrder) -> Number {
135 binomial::long(n, k, |x, len, shift| shifted_number(x, len, shift, order))
136}
137
138/// The magnitude of the `len` limbs `x`, not zero, shifted left by `shift` bits, as a number in
139/// one new vector of exactly its length, in the byte order `order`: `x` shifted by the bits below a
140/// whole byte in place, into the limb after its own, which `x` must have, then written over the
141/// bytes above the `shift / 8` zero bytes at the low end.
142fn shifted_number(x: &mut [u64], mut len: usize, shift: u64, order: ByteOrder) -> Number {
143 let zeros = usize::try_from(shift / 8).expect("capacity overflow");
144 let bits = (shift % 8) as u32;
145 if bits != 0 {
146 // SAFETY: the slice holds the `len` limbs, shifted in place.
147 let out = unsafe { lshift(x.as_mut_ptr(), x.as_ptr(), len, bits) };
148 if out != 0 {
149 x[len] = out;
150 len += 1;
151 }
152 }
153 let top = x[len - 1];
154 let bytes = 8 * len - top.leading_zeros() as usize / 8;
155 let total = bytes.checked_add(zeros).expect("capacity overflow");
156 let p = Product {
157 r: x.as_ptr(),
158 len: bytes,
159 negative: false,
160 };
161 let mut v = Vec::with_capacity(total);
162 // SAFETY: the new vector has room for the `total` bytes, all of which are written before the
163 // length is set: the magnitude's and the zeros below it.
164 unsafe {
165 let dst = v.as_mut_ptr();
166 if order == ByteOrder::BigEndian {
167 p.write(dst, order);
168 core::ptr::write_bytes(dst.add(bytes), 0, zeros);
169 } else {
170 core::ptr::write_bytes(dst, 0, zeros);
171 p.write(dst.add(zeros), order);
172 }
173 v.set_len(total);
174 }
175 Number {
176 value: v,
177 negative: false,
178 byte_order: order,
179 }
180}