a/math/numbers/div/exact.rs
1//! Exact division and divisibility: [`Number::div_exact`] and [`Number::is_multiple_of`].
2//!
3//! When the divisor is known to divide the dividend, the quotient can be computed from the low
4//! end, by Hensel's method (see [`bdiv_q`]): each limb of the quotient is exact, with no estimate
5//! to correct, and the limbs of the partial remainder above the quotient's are never needed, so a
6//! quotient as long as the divisor takes about half the work of a division.
7
8use super::super::Number;
9use super::super::add::{read_small, small};
10use super::super::mul::{Operand, Product, STACK_LIMBS, on_heap, on_stack};
11use super::limbs::{DC_DIV, bdiv_q, binvert_limb, rshift};
12use super::{
13 TRUNCATED, Want, div_u128, divide, operands, register_division, result, small_division,
14 small_number, wide, wide_number,
15};
16use core::mem::MaybeUninit;
17
18/// From this many limb products of Hensel's method, an exact division by a divisor long enough
19/// for divide and conquer is left to the ordinary division, which that makes faster than the
20/// quadratic method: measured on an Apple M4 Max, a quotient of 512 limbs by a divisor of 512
21/// (131,072 products) took 156,842 cycles so against 173,462, one of 768 by 768 356,035 against
22/// 339,764, and one of 2048 by 256 605,302 against 454,124.
23const HENSEL_LIMIT: usize = 1 << 18;
24
25/// Whether an exact quotient of `qn` limbs by a divisor of `dn`, at least two, is computed by
26/// Hensel's method: below the divisors that divide and conquer divides, always, as both methods
27/// are quadratic there and Hensel's does half the work; beyond, up to [`HENSEL_LIMIT`] limb
28/// products: `qn m - m^2 / 2` for `m = min(qn, dn)`, as the divisor's limbs above the quotient's
29/// are never needed.
30fn by_hensel(qn: usize, dn: usize) -> bool {
31 let m = qn.min(dn);
32 dn < DC_DIV || qn * m - m * m / 2 < HENSEL_LIMIT
33}
34
35impl Number {
36 /// Returns `self / rhs` for a `rhs` that divides `self` exactly, faster than `/` does: in the
37 /// byte order of `self`, in the shortest form, in one new vector of exactly its length.
38 ///
39 /// The quotient is computed from the low end, by Hensel's method, whose limbs need no
40 /// estimates and whose partial remainders need no limbs above the quotient's: for a quotient
41 /// as long as the divisor, about half the work of a division. When `rhs` does not divide
42 /// `self`, the result is a number, but not a meaningful one; [`is_multiple_of`] tells.
43 ///
44 /// [`is_multiple_of`]: Self::is_multiple_of
45 ///
46 /// # Panics
47 ///
48 /// When `rhs` is zero.
49 ///
50 /// # Examples
51 ///
52 /// ```
53 /// use a::math::numbers::{ByteOrder, Number};
54 ///
55 /// // 0x0123_4567_89AB_CDEF * -7 = -0x07F6_E5D4_C3B2_A189, divided back by 7.
56 /// let a = Number::new_from_i64(-0x07F6_E5D4_C3B2_A189, ByteOrder::BigEndian);
57 /// let q = a.div_exact(&Number::new_from_i32(7, ByteOrder::LittleEndian));
58 /// assert_eq!(q.value, [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
59 /// assert!(q.is_negative());
60 /// ```
61 #[track_caller]
62 pub fn div_exact(&self, rhs: &Number) -> Number {
63 if small(self, rhs) {
64 let (q, _) = small_division::<TRUNCATED, false>(self, rhs);
65 return small_number(self.byte_order, q);
66 }
67 exact_quotient(self, rhs)
68 }
69
70 /// Returns whether `self` is a multiple of `rhs`: `self = rhs q` for an integer `q`, which is
71 /// to say that the remainder of `self` by `rhs` is zero. As for `u32::is_multiple_of`, zero is
72 /// a multiple of everything, and only zero is a multiple of zero. Signs do not count.
73 ///
74 /// Allocates nothing; a dividend shorter than the divisor, or with fewer zero bits at the low
75 /// end, is told apart without dividing.
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// use a::math::numbers::{ByteOrder, Number};
81 ///
82 /// let a = Number::new_from_i64(-1_000_000_000_007 * 13, ByteOrder::BigEndian);
83 /// assert!(a.is_multiple_of(&Number::new_from_u8(13, ByteOrder::LittleEndian)));
84 /// assert!(!a.is_multiple_of(&Number::new_from_u8(12, ByteOrder::LittleEndian)));
85 ///
86 /// let zero = Number::new_from_u8(0, ByteOrder::BigEndian);
87 /// assert!(zero.is_multiple_of(&zero));
88 /// assert!(!a.is_multiple_of(&zero));
89 /// ```
90 pub fn is_multiple_of(&self, rhs: &Number) -> bool {
91 if small(self, rhs) {
92 // SAFETY: both vectors hold at most 16 bytes.
93 let (x, y) = unsafe {
94 (
95 read_small(&self.value, self.byte_order),
96 read_small(&rhs.value, rhs.byte_order),
97 )
98 };
99 return if y == 0 {
100 x == 0
101 } else {
102 div_u128(x, y).1 == 0
103 };
104 }
105 multiple(self, rhs)
106 }
107}
108
109/// `a.div_exact(b)` for operands of which at least one has more than 16 bytes.
110#[inline(never)]
111#[track_caller]
112fn exact_quotient(a: &Number, b: &Number) -> Number {
113 let order = a.byte_order;
114 if wide(a, b) {
115 // SAFETY: the vectors hold at most 64 and 16 bytes.
116 let (q, _) = unsafe { register_division::<TRUNCATED, false>(a, b) };
117 return wide_number(order, &q);
118 }
119 let (x, y) = operands::<false>(a, b);
120 let (lx, ny) = (x.significant.div_ceil(8), y.significant.div_ceil(8));
121 let negative = (a.negative && x.significant != 0) != b.negative;
122 let place = |q: &Product| {
123 let mut v = Vec::with_capacity(q.len);
124 // SAFETY: the new vector has room for the `len` bytes, all of which are written before
125 // the length is set.
126 unsafe {
127 q.write(v.as_mut_ptr(), order);
128 v.set_len(q.len);
129 }
130 Number {
131 value: v,
132 negative: q.negative,
133 byte_order: order,
134 }
135 };
136 if ny == 1 || lx < ny || !by_hensel(lx - ny + 1, ny) {
137 // A divisor of one limb folds the limbs in about as fast as Hensel's method goes, and a
138 // long one divides faster by divide and conquer.
139 // SAFETY: the operands are those of `a` and `b`, borrowed until the quotient is written.
140 return unsafe {
141 divide::<TRUNCATED, _>(x, y, a.negative, b.negative, Want::Quotient, |q, _| {
142 place(q)
143 })
144 };
145 }
146 // SAFETY: as above.
147 unsafe { hensel(x, y, negative, place) }
148}
149
150/// The quotient of the operand `x` by the operand `y` of at least two limbs, assumed exact, by
151/// Hensel's method, handed to `place`. Both are shifted right by the zero bits at the low end of
152/// `y`, which `x` has too when the division is exact, so that the divisor is odd; only the
153/// quotient's `qn` low limbs of the dividend, and as many of the divisor, are read.
154///
155/// # Safety
156///
157/// The operands must describe vectors that stay valid for reads until `place` is called, `y` of
158/// at least two limbs and `x` at least as long.
159#[inline(always)]
160unsafe fn hensel<R>(
161 x: Operand,
162 y: Operand,
163 negative: bool,
164 place: impl FnOnce(&Product) -> R,
165) -> R {
166 let (lx, ny) = (x.significant.div_ceil(8), y.significant.div_ceil(8));
167 let qn = lx - ny + 1;
168 // SAFETY: as the caller guarantees.
169 let zeros = unsafe { trailing_zeros(y) };
170 let (skip, bits) = (zeros / 64, (zeros % 64) as u32);
171 // The divisor's limbs after the shift, of which the quotient's `qn` are needed.
172 let dn = (8 * y.significant - zeros).div_ceil(64).min(qn);
173 let need = 1 + (qn + 1) + (dn + 1) + qn;
174 let compute = |s: *mut MaybeUninit<u64>| {
175 let s: *mut u64 = s.cast();
176 // SAFETY: the working memory, on 16 bytes, holds a limb to place the dividend, its
177 // `qn + 1` limbs, the divisor's `dn + 1` and the quotient's `qn`.
178 unsafe {
179 // Step `i` subtracts a row of `qn - i` limbs from the dividend's limbs from `i`, of
180 // which the kernel takes an odd one first and then pairs: from limb `qn` modulo 2,
181 // whatever `i`, which this puts on 16 bytes. Off by 8, a quotient of 257 limbs by a
182 // divisor of 256 took 48,100 cycles against 38,000, on an Apple M4 Max.
183 let n = s.add(qn & 1);
184 let d = n.add(qn + 1);
185 let q = d.add(dn + 1);
186 limbs_from(x, skip, qn + 1, n);
187 limbs_from(y, skip, dn + 1, d);
188 if bits != 0 {
189 rshift(n, qn + 1, bits);
190 rshift(d, dn + 1, bits);
191 }
192 bdiv_q(q, n, qn, d, dn, binvert_limb(*d));
193 place(&result(q, qn, negative))
194 }
195 };
196 if need <= STACK_LIMBS {
197 on_stack(compute)
198 } else {
199 on_heap(need, compute)
200 }
201}
202
203/// `a.is_multiple_of(b)` for operands of which at least one has more than 16 bytes.
204#[inline(never)]
205fn multiple(a: &Number, b: &Number) -> bool {
206 let (x, y) = (Operand::of(a), Operand::of(b));
207 if y.significant == 0 || x.significant == 0 {
208 return x.significant == 0;
209 }
210 if x.significant < y.significant {
211 return false;
212 }
213 // SAFETY: both operands are not zero, and borrowed.
214 if unsafe { trailing_zeros(x) < trailing_zeros(y) } {
215 return false;
216 }
217 if wide(a, b) {
218 // SAFETY: the vectors hold at most 64 and 16 bytes, and the divisor is not zero.
219 let (_, r) = unsafe { register_division::<TRUNCATED, true>(a, b) };
220 return r.limbs == [0; 8];
221 }
222 // SAFETY: the operands are those of `a` and `b`, borrowed, and the divisor is not zero.
223 unsafe { divide::<TRUNCATED, _>(x, y, false, false, Want::Remainder, |_, r| r.r.is_null()) }
224}
225
226/// The number of zero bits at the low end of the magnitude of the operand `x`, not zero.
227///
228/// # Safety
229///
230/// The operand's vector must be valid for reads, and its magnitude not zero.
231unsafe fn trailing_zeros(x: Operand) -> usize {
232 let mut i = 0;
233 loop {
234 // SAFETY: the magnitude is not zero, so a limb that is not zero comes before its end.
235 let l = unsafe { super::limb(x, i) };
236 if l != 0 {
237 return 64 * i + l.trailing_zeros() as usize;
238 }
239 i += 1;
240 }
241}
242
243/// Reads limbs `from..from + n` of the magnitude of the operand `x`, zero above it, into the `n`
244/// limbs at `out`.
245///
246/// # Safety
247///
248/// The operand's vector must be valid for reads, and `out` for writing `n` limbs.
249#[inline(always)]
250unsafe fn limbs_from(x: Operand, from: usize, n: usize, out: *mut u64) {
251 // SAFETY: as the caller guarantees.
252 unsafe { super::shifted_limbs(x, from, from + n, 0, out) }
253}