1use super::HeaplessBigInt;
16use crate::MachineWord;
17use const_num_traits::{CarryingMul, 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 >>= 1;
83 bit >>= 1;
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> core::ops::DivAssign for HeaplessBigInt<T, CAP, Nct>
141where
142 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
143{
144 fn div_assign(&mut self, other: Self) {
145 *self = div_rem_impl::<T, CAP>(self, &other).0;
146 }
147}
148
149impl<T, const CAP: usize> core::ops::DivAssign<&HeaplessBigInt<T, CAP, Nct>>
150 for HeaplessBigInt<T, CAP, Nct>
151where
152 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
153{
154 fn div_assign(&mut self, other: &Self) {
155 *self = div_rem_impl::<T, CAP>(self, other).0;
156 }
157}
158
159impl<T, const CAP: usize> core::ops::RemAssign for HeaplessBigInt<T, CAP, Nct>
160where
161 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
162{
163 fn rem_assign(&mut self, other: Self) {
164 *self = div_rem_impl::<T, CAP>(self, &other).1;
165 }
166}
167
168impl<T, const CAP: usize> core::ops::RemAssign<&HeaplessBigInt<T, CAP, Nct>>
169 for HeaplessBigInt<T, CAP, Nct>
170where
171 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
172{
173 fn rem_assign(&mut self, other: &Self) {
174 *self = div_rem_impl::<T, CAP>(self, other).1;
175 }
176}