1use crate::error::{BigIntError, Result};
6use crate::limbs::{limb_add_carry, limb_mul_wide, limb_sub_borrow};
7use crate::types::BigIntCore;
8
9#[cfg(feature = "alloc")]
10use crate::types::BigInt;
11#[cfg(feature = "alloc")]
12use alloc::vec;
13
14#[cfg(feature = "alloc")]
20pub fn div_rem(a: &BigInt, b: &BigInt) -> Result<(BigInt, BigInt)> {
21 if b.is_zero() {
23 return Err(BigIntError::DivisionByZero);
24 }
25
26 if a.is_zero() {
28 let max_limbs = a.max_limbs().max(b.max_limbs());
29 let zero = BigInt::new(max_limbs);
30 return Ok((zero.clone(), zero));
31 }
32
33 let result_sign = a.sign() != b.sign();
35 let a_abs = if a.sign() {
36 crate::sub::sub(&BigInt::new(a.max_limbs()), a)?
37 } else {
38 a.clone()
39 };
40 let b_abs = if b.sign() {
41 crate::sub::sub(&BigInt::new(b.max_limbs()), b)?
42 } else {
43 b.clone()
44 };
45
46 let (mut quotient, mut remainder) = div_rem_unsigned(&a_abs, &b_abs)?;
48
49 if result_sign {
51 quotient.set_sign(true);
52 }
53 if a.sign() {
54 remainder.set_sign(true);
55 }
56
57 quotient.canonicalize()?;
58 remainder.canonicalize()?;
59
60 Ok((quotient, remainder))
61}
62
63fn div_rem_unsigned(a: &BigInt, b: &BigInt) -> Result<(BigInt, BigInt)> {
65 let a_limbs = a.limbs();
66 let b_limbs = b.limbs();
67
68 if a_limbs.len() < b_limbs.len()
70 || (a_limbs.len() == b_limbs.len()
71 && a_limbs[a_limbs.len() - 1] < b_limbs[a_limbs.len() - 1])
72 {
73 let max_limbs = a.max_limbs().max(b.max_limbs());
74 let zero = BigInt::new(max_limbs);
75 return Ok((zero, a.clone()));
76 }
77
78 if a_limbs.len() == 1 && b_limbs.len() == 1 {
80 let max_limbs = a.max_limbs().max(b.max_limbs());
81 let mut quotient = BigInt::new(max_limbs);
82 let mut remainder = BigInt::new(max_limbs);
83
84 let a_val = a_limbs[0];
85 let b_val = b_limbs[0];
86 let q = a_val / b_val;
87 let r = a_val % b_val;
88
89 quotient.limbs_mut()[0] = q;
90 remainder.limbs_mut()[0] = r;
91
92 quotient.canonicalize()?;
93 remainder.canonicalize()?;
94 return Ok((quotient, remainder));
95 }
96
97 let max_limbs = a.max_limbs().max(b.max_limbs());
99
100 let v_n1 = b_limbs[b_limbs.len() - 1];
103 let d_shift = 63 - (63 - v_n1.leading_zeros());
104 let d = if d_shift < 64 {
105 1u64 << (63 - v_n1.leading_zeros())
106 } else {
107 1
108 };
109
110 let mut u_normalized = vec![0u64; a_limbs.len() + 1]; let mut v_normalized = vec![0u64; b_limbs.len()];
113
114 let mut carry = 0u64;
116 for i in 0..a_limbs.len() {
117 let prod = limb_mul_wide(a_limbs[i], d);
118 let (sum, carry1) = limb_add_carry(prod.lo, carry, 0);
119 u_normalized[i] = sum;
120 carry = prod.hi + carry1;
121 }
122 if carry > 0 {
123 u_normalized[a_limbs.len()] = carry;
124 }
125
126 carry = 0;
128 for i in 0..b_limbs.len() {
129 let prod = limb_mul_wide(b_limbs[i], d);
130 let (sum, carry1) = limb_add_carry(prod.lo, carry, 0);
131 v_normalized[i] = sum;
132 carry = prod.hi + carry1;
133 }
134
135 if v_normalized.len() > 0 && (v_normalized[v_normalized.len() - 1] & (1u64 << 63)) == 0 {
137 let mut carry = 0u64;
139 for i in 0..u_normalized.len() {
140 let new_carry = (u_normalized[i] >> 63) & 1;
141 u_normalized[i] = (u_normalized[i] << 1) | carry;
142 carry = new_carry;
143 }
144 carry = 0;
145 for i in 0..v_normalized.len() {
146 let new_carry = (v_normalized[i] >> 63) & 1;
147 v_normalized[i] = (v_normalized[i] << 1) | carry;
148 carry = new_carry;
149 }
150 }
151
152 let m = u_normalized.len() - v_normalized.len();
153 let n = v_normalized.len();
154
155 let mut quotient = BigInt::new(max_limbs);
157 let q_limbs = quotient.limbs_mut();
158
159 for j in (0..=m).rev() {
161 let u_jn = if j + n < u_normalized.len() {
164 u_normalized[j + n]
165 } else {
166 0
167 };
168 let u_jn1 = if j + n - 1 < u_normalized.len() {
169 u_normalized[j + n - 1]
170 } else {
171 0
172 };
173 let v_nm1 = v_normalized[n - 1];
174
175 let mut q_hat = if v_nm1 == 0 {
177 u64::MAX
178 } else {
179 let num = (u_jn as u128) << 64 | (u_jn1 as u128);
181 (num / (v_nm1 as u128)) as u64
182 };
183
184 if q_hat > 0 {
186 let mut prod_carry = 0u64;
187 for i in 0..n {
188 let prod = limb_mul_wide(q_hat, v_normalized[i]);
189 let (sum, carry1) = limb_add_carry(prod.lo, prod_carry, 0);
190 prod_carry = prod.hi + carry1;
191 if i + j < u_normalized.len() && sum > u_normalized[i + j] {
192 q_hat -= 1;
193 break;
194 } else if i + j < u_normalized.len() && sum < u_normalized[i + j] {
195 break;
196 }
197 }
198 }
199
200 let mut borrow = 0u64;
202 for i in 0..n {
203 let idx = j + i;
204 if idx >= u_normalized.len() {
205 continue;
206 }
207
208 let prod = limb_mul_wide(q_hat, v_normalized[i]);
209 let (diff, borrow_out) = limb_sub_borrow(u_normalized[idx], prod.lo, borrow);
210 u_normalized[idx] = diff;
211 borrow = borrow_out + prod.hi;
212 }
213
214 let mut idx = j + n;
216 while borrow > 0 && idx < u_normalized.len() {
217 let (diff, borrow_out) = limb_sub_borrow(u_normalized[idx], 0, borrow);
218 u_normalized[idx] = diff;
219 borrow = borrow_out;
220 idx += 1;
221 }
222
223 if borrow > 0 {
225 q_hat -= 1;
227 let mut carry = 0u64;
228 for i in 0..n {
229 let idx = j + i;
230 if idx >= u_normalized.len() {
231 continue;
232 }
233 let (sum, carry_out) = limb_add_carry(u_normalized[idx], v_normalized[i], carry);
234 u_normalized[idx] = sum;
235 carry = carry_out;
236 }
237 }
238
239 let q_idx = j;
241 let limb_idx = q_idx / 64;
242 let bit_idx = q_idx % 64;
243 if limb_idx < q_limbs.len() {
244 q_limbs[limb_idx] |= q_hat << bit_idx;
245 }
246 }
247
248 let mut remainder = BigInt::new(max_limbs);
250 let r_limbs = remainder.limbs_mut();
251
252 for i in 0..b_limbs.len() {
254 if i < u_normalized.len() {
255 r_limbs[i] = u_normalized[i];
256 }
257 }
258
259 if d > 1 {
261 let mut rem = 0u64;
262 for i in (0..r_limbs.len()).rev() {
263 let num = (rem as u128) << 64 | (r_limbs[i] as u128);
264 r_limbs[i] = (num / (d as u128)) as u64;
265 rem = (num % (d as u128)) as u64;
266 }
267 }
268
269 quotient.canonicalize()?;
270 remainder.canonicalize()?;
271
272 Ok((quotient, remainder))
273}
274
275#[cfg(feature = "alloc")]
277pub fn div(a: &BigInt, b: &BigInt) -> Result<BigInt> {
278 let (q, _) = div_rem(a, b)?;
279 Ok(q)
280}
281
282#[cfg(feature = "alloc")]
284pub fn rem(a: &BigInt, b: &BigInt) -> Result<BigInt> {
285 let (_, remainder) = div_rem(a, b)?;
286 Ok(remainder)
287}
288
289#[cfg(feature = "alloc")]
291pub fn div_assign(a: &mut BigInt, b: &BigInt) -> Result<()> {
292 let result = div(a, b)?;
293 *a = result;
294 Ok(())
295}
296
297#[cfg(feature = "alloc")]
299pub fn rem_assign(a: &mut BigInt, b: &BigInt) -> Result<()> {
300 let result = rem(a, b)?;
301 *a = result;
302 Ok(())
303}
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308
309 #[test]
310 fn test_div_by_zero() {
311 let a = BigInt::from_u64(10, 10);
312 let b = BigInt::from_u64(0, 10);
313 assert!(div(&a, &b).is_err());
314 }
315
316 #[test]
317 fn test_div_zero_dividend() {
318 let a = BigInt::from_u64(0, 10);
319 let b = BigInt::from_u64(10, 10);
320 let (q, r) = div_rem(&a, &b).unwrap();
321 assert!(q.is_zero());
322 assert!(r.is_zero());
323 }
324
325 #[test]
326 fn test_div_simple() {
327 let a = BigInt::from_u64(100, 10);
328 let b = BigInt::from_u64(10, 10);
329 let (q, r) = div_rem(&a, &b).unwrap();
330 assert_eq!(q.limbs()[0], 10);
331 assert_eq!(r.limbs()[0], 0);
332 }
333
334 #[test]
335 fn test_div_with_remainder() {
336 let a = BigInt::from_u64(123, 10);
337 let b = BigInt::from_u64(10, 10);
338 let (q, r) = div_rem(&a, &b).unwrap();
339 assert_eq!(q.limbs()[0], 12);
340 assert_eq!(r.limbs()[0], 3);
341 }
342}