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::{algorithms::DoubleWord, utils::unlikely};
12
13pub use self::{div_2x1_mg10 as div_2x1, div_3x2_mg10 as div_3x2};
16
17#[inline]
23pub fn div_nx1_normalized(u: &mut [u64], d: u64) -> u64 {
24 debug_assert!(d >= (1 << 63));
26
27 let v = reciprocal(d);
28 let mut r: u64 = 0;
29 for u in u.iter_mut().rev() {
30 let n = u128::join(r, *u);
31 let (q, r0) = div_2x1(n, d, v);
32 *u = q;
33 r = r0;
34 }
35 r
36}
37
38#[inline]
51pub fn div_nx1(limbs: &mut [u64], divisor: u64) -> u64 {
52 debug_assert!(divisor != 0);
53 debug_assert!(!limbs.is_empty());
54 debug_assert!(*limbs.last().unwrap() != 0);
55
56 let shift = divisor.leading_zeros();
58 if shift == 0 {
59 return div_nx1_normalized(limbs, divisor);
60 }
61 let divisor = divisor << shift;
62 let reciprocal = reciprocal(divisor);
63
64 let last = unsafe { limbs.get_unchecked(limbs.len() - 1) };
65 let mut remainder = last >> (64 - shift);
66 for i in (1..limbs.len()).rev() {
67 let upper = unsafe { limbs.get_unchecked(i) };
69 let lower = unsafe { limbs.get_unchecked(i - 1) };
70 let u = (upper << shift) | (lower >> (64 - shift));
71
72 let n = u128::join(remainder, u);
74 let (q, r) = div_2x1(n, divisor, reciprocal);
75
76 *unsafe { limbs.get_unchecked_mut(i) } = q;
78 remainder = r;
79 }
80 let first = unsafe { limbs.get_unchecked_mut(0) };
82 let n = u128::join(remainder, *first << shift);
83 let (q, remainder) = div_2x1(n, divisor, reciprocal);
84 *first = q;
85
86 remainder >> shift
88}
89
90#[inline]
95pub fn div_nx2_normalized(u: &mut [u64], d: u128) -> u128 {
96 debug_assert!(d >= (1 << 127));
98
99 let v = reciprocal_2(d);
100 let mut remainder: u128 = 0;
101 for u in u.iter_mut().rev() {
102 let (q, r) = div_3x2(remainder, *u, d, v);
103 *u = q;
104 remainder = r;
105 }
106 remainder
107}
108
109#[inline]
119pub fn div_nx2(limbs: &mut [u64], divisor: u128) -> u128 {
120 debug_assert!(divisor >= 1 << 64);
121 debug_assert!(!limbs.is_empty());
122 debug_assert!(*limbs.last().unwrap() != 0);
123
124 let shift = divisor.high().leading_zeros();
126 if shift == 0 {
127 return div_nx2_normalized(limbs, divisor);
128 }
129 let divisor = divisor << shift;
130 let reciprocal = reciprocal_2(divisor);
131
132 let last = unsafe { limbs.get_unchecked(limbs.len() - 1) };
133 let mut remainder: u128 = u128::from(last >> (64 - shift));
134 for i in (1..limbs.len()).rev() {
135 let upper = unsafe { limbs.get_unchecked(i) };
137 let lower = unsafe { limbs.get_unchecked(i - 1) };
138 let u = (upper << shift) | (lower >> (64 - shift));
139
140 let (q, r) = div_3x2(remainder, u, divisor, reciprocal);
142
143 *unsafe { limbs.get_unchecked_mut(i) } = q;
145 remainder = r;
146 }
147 let first = unsafe { limbs.get_unchecked_mut(0) };
149 let (q, remainder) = div_3x2(remainder, *first << shift, divisor, reciprocal);
150 *first = q;
151
152 remainder >> shift
154}
155
156#[inline]
157#[must_use]
158pub fn div_2x1_ref(u: u128, d: u64) -> (u64, u64) {
159 debug_assert!(d >= (1 << 63));
160 debug_assert!((u >> 64) < u128::from(d));
161 let d = u128::from(d);
162 let q = (u / d) as u64;
163 let r = (u % d) as u64;
164 (q, r)
165}
166
167#[inline]
178#[must_use]
179pub fn div_2x1_mg10(u: u128, d: u64, v: u64) -> (u64, u64) {
180 debug_assert!(d >= (1 << 63));
181 debug_assert!((u >> 64) < u128::from(d));
182 debug_assert_eq!(v, reciprocal(d));
183
184 let q = u + (u >> 64) * u128::from(v);
185 let q0 = q as u64;
186 let q1 = ((q >> 64) as u64).wrapping_add(1);
187 let r = (u as u64).wrapping_sub(q1.wrapping_mul(d));
188 let (q1, r) = if r > q0 {
189 (q1.wrapping_sub(1), r.wrapping_add(d))
190 } else {
191 (q1, r)
192 };
193 let (q1, r) = if unlikely(r >= d) {
194 (q1.wrapping_add(1), r.wrapping_sub(d))
195 } else {
196 (q1, r)
197 };
198 (q1, r)
199}
200
201#[inline]
203#[must_use]
204pub fn div_3x2_ref(n21: u128, n0: u64, d: u128) -> u64 {
205 debug_assert!(d >= (1 << 127));
206 debug_assert!(n21 < d);
207
208 let n2 = (n21 >> 64) as u64;
209 let n1 = n21 as u64;
210 let d1 = (d >> 64) as u64;
211 let d0 = d as u64;
212
213 if unlikely(n2 == d1) {
214 debug_assert!(n1 < d0);
216 let neg_remainder = u128::from(d0).wrapping_sub((u128::from(n1) << 64) | u128::from(n0));
222 if neg_remainder > d {
223 0xffff_ffff_ffff_fffe_u64
224 } else {
225 0xffff_ffff_ffff_ffff_u64
226 }
227 } else {
228 let (mut q, mut r) = div_2x1_ref(n21, d1);
230
231 let t1 = u128::from(q) * u128::from(d0);
232 let t2 = (u128::from(n0) << 64) | u128::from(r);
233 if t1 > t2 {
234 q -= 1;
235 r = r.wrapping_add(d1);
236 let overflow = r < d1;
237 if !overflow {
238 let t1 = u128::from(q) * u128::from(d0);
239 let t2 = (u128::from(n0) << 64) | u128::from(r);
240 if t1 > t2 {
241 q -= 1;
242 }
244 }
245 }
246 q
247 }
248}
249
250#[inline]
256#[must_use]
257pub fn div_3x2_mg10(u21: u128, u0: u64, d: u128, v: u64) -> (u64, u128) {
258 debug_assert!(d >= (1 << 127));
259 debug_assert!(u21 < d);
260 debug_assert_eq!(v, reciprocal_2(d));
261
262 let q = u128::mul(u21.high(), v) + u21;
263 let r1 = u21.low().wrapping_sub(q.high().wrapping_mul(d.high()));
264 let t = u128::mul(d.low(), q.high());
265 let mut r = u128::join(r1, u0).wrapping_sub(t).wrapping_sub(d);
266 let mut q1 = q.high().wrapping_add(1);
267 if r.high() >= q.low() {
268 q1 = q1.wrapping_sub(1);
269 r = r.wrapping_add(d);
270 }
271 if unlikely(r >= d) {
272 q1 = q1.wrapping_add(1);
273 r = r.wrapping_sub(d);
274 }
275 (q1, r)
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281 use crate::algorithms::addmul;
282 use proptest::{
283 collection,
284 num::{u128, u64},
285 prop_assume, proptest,
286 strategy::Strategy,
287 };
288
289 #[test]
290 fn test_div_2x1_mg10() {
291 proptest!(|(q: u64, r: u64, mut d: u64)| {
292 let d = d | (1 << 63);
293 let r = r % d;
294 let n = u128::from(q) * u128::from(d) + u128::from(r);
295 let v = reciprocal(d);
296 assert_eq!(div_2x1_mg10(n, d, v), (q,r));
297 });
298 }
299
300 #[ignore] #[test]
302 fn test_div_3x2_ref() {
303 proptest!(|(q: u64, r: u128, mut d: u128)| {
304 let d = d | (1 << 127);
305 let r = r % d;
306 let (n21, n0) = {
307 let d1 = (d >> 64) as u64;
308 let d0 = d as u64;
309 let r1 = (r >> 64) as u64;
310 let r0 = r as u64;
311 let n10 = u128::from(q) * u128::from(d0) + u128::from(r0);
313 let n0 = n10 as u64;
314 let n21 = (n10 >> 64) + u128::from(q) * u128::from(d1) + u128::from(r1);
315 (n21, n0)
316 };
317 assert_eq!(div_3x2_ref(n21, n0, d), q);
318 });
319 }
320
321 #[test]
322 fn test_div_3x2_mg10() {
323 proptest!(|(q: u64, r: u128, mut d: u128)| {
324 let d = d | (1 << 127);
325 let r = r % d;
326 let (n21, n0) = {
327 let d1 = (d >> 64) as u64;
328 let d0 = d as u64;
329 let r1 = (r >> 64) as u64;
330 let r0 = r as u64;
331 let n10 = u128::from(q) * u128::from(d0) + u128::from(r0);
333 let n0 = n10 as u64;
334 let n21 = (n10 >> 64) + u128::from(q) * u128::from(d1) + u128::from(r1);
335 (n21, n0)
336 };
337 let v = reciprocal_2(d);
338 assert_eq!(div_3x2_mg10(n21, n0, d, v), (q, r));
339 });
340 }
341
342 #[test]
343 fn test_div_nx1_normalized() {
344 let any_vec = collection::vec(u64::ANY, ..10);
345 proptest!(|(quotient in any_vec, mut divisor: u64, mut remainder: u64)| {
346 divisor |= 1 << 63;
348 remainder %= divisor;
349 let mut numerator = vec![0; quotient.len() + 1];
350 numerator[0] = remainder;
351 addmul(&mut numerator, "ient, &[divisor]);
352
353 let r = div_nx1_normalized(&mut numerator, divisor);
355 assert_eq!(&numerator[..quotient.len()], "ient);
356 assert_eq!(r, remainder);
357 });
358 }
359
360 #[test]
361 fn test_div_nx1() {
362 let any_vec = collection::vec(u64::ANY, 1..10);
363 let divrem = (1..u64::MAX, u64::ANY).prop_map(|(d, r)| (d, r % d));
364 proptest!(|(quotient in any_vec,(divisor, remainder) in divrem)| {
365 let mut numerator = vec![0; quotient.len() + 1];
367 numerator[0] = remainder;
368 addmul( &mut numerator, "ient, &[divisor]);
369
370 while numerator.last() == Some(&0) {
372 numerator.pop();
373 }
374 prop_assume!(!numerator.is_empty());
375
376 let r = div_nx1(&mut numerator, divisor);
378 assert_eq!(&numerator[..quotient.len()], "ient);
379 assert_eq!(r, remainder);
380 });
381 }
382
383 #[test]
384 fn test_div_nx2_normalized() {
385 let any_vec = collection::vec(u64::ANY, ..10);
386 let divrem = (1_u128 << 127.., u128::ANY).prop_map(|(d, r)| (d, r % d));
387 proptest!(|(quotient in any_vec, (divisor, remainder) in divrem)| {
388 let mut numerator = vec![0; quotient.len() + 2];
390 numerator[0] = remainder.low();
391 numerator[1] = remainder.high();
392 addmul(&mut numerator, "ient, &[divisor.low(), divisor.high()]);
393
394 let r = div_nx2_normalized(&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() {
403 let any_vec = collection::vec(u64::ANY, 2..10);
404 let divrem = (1..u128::MAX, 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 while numerator.last() == Some(&0) {
414 numerator.pop();
415 }
416 prop_assume!(!numerator.is_empty());
417
418 let r = div_nx2(&mut numerator, divisor);
420 assert_eq!(&numerator[..quotient.len()], "ient);
421 assert_eq!(r, remainder);
422 });
423 }
424}