1use super::HeaplessBigInt;
16use crate::MachineWord;
17use const_num_traits::{CarryingMul, CheckedAdd, CheckedDiv, CheckedRem, DivCeil, Nct, One, Zero};
18
19fn div_rem_impl<T, const CAP: usize>(
20 dividend: &HeaplessBigInt<T, CAP, Nct>,
21 divisor: &HeaplessBigInt<T, CAP, Nct>,
22) -> (HeaplessBigInt<T, CAP, Nct>, HeaplessBigInt<T, CAP, Nct>)
23where
24 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
25{
26 use core::cmp::Ordering;
27 assert!(
28 !<HeaplessBigInt<T, CAP, Nct> as Zero>::is_zero(divisor),
29 "HeaplessBigInt: divide by zero"
30 );
31
32 let work_len = core::cmp::max(dividend.len(), divisor.len());
37
38 match dividend.cmp(divisor) {
39 Ordering::Less => {
40 return (
41 <HeaplessBigInt<T, CAP, Nct> as Zero>::zero().widened(work_len),
42 dividend.widened(work_len),
43 );
44 }
45 Ordering::Equal => {
46 return (
47 <HeaplessBigInt<T, CAP, Nct> as One>::one().widened(work_len),
48 <HeaplessBigInt<T, CAP, Nct> as Zero>::zero().widened(work_len),
49 );
50 }
51 Ordering::Greater => {}
52 }
53
54 let d_bits = dividend.bit_length();
55 let dv_bits = divisor.bit_length();
56 let mut shift = d_bits - dv_bits;
57
58 let mut rem = dividend.widened(work_len);
63 let wide_divisor = divisor.widened(work_len);
64 let one = <HeaplessBigInt<T, CAP, Nct> as One>::one().widened(work_len);
65 let mut quotient = <HeaplessBigInt<T, CAP, Nct> as Zero>::zero().widened(work_len);
66
67 let mut shifted = wide_divisor << shift;
73 let mut bit = one << shift;
74 loop {
75 if rem >= shifted {
76 rem = rem.wrapping_sub(&shifted);
77 quotient = quotient.wrapping_add(&bit);
78 }
79 if shift == 0 {
80 break;
81 }
82 shifted >>= 1usize;
83 bit >>= 1usize;
84 shift -= 1;
85 }
86
87 (quotient, rem)
88}
89
90macro_rules! div_impls {
91 ($lhs:ty, $rhs:ty, $out:ty) => {
92 impl<T, const CAP: usize> core::ops::Div<$rhs> for $lhs
93 where
94 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
95 {
96 type Output = $out;
97 fn div(self, other: $rhs) -> Self::Output {
98 div_rem_impl::<T, CAP>(&self, &other).0
99 }
100 }
101
102 impl<T, const CAP: usize> core::ops::Rem<$rhs> for $lhs
103 where
104 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
105 {
106 type Output = $out;
107 fn rem(self, other: $rhs) -> Self::Output {
108 div_rem_impl::<T, CAP>(&self, &other).1
109 }
110 }
111 };
112}
113
114div_impls!(
115 HeaplessBigInt<T, CAP, Nct>,
116 HeaplessBigInt<T, CAP, Nct>,
117 HeaplessBigInt<T, CAP, Nct>
118);
119div_impls!(
120 HeaplessBigInt<T, CAP, Nct>,
121 &HeaplessBigInt<T, CAP, Nct>,
122 HeaplessBigInt<T, CAP, Nct>
123);
124div_impls!(
125 &HeaplessBigInt<T, CAP, Nct>,
126 HeaplessBigInt<T, CAP, Nct>,
127 HeaplessBigInt<T, CAP, Nct>
128);
129div_impls!(
130 &HeaplessBigInt<T, CAP, Nct>,
131 &HeaplessBigInt<T, CAP, Nct>,
132 HeaplessBigInt<T, CAP, Nct>
133);
134
135impl<T, const CAP: usize> HeaplessBigInt<T, CAP, Nct>
142where
143 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
144{
145 pub fn div_rem(&self, other: &Self) -> (Self, Self) {
148 div_rem_impl(self, other)
149 }
150
151 pub fn checked_div(&self, other: &Self) -> Option<Self> {
153 if <Self as Zero>::is_zero(other) {
154 None
155 } else {
156 Some(div_rem_impl(self, other).0)
157 }
158 }
159
160 pub fn checked_rem(&self, other: &Self) -> Option<Self> {
162 if <Self as Zero>::is_zero(other) {
163 None
164 } else {
165 Some(div_rem_impl(self, other).1)
166 }
167 }
168
169 pub fn checked_div_ceil(&self, other: &Self) -> Option<Self> {
172 if <Self as Zero>::is_zero(other) {
173 return None;
174 }
175 let (q, r) = div_rem_impl(self, other);
176 if <Self as Zero>::is_zero(&r) {
177 Some(q)
178 } else {
179 CheckedAdd::checked_add(q, <Self as One>::one())
180 }
181 }
182}
183
184impl<T, const CAP: usize> CheckedDiv for HeaplessBigInt<T, CAP, Nct>
188where
189 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
190{
191 type Output = Self;
192 fn checked_div(self, v: Self) -> Option<Self> {
193 Self::checked_div(&self, &v)
194 }
195}
196
197impl<T, const CAP: usize> CheckedRem for HeaplessBigInt<T, CAP, Nct>
198where
199 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
200{
201 type Output = Self;
202 fn checked_rem(self, v: Self) -> Option<Self> {
203 Self::checked_rem(&self, &v)
204 }
205}
206
207impl<T, const CAP: usize> DivCeil for HeaplessBigInt<T, CAP, Nct>
208where
209 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
210{
211 type Output = Self;
212 fn div_ceil(self, rhs: Self) -> Self {
213 match Self::checked_div_ceil(&self, &rhs) {
214 Some(v) => v,
215 None => panic!("HeaplessBigInt::div_ceil: division by zero or overflow"),
216 }
217 }
218}
219
220impl<T, const CAP: usize> CheckedDiv for &HeaplessBigInt<T, CAP, Nct>
225where
226 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
227{
228 type Output = HeaplessBigInt<T, CAP, Nct>;
229 fn checked_div(self, v: Self) -> Option<Self::Output> {
230 <HeaplessBigInt<T, CAP, Nct> as CheckedDiv>::checked_div(*self, *v)
231 }
232}
233
234impl<T, const CAP: usize> CheckedRem for &HeaplessBigInt<T, CAP, Nct>
235where
236 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
237{
238 type Output = HeaplessBigInt<T, CAP, Nct>;
239 fn checked_rem(self, v: Self) -> Option<Self::Output> {
240 <HeaplessBigInt<T, CAP, Nct> as CheckedRem>::checked_rem(*self, *v)
241 }
242}
243
244impl<T, const CAP: usize> DivCeil for &HeaplessBigInt<T, CAP, Nct>
245where
246 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
247{
248 type Output = HeaplessBigInt<T, CAP, Nct>;
249 fn div_ceil(self, rhs: Self) -> Self::Output {
250 <HeaplessBigInt<T, CAP, Nct> as DivCeil>::div_ceil(*self, *rhs)
251 }
252}
253
254#[cfg(feature = "num-traits")]
255impl<T, const CAP: usize> num_traits::CheckedDiv for HeaplessBigInt<T, CAP, Nct>
256where
257 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
258{
259 fn checked_div(&self, v: &Self) -> Option<Self> {
260 Self::checked_div(self, v)
261 }
262}
263
264#[cfg(feature = "num-traits")]
265impl<T, const CAP: usize> num_traits::CheckedRem for HeaplessBigInt<T, CAP, Nct>
266where
267 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
268{
269 fn checked_rem(&self, v: &Self) -> Option<Self> {
270 Self::checked_rem(self, v)
271 }
272}
273
274impl<T, const CAP: usize> core::ops::DivAssign for HeaplessBigInt<T, CAP, Nct>
280where
281 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
282{
283 fn div_assign(&mut self, other: Self) {
284 *self = div_rem_impl::<T, CAP>(self, &other).0;
285 }
286}
287
288impl<T, const CAP: usize> core::ops::DivAssign<&HeaplessBigInt<T, CAP, Nct>>
289 for HeaplessBigInt<T, CAP, Nct>
290where
291 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
292{
293 fn div_assign(&mut self, other: &Self) {
294 *self = div_rem_impl::<T, CAP>(self, other).0;
295 }
296}
297
298impl<T, const CAP: usize> core::ops::RemAssign for HeaplessBigInt<T, CAP, Nct>
299where
300 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
301{
302 fn rem_assign(&mut self, other: Self) {
303 *self = div_rem_impl::<T, CAP>(self, &other).1;
304 }
305}
306
307impl<T, const CAP: usize> core::ops::RemAssign<&HeaplessBigInt<T, CAP, Nct>>
308 for HeaplessBigInt<T, CAP, Nct>
309where
310 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
311{
312 fn rem_assign(&mut self, other: &Self) {
313 *self = div_rem_impl::<T, CAP>(self, other).1;
314 }
315}
316
317#[cfg(test)]
318mod div_ceil_tests {
319 use super::HeaplessBigInt;
320 use const_num_traits::{CheckedDiv, CheckedRem, DivCeil};
321
322 type H = HeaplessBigInt<u8, 4>;
323
324 #[test]
325 fn div_ceil_rounds_up() {
326 assert_eq!(DivCeil::div_ceil(H::from(10u8), H::from(5u8)), H::from(2u8));
327 assert_eq!(DivCeil::div_ceil(H::from(11u8), H::from(3u8)), H::from(4u8));
328 assert_eq!(DivCeil::div_ceil(H::from(1u8), H::from(5u8)), H::from(1u8));
329 assert_eq!(DivCeil::div_ceil(H::from(0u8), H::from(5u8)), H::from(0u8));
330 }
331
332 #[test]
333 fn checked_div_ceil_edges() {
334 assert_eq!(H::from(10u8).checked_div_ceil(&H::from(0u8)), None);
336 assert_eq!(
338 H::from(u32::MAX).checked_div_ceil(&H::from(2u8)),
339 Some(H::from(0x8000_0000u32))
340 );
341 }
342
343 #[test]
346 fn by_ref_matches_value() {
347 let a = H::from(100u8);
348 let b = H::from(7u8);
349 assert_eq!(
350 CheckedDiv::checked_div(&a, &b),
351 CheckedDiv::checked_div(a, b)
352 );
353 assert_eq!(
354 CheckedRem::checked_rem(&a, &b),
355 CheckedRem::checked_rem(a, b)
356 );
357 assert_eq!(DivCeil::div_ceil(&a, &b), DivCeil::div_ceil(a, b));
358 }
359}