Skip to main content

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}