1#![allow(clippy::many_single_char_names, clippy::similar_names)]
7#![allow(clippy::cast_possible_truncation)]
9
10use super::reciprocal::{reciprocal, reciprocal_2};
11use crate::{
12 algorithms::DoubleWord,
13 utils::{unlikely, UncheckedSlice},
14};
15
16pub use self::{div_2x1_mg10 as div_2x1, div_3x2_mg10 as div_3x2};
19
20#[doc = crate::algorithms::unstable_warning!()]
22#[inline(always)]
23#[track_caller]
24#[must_use]
25pub const fn div_1x1(numerator: u64, divisor: u64) -> (u64, u64) {
26 (numerator / divisor, numerator % divisor)
27}
28
29#[doc = crate::algorithms::unstable_warning!()]
31#[inline(always)]
35pub fn div_nx1_normalized(u: &mut [u64], d: u64) -> u64 {
36 debug_assert!(d >= (1 << 63));
38
39 let v = reciprocal(d);
40 let mut r: u64 = 0;
41 for u in u.iter_mut().rev() {
42 let n = u128::join(r, *u);
43 let (q, r0) = div_2x1(n, d, v);
44 *u = q;
45 r = r0;
46 }
47 r
48}
49
50#[doc = crate::algorithms::unstable_warning!()]
52#[inline(always)]
62pub fn div_nx1(limbs: &mut [u64], divisor: u64) -> u64 {
63 debug_assert!(divisor != 0);
64 debug_assert!(!limbs.is_empty());
65 debug_assert!(*limbs.last().unwrap() != 0);
66
67 let limbs = UncheckedSlice::wrap_mut(limbs);
68
69 let shift = divisor.leading_zeros();
71 if shift == 0 {
72 return div_nx1_normalized(limbs, divisor);
73 }
74 let divisor = divisor << shift;
75 let reciprocal = reciprocal(divisor);
76
77 let last = limbs[limbs.len() - 1];
78 let mut remainder = last >> (64 - shift);
79 for i in (1..limbs.len()).rev() {
80 let upper = limbs[i];
82 let lower = limbs[i - 1];
83 let u = (upper << shift) | (lower >> (64 - shift));
84
85 let n = u128::join(remainder, u);
87 let (q, r) = div_2x1(n, divisor, reciprocal);
88
89 limbs[i] = q;
91 remainder = r;
92 }
93 let first = limbs[0];
95 let n = u128::join(remainder, first << shift);
96 let (q, remainder) = div_2x1(n, divisor, reciprocal);
97 limbs[0] = q;
98
99 remainder >> shift
101}
102
103#[doc = crate::algorithms::unstable_warning!()]
105#[inline(always)]
108pub fn div_nx2_normalized(u: &mut [u64], d: u128) -> u128 {
109 debug_assert!(d >= (1 << 127));
111
112 let v = reciprocal_2(d);
113 let mut remainder: u128 = 0;
114 for u in u.iter_mut().rev() {
115 let (q, r) = div_3x2(remainder, *u, d, v);
116 *u = q;
117 remainder = r;
118 }
119 remainder
120}
121
122#[doc = crate::algorithms::unstable_warning!()]
124#[inline(always)]
131pub fn div_nx2(limbs: &mut [u64], divisor: u128) -> u128 {
132 debug_assert!(divisor >= 1 << 64);
133 debug_assert!(!limbs.is_empty());
134 debug_assert!(*limbs.last().unwrap() != 0);
135
136 let limbs = UncheckedSlice::wrap_mut(limbs);
137
138 let shift = divisor.high().leading_zeros();
140 if shift == 0 {
141 return div_nx2_normalized(limbs, divisor);
142 }
143 let divisor = divisor << shift;
144 let reciprocal = reciprocal_2(divisor);
145
146 let last = limbs[limbs.len() - 1];
147 let mut remainder: u128 = u128::from(last >> (64 - shift));
148 for i in (1..limbs.len()).rev() {
149 let upper = limbs[i];
151 let lower = limbs[i - 1];
152 let u = (upper << shift) | (lower >> (64 - shift));
153
154 let (q, r) = div_3x2(remainder, u, divisor, reciprocal);
156
157 limbs[i] = q;
159 remainder = r;
160 }
161 let first = limbs[0];
163 let (q, remainder) = div_3x2(remainder, first << shift, divisor, reciprocal);
164 limbs[0] = q;
165
166 remainder >> shift
168}
169
170#[doc = crate::algorithms::unstable_warning!()]
172#[inline]
173#[must_use]
174pub fn div_2x1_ref(u: u128, d: u64) -> (u64, u64) {
175 debug_assert!(d >= (1 << 63));
176 debug_assert!((u >> 64) < u128::from(d));
177 let d = u128::from(d);
178 let q = (u / d) as u64;
179 let r = (u % d) as u64;
180 (q, r)
181}
182
183#[doc = crate::algorithms::unstable_warning!()]
185#[inline(always)]
194#[must_use]
195pub fn div_2x1_mg10(u: u128, d: u64, v: u64) -> (u64, u64) {
196 debug_assert!(d >= (1 << 63));
197 debug_assert!((u >> 64) < u128::from(d));
198 debug_assert_eq!(v, reciprocal(d));
199
200 let q = u + (u >> 64) * u128::from(v);
201 let q0 = q as u64;
202 let q1 = ((q >> 64) as u64).wrapping_add(1);
203 let r = (u as u64).wrapping_sub(q1.wrapping_mul(d));
204 let (q1, r) = if r > q0 {
205 (q1.wrapping_sub(1), r.wrapping_add(d))
206 } else {
207 (q1, r)
208 };
209 let (q1, r) = if unlikely(r >= d) {
210 (q1.wrapping_add(1), r.wrapping_sub(d))
211 } else {
212 (q1, r)
213 };
214 (q1, r)
215}
216
217#[doc = crate::algorithms::unstable_warning!()]
219#[inline]
221#[must_use]
222pub fn div_3x2_ref(n21: u128, n0: u64, d: u128) -> u64 {
223 debug_assert!(d >= (1 << 127));
224 debug_assert!(n21 < d);
225
226 let n2 = (n21 >> 64) as u64;
227 let n1 = n21 as u64;
228 let d1 = (d >> 64) as u64;
229 let d0 = d as u64;
230
231 if unlikely(n2 == d1) {
232 debug_assert!(n1 < d0);
234 let neg_remainder = u128::from(d0).wrapping_sub((u128::from(n1) << 64) | u128::from(n0));
240 if neg_remainder > d {
241 0xffff_ffff_ffff_fffe_u64
242 } else {
243 0xffff_ffff_ffff_ffff_u64
244 }
245 } else {
246 let (mut q, mut r) = div_2x1_ref(n21, d1);
248
249 let t1 = u128::from(q) * u128::from(d0);
250 let t2 = (u128::from(n0) << 64) | u128::from(r);
251 if t1 > t2 {
252 q -= 1;
253 r = r.wrapping_add(d1);
254 let overflow = r < d1;
255 if !overflow {
256 let t1 = u128::from(q) * u128::from(d0);
257 let t2 = (u128::from(n0) << 64) | u128::from(r);
258 if t1 > t2 {
259 q -= 1;
260 }
262 }
263 }
264 q
265 }
266}
267
268#[doc = crate::algorithms::unstable_warning!()]
270#[inline(always)]
274#[must_use]
275pub fn div_3x2_mg10(u21: u128, u0: u64, d: u128, v: u64) -> (u64, u128) {
276 debug_assert!(d >= (1 << 127));
277 debug_assert!(u21 < d);
278 debug_assert_eq!(v, reciprocal_2(d));
279
280 let q = u128::mul(u21.high(), v) + u21;
281 let r1 = u21.low().wrapping_sub(q.high().wrapping_mul(d.high()));
282 let t = u128::mul(d.low(), q.high());
283 let mut r = u128::join(r1, u0).wrapping_sub(t).wrapping_sub(d);
284 let mut q1 = q.high().wrapping_add(1);
285 if r.high() >= q.low() {
286 q1 = q1.wrapping_sub(1);
287 r = r.wrapping_add(d);
288 }
289 if unlikely(r >= d) {
290 q1 = q1.wrapping_add(1);
291 r = r.wrapping_sub(d);
292 }
293 (q1, r)
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299 use crate::algorithms::addmul;
300 use proptest::{
301 collection,
302 num::{u128, u64},
303 prop_assume, proptest,
304 strategy::Strategy,
305 };
306
307 #[test]
308 fn test_div_2x1_mg10() {
309 proptest!(|(q: u64, r: u64, mut d: u64)| {
310 let d = d | (1 << 63);
311 let r = r % d;
312 let n = u128::from(q) * u128::from(d) + u128::from(r);
313 let v = reciprocal(d);
314 assert_eq!(div_2x1_mg10(n, d, v), (q,r));
315 });
316 }
317
318 #[ignore = "TODO"]
319 #[test]
320 fn test_div_3x2_ref() {
321 proptest!(|(q: u64, r: u128, mut d: u128)| {
322 let d = d | (1 << 127);
323 let r = r % d;
324 let (n21, n0) = {
325 let d1 = (d >> 64) as u64;
326 let d0 = d as u64;
327 let r1 = (r >> 64) as u64;
328 let r0 = r as u64;
329 let n10 = u128::from(q) * u128::from(d0) + u128::from(r0);
331 let n0 = n10 as u64;
332 let n21 = (n10 >> 64) + u128::from(q) * u128::from(d1) + u128::from(r1);
333 (n21, n0)
334 };
335 assert_eq!(div_3x2_ref(n21, n0, d), q);
336 });
337 }
338
339 #[test]
340 fn test_div_3x2_mg10() {
341 proptest!(|(q: u64, r: u128, mut d: u128)| {
342 let d = d | (1 << 127);
343 let r = r % d;
344 let (n21, n0) = {
345 let d1 = (d >> 64) as u64;
346 let d0 = d as u64;
347 let r1 = (r >> 64) as u64;
348 let r0 = r as u64;
349 let n10 = u128::from(q) * u128::from(d0) + u128::from(r0);
351 let n0 = n10 as u64;
352 let n21 = (n10 >> 64) + u128::from(q) * u128::from(d1) + u128::from(r1);
353 (n21, n0)
354 };
355 let v = reciprocal_2(d);
356 assert_eq!(div_3x2_mg10(n21, n0, d, v), (q, r));
357 });
358 }
359
360 #[test]
361 fn test_div_nx1_normalized() {
362 let any_vec = collection::vec(u64::ANY, ..10);
363 proptest!(|(quotient in any_vec, mut divisor: u64, mut remainder: u64)| {
364 divisor |= 1 << 63;
366 remainder %= divisor;
367 let mut numerator = vec![0; quotient.len() + 1];
368 numerator[0] = remainder;
369 addmul(&mut numerator, "ient, &[divisor]);
370
371 let r = div_nx1_normalized(&mut numerator, divisor);
373 assert_eq!(&numerator[..quotient.len()], "ient);
374 assert_eq!(r, remainder);
375 });
376 }
377
378 #[test]
379 fn test_div_nx1() {
380 let any_vec = collection::vec(u64::ANY, 1..10);
381 let divrem = (1..u64::MAX, u64::ANY).prop_map(|(d, r)| (d, r % d));
382 proptest!(|(quotient in any_vec,(divisor, remainder) in divrem)| {
383 let mut numerator = vec![0; quotient.len() + 1];
385 numerator[0] = remainder;
386 addmul( &mut numerator, "ient, &[divisor]);
387
388 while numerator.last() == Some(&0) {
390 numerator.pop();
391 }
392 prop_assume!(!numerator.is_empty());
393
394 let r = div_nx1(&mut numerator, divisor);
396 assert_eq!(&numerator[..quotient.len()], "ient);
397 assert_eq!(r, remainder);
398 });
399 }
400
401 #[test]
402 fn test_div_nx2_normalized() {
403 let any_vec = collection::vec(u64::ANY, ..10);
404 let divrem = (1_u128 << 127.., u128::ANY).prop_map(|(d, r)| (d, r % d));
405 proptest!(|(quotient in any_vec, (divisor, remainder) in divrem)| {
406 let mut numerator = vec![0; quotient.len() + 2];
408 numerator[0] = remainder.low();
409 numerator[1] = remainder.high();
410 addmul(&mut numerator, "ient, &[divisor.low(), divisor.high()]);
411
412 let r = div_nx2_normalized(&mut numerator, divisor);
414 assert_eq!(&numerator[..quotient.len()], "ient);
415 assert_eq!(r, remainder);
416 });
417 }
418
419 #[test]
420 fn test_div_nx2() {
421 let any_vec = collection::vec(u64::ANY, 2..10);
422 let divrem = (1..u128::MAX, u128::ANY).prop_map(|(d, r)| (d, r % d));
423 proptest!(|(quotient in any_vec,(divisor, remainder) in divrem)| {
424 let mut numerator = vec![0; quotient.len() + 2];
426 numerator[0] = remainder.low();
427 numerator[1] = remainder.high();
428 addmul(&mut numerator, "ient, &[divisor.low(), divisor.high()]);
429
430 while numerator.last() == Some(&0) {
432 numerator.pop();
433 }
434 prop_assume!(!numerator.is_empty());
435
436 let r = div_nx2(&mut numerator, divisor);
438 assert_eq!(&numerator[..quotient.len()], "ient);
439 assert_eq!(r, remainder);
440 });
441 }
442}