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 == Self::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 == Self::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        assert!(rhs != Self::ZERO, "Division by zero");
37        let (q, r) = self.div_rem(rhs);
38        if r == Self::ZERO {
39            q
40        } else {
41            q + Self::from(1)
42        }
43    }
44
45    /// Computes `self / rhs` and `self % rhs`.
46    ///
47    /// # Panics
48    ///
49    /// Panics if `rhs == 0`.
50    #[inline]
51    #[must_use]
52    #[track_caller]
53    pub fn div_rem(mut self, mut rhs: Self) -> (Self, Self) {
54        assert!(rhs != Self::ZERO, "Division by zero");
55        algorithms::div(&mut self.limbs, &mut rhs.limbs);
56        (self, rhs)
57    }
58
59    /// Computes `self / rhs` rounding down.
60    ///
61    /// # Panics
62    ///
63    /// Panics if `rhs == 0`.
64    #[inline]
65    #[must_use]
66    #[track_caller]
67    pub fn wrapping_div(self, rhs: Self) -> Self {
68        self.div_rem(rhs).0
69    }
70
71    /// Computes `self % rhs`.
72    ///
73    /// # Panics
74    ///
75    /// Panics if `rhs == 0`.
76    #[inline]
77    #[must_use]
78    #[track_caller]
79    pub fn wrapping_rem(self, rhs: Self) -> Self {
80        self.div_rem(rhs).1
81    }
82}
83
84impl_bin_op!(Div, div, DivAssign, div_assign, wrapping_div);
85impl_bin_op!(Rem, rem, RemAssign, rem_assign, wrapping_rem);
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::{const_for, nlimbs};
91    use proptest::{prop_assume, proptest};
92
93    #[test]
94    fn test_div_ceil() {
95        const_for!(BITS in NON_ZERO {
96            const LIMBS: usize = nlimbs(BITS);
97            type U = Uint<BITS, LIMBS>;
98            proptest!(|(n: U, mut d: U)| {
99                d >>= BITS / 2; // make d small
100                prop_assume!(d != U::ZERO);
101                let qf = n / d;
102                let qc = n.div_ceil(d);
103                assert!(qf <= qc);
104                assert!(qf == qc || qf == qc - U::from(1));
105                if qf == qc {
106                    assert!(n % d == U::ZERO);
107                }
108            });
109        });
110    }
111
112    #[test]
113    fn test_divrem() {
114        const_for!(BITS in NON_ZERO {
115            const LIMBS: usize = nlimbs(BITS);
116            type U = Uint<BITS, LIMBS>;
117            proptest!(|(n: U, mut d: u64)| {
118                if BITS < 64 {
119                    d &= U::MASK;
120                }
121                if d == 0 {
122                    d = 1;
123                }
124                let d = U::from(d);
125                let (q, r) = n.div_rem(d);
126                assert!(r < d);
127                assert_eq!(q * d + r, n);
128            });
129            proptest!(|(n: U, mut d: U)| {
130                d >>= BITS / 2; // make d small
131                prop_assume!(d != U::ZERO);
132                let (q, r) = n.div_rem(d);
133                assert!(r < d);
134                assert_eq!(q * d + r, n);
135            });
136            proptest!(|(n: U, d: U)| {
137                prop_assume!(d != U::ZERO);
138                let (q, r) = n.div_rem(d);
139                assert!(r < d);
140                assert_eq!(q * d + r, n);
141            });
142        });
143    }
144}