1use crate::{algorithms, Uint};
2use core::ops::{Div, DivAssign, Rem, RemAssign};
3
4impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
5 #[inline]
7 #[must_use]
8 #[allow(clippy::missing_const_for_fn)] 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 #[inline]
18 #[must_use]
19 #[allow(clippy::missing_const_for_fn)] 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 #[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 #[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 #[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 #[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; 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; 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}