ruint/
div.rs

1use crate::{algorithms, Uint};
2use core::ops::{Div, DivAssign, Rem, RemAssign};
3
4impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
5    /// Computes `self / rhs`, returning [`None`] if `rhs == 0`.
6    #[inline]
7    #[must_use]
8    #[allow(clippy::missing_const_for_fn)] // False positive
9    pub fn checked_div(self, rhs: Self) -> Option<Self> {
10        if rhs.is_zero() {
11            return None;
12        }
13        Some(self.div(rhs))
14    }
15
16    /// Computes `self % rhs`, returning [`None`] if `rhs == 0`.
17    #[inline]
18    #[must_use]
19    #[allow(clippy::missing_const_for_fn)] // False positive
20    pub fn checked_rem(self, rhs: Self) -> Option<Self> {
21        if rhs.is_zero() {
22            return None;
23        }
24        Some(self.rem(rhs))
25    }
26
27    /// Computes `self / rhs` rounding up.
28    ///
29    /// # Panics
30    ///
31    /// Panics if `rhs == 0`.
32    #[inline]
33    #[must_use]
34    #[track_caller]
35    pub fn div_ceil(self, rhs: Self) -> Self {
36        let (q, r) = self.div_rem(rhs);
37        if r.is_zero() {
38            q
39        } else {
40            q + Self::ONE
41        }
42    }
43
44    /// Computes `self / rhs` and `self % rhs`.
45    ///
46    /// # Panics
47    ///
48    /// Panics if `rhs == 0`.
49    #[inline(always)]
50    #[must_use]
51    #[track_caller]
52    pub fn div_rem(mut self, mut rhs: Self) -> (Self, Self) {
53        if LIMBS == 1 {
54            let q = &mut self.limbs[0];
55            let r = &mut rhs.limbs[0];
56            (*q, *r) = algorithms::div::div_1x1(*q, *r);
57        } else {
58            Self::div_rem_by_ref(&mut self, &mut rhs);
59        }
60        (self, rhs)
61    }
62
63    #[inline(never)]
64    pub(crate) fn div_rem_by_ref(numerator: &mut Self, rhs: &mut Self) {
65        algorithms::div::div_inlined(&mut numerator.limbs, &mut rhs.limbs);
66    }
67
68    /// Computes `self / rhs` rounding down.
69    ///
70    /// # Panics
71    ///
72    /// Panics if `rhs == 0`.
73    #[inline]
74    #[must_use]
75    #[track_caller]
76    pub fn wrapping_div(self, rhs: Self) -> Self {
77        self.div_rem(rhs).0
78    }
79
80    /// Computes `self % rhs`.
81    ///
82    /// # Panics
83    ///
84    /// Panics if `rhs == 0`.
85    #[inline]
86    #[must_use]
87    #[track_caller]
88    pub fn wrapping_rem(self, rhs: Self) -> Self {
89        self.div_rem(rhs).1
90    }
91}
92
93impl_bin_op!(Div, div, DivAssign, div_assign, wrapping_div);
94impl_bin_op!(Rem, rem, RemAssign, rem_assign, wrapping_rem);
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use crate::{const_for, nlimbs};
100    use proptest::{prop_assume, proptest};
101
102    #[test]
103    fn test_div_ceil() {
104        const_for!(BITS in NON_ZERO {
105            const LIMBS: usize = nlimbs(BITS);
106            type U = Uint<BITS, LIMBS>;
107            proptest!(|(n: U, mut d: U)| {
108                d >>= BITS / 2; // make d small
109                prop_assume!(d != U::ZERO);
110                let qf = n / d;
111                let qc = n.div_ceil(d);
112                assert!(qf <= qc);
113                assert!(qf == qc || qf == qc - U::ONE);
114                if qf == qc {
115                    assert!(n % d == U::ZERO);
116                }
117            });
118        });
119    }
120
121    #[test]
122    fn test_divrem() {
123        const_for!(BITS in NON_ZERO {
124            const LIMBS: usize = nlimbs(BITS);
125            type U = Uint<BITS, LIMBS>;
126            proptest!(|(n: U, mut d: u64)| {
127                if BITS < 64 {
128                    d &= U::MASK;
129                }
130                if d == 0 {
131                    d = 1;
132                }
133                let d = U::from(d);
134                let (q, r) = n.div_rem(d);
135                assert!(r < d);
136                assert_eq!(q * d + r, n);
137            });
138            proptest!(|(n: U, mut d: U)| {
139                d >>= BITS / 2; // make d small
140                prop_assume!(d != U::ZERO);
141                let (q, r) = n.div_rem(d);
142                assert!(r < d);
143                assert_eq!(q * d + r, n);
144            });
145            proptest!(|(n: U, d: U)| {
146                prop_assume!(d != U::ZERO);
147                let (q, r) = n.div_rem(d);
148                assert!(r < d);
149                assert_eq!(q * d + r, n);
150            });
151        });
152    }
153}