1use super::{reciprocal::reciprocal_2, small::div_3x2, DoubleWord};
4use crate::{
5 algorithms::{add::carrying_add_n, mul::submul_nx1},
6 utils::{likely, unlikely, UncheckedSlice},
7};
8
9#[doc = crate::algorithms::unstable_warning!()]
11#[inline(always)]
21#[allow(clippy::many_single_char_names)]
22pub fn div_nxm_normalized(numerator: &mut [u64], divisor: &[u64]) {
23 debug_assert!(divisor.len() >= 2);
24 debug_assert!(numerator.len() >= divisor.len());
25 debug_assert!(*divisor.last().unwrap() >= (1 << 63));
26
27 let numerator = UncheckedSlice::wrap_mut(numerator);
28 let divisor = UncheckedSlice::wrap(divisor);
29
30 let n = divisor.len();
31 let m = numerator.len() - n - 1;
32
33 let d = u128::join(divisor[n - 1], divisor[n - 2]);
35 let v = reciprocal_2(d);
36
37 for j in (0..=m).rev() {
39 let n21 = u128::join(numerator[j + n], numerator[j + n - 1]);
41 let n0 = numerator[j + n - 2];
42 debug_assert!(n21 <= d);
43
44 if unlikely(n21 == d) {
46 let q = u64::MAX;
47 let _carry = submul_nx1(&mut numerator[j..j + n], divisor, q);
48 numerator[j + n] = q;
49 continue;
50 }
51
52 let (mut q, r) = div_3x2(n21, n0, d, v);
57
58 let borrow = submul_nx1(&mut numerator[j..j + n - 2], &divisor[..n - 2], q);
62 let (r, borrow) = r.overflowing_sub(u128::from(borrow));
63 numerator[j + n - 2] = r.low();
64 numerator[j + n - 1] = r.high();
65
66 if unlikely(borrow) {
69 q = q.wrapping_sub(1);
70 let carry = carrying_add_n(&mut numerator[j..j + n], &divisor[..n], false);
71 debug_assert!(carry);
73 }
74
75 numerator[j + n] = q;
77 }
78}
79
80#[doc = crate::algorithms::unstable_warning!()]
82#[inline(always)]
93#[allow(clippy::many_single_char_names)]
94pub fn div_nxm(numerator: &mut [u64], divisor: &mut [u64]) {
95 debug_assert!(divisor.len() >= 3);
96 assume!(numerator.len() >= divisor.len()); debug_assert!(*divisor.last().unwrap() >= 1);
98
99 let numerator = UncheckedSlice::wrap_mut(numerator);
100 let divisor = UncheckedSlice::wrap_mut(divisor);
101
102 let n = divisor.len();
103 let m = numerator.len() - n;
104
105 let (d, shift) = {
108 let d = u128::join(divisor[n - 1], divisor[n - 2]);
109 let shift = d.high().leading_zeros();
110 (
111 if shift == 0 {
112 d
113 } else {
114 (d << shift) | u128::from(divisor[n - 3] >> (64 - shift))
115 },
116 shift,
117 )
118 };
119 debug_assert!(d >= 1 << 127);
120 let v = reciprocal_2(d);
121
122 let mut q_high = 0;
124 #[allow(clippy::range_plus_one)] for j in (0..m + 1).rev() {
126 let (n21, n0) = {
128 let n2 = numerator.get(j + n).copied().unwrap_or_default();
129 let n21 = u128::join(n2, numerator[j + n - 1]);
130 let n0 = numerator[j + n - 2];
131 if shift == 0 {
132 (n21, n0)
133 } else {
134 (
135 (n21 << shift) | u128::from(n0 >> (64 - shift)),
136 (n0 << shift) | (numerator[j + n - 3] >> (64 - shift)),
137 )
138 }
139 };
140 debug_assert!(n21 <= d);
141
142 let q = if likely(n21 < d) {
144 let (mut q, r) = div_3x2(n21, n0, d, v);
149
150 if q != 0 {
151 let borrow = if shift == 0 {
155 let borrow = submul_nx1(&mut numerator[j..j + n - 2], &divisor[..n - 2], q);
156 let (r, borrow) = r.overflowing_sub(u128::from(borrow));
157 numerator[j + n - 2] = r.low();
158 numerator[j + n - 1] = r.high();
159 borrow
160 } else {
161 let borrow = submul_nx1(&mut numerator[j..j + n], divisor, q);
165 let n2 = numerator.get(j + n).copied().unwrap_or_default();
166 borrow != n2
167 };
168
169 if unlikely(borrow) {
172 q = q.wrapping_sub(1);
173 let carry = carrying_add_n(&mut numerator[j..j + n], &divisor[..n], false);
174 debug_assert!(carry);
176 }
177 }
178 q
179 } else {
180 let q = u64::MAX;
182 let _carry = submul_nx1(&mut numerator[j..j + n], divisor, q);
183 q
184 };
185
186 if j + n < numerator.len() {
188 numerator[j + n] = q;
189 } else {
190 q_high = q;
191 }
192 }
193
194 divisor.copy_from_slice(&numerator[..n]);
196 numerator.copy_within(n.., 0);
197 numerator[m] = q_high;
198 numerator[m + 1..].fill(0);
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use crate::algorithms::{addmul, borrowing_sub_n, cmp};
205 use core::cmp::Ordering;
206 use proptest::{
207 collection, num, proptest,
208 strategy::{Just, Strategy},
209 };
210
211 #[allow(unused_imports)]
212 use alloc::vec::Vec;
213
214 #[test]
216 fn test_divrem_8by4() {
217 let mut numerator = [
218 0x3000000000000000,
219 0xd4e15e75fd4e6516,
220 0x593a70aa5daf127b,
221 0xff0a216ae9c215f1,
222 0xa78c7ad6fea10429,
223 0x18276b093f5d1dac,
224 0xfe2e0bccb9e6d8b3,
225 0x1bebfb3bc05d9347,
226 ];
227 let divisor = [
228 0x800000000000000,
229 0x580c0c40583c55b5,
230 0x6b16b3fb5bd85ed3,
231 0xcc958c207ce3c96f,
232 ];
233 let expected_quotient = [
234 0x9128464e61d6b5b3_u64,
235 0xd9eea4fc30c5ac6c_u64,
236 0x944a2d832d5a6a08_u64,
237 0x22f06722e8d883b1_u64,
238 ];
239 let expected_remainder = [
240 0x9800000000000000,
241 0x70efd2d3f528c8d9,
242 0x6dad759fcd6af14a,
243 0x5fe38801c609f277,
244 ];
245 div_nxm_normalized(&mut numerator, &divisor);
246 let (remainder, quotient) = numerator.split_at(divisor.len());
247 assert_eq!(remainder, expected_remainder);
248 assert_eq!(quotient, expected_quotient);
249 }
250
251 #[test]
253 fn test_div_rollback() {
254 let mut numerator = [
255 0x1656178c14142000,
256 0x821415dfe9e81612,
257 0x1616561616161616,
258 0x96000016820016,
259 ];
260 let divisor = [0x1415dfe9e8161414, 0x1656161616161682, 0x9600001682001616];
261 let expected_quotient = [0xffffffffffffff];
262 let expected_remainder = [0x166bf775fc2a3414, 0x1656161616161680, 0x9600001682001616];
263 div_nxm_normalized(&mut numerator, &divisor);
264 let (remainder, quotient) = numerator.split_at(divisor.len());
265 assert_eq!(remainder, expected_remainder);
266 assert_eq!(quotient, expected_quotient);
267 }
268
269 #[test]
271 fn test_div_rollback_2() {
272 let mut numerator = [
273 0x100100000,
274 0x81000,
275 0x1000000000000000,
276 0x0,
277 0x0,
278 0xfffff00000000000,
279 0xffffffffffffffff,
280 0xdfffffffffffff,
281 ];
282 let divisor = [
283 0xfffffffffff00000,
284 0xffffffffffffffff,
285 0xfffffffffffff3ff,
286 0xffffffffffffffff,
287 0xdfffffffffffffff,
288 ];
289 let expected_quotient = [0xffffedb6db6db6e9, 0xffffffffffffffff, 0xffffffffffffff];
290 let expected_remainder = [
291 0xdb6db6dc6ea00000,
292 0x80ffe,
293 0xf2492492492ec00,
294 0x1000,
295 0x2000000000000000,
296 ];
297 div_nxm_normalized(&mut numerator, &divisor);
298 let (remainder, quotient) = numerator.split_at(divisor.len());
299 assert_eq!(quotient, expected_quotient);
300 assert_eq!(remainder, expected_remainder);
301 }
302
303 #[test]
304 fn test_div_overflow() {
305 let mut numerator = [0xb200000000000002, 0x1, 0x0, 0xfdffffff00000000];
306 let divisor = [0x10002, 0x0, 0xfdffffff00000000];
307 let expected_quotient = [0xffffffffffffffff];
308 let expected_remainder = [0xb200000000010004, 0xfffffffffffeffff, 0xfdfffffeffffffff];
309 div_nxm_normalized(&mut numerator, &divisor);
310 let (remainder, quotient) = numerator.split_at(divisor.len());
311 assert_eq!(quotient, expected_quotient);
312 assert_eq!(remainder, expected_remainder);
313 }
314
315 #[test]
317 fn test_div_nxm_normalized() {
318 let quotient = collection::vec(num::u64::ANY, 1..10);
319 let divisor = collection::vec(num::u64::ANY, 2..10).prop_map(|mut vec| {
320 *vec.last_mut().unwrap() |= 1 << 63;
321 vec
322 });
323 let dr = divisor.prop_flat_map(|divisor| {
324 let d = divisor.clone();
325 let remainder =
326 collection::vec(num::u64::ANY, divisor.len()).prop_map(move |mut vec| {
327 if cmp(&vec, &d) != Ordering::Less {
328 let borrow = borrowing_sub_n(&mut vec, &d, false);
329 assert!(!borrow);
330 }
331 vec
332 });
333 (Just(divisor), remainder)
334 });
335 proptest!(|(quotient in quotient, (divisor, remainder) in dr)| {
336 let mut numerator: Vec<u64> = vec![0; divisor.len() + quotient.len()];
337 numerator[..remainder.len()].copy_from_slice(&remainder);
338 addmul(&mut numerator, quotient.as_slice(), divisor.as_slice());
339
340 div_nxm_normalized(numerator.as_mut_slice(), divisor.as_slice());
341 let (r, q) = numerator.split_at(divisor.len());
342 assert_eq!(r, remainder);
343 assert_eq!(q, quotient);
344 });
345 }
346
347 #[test]
349 fn test_div_nxm_8by4_noshift() {
350 let mut numerator = [
351 0x3000000000000000,
352 0xd4e15e75fd4e6516,
353 0x593a70aa5daf127b,
354 0xff0a216ae9c215f1,
355 0xa78c7ad6fea10429,
356 0x18276b093f5d1dac,
357 0xfe2e0bccb9e6d8b3,
358 0x1bebfb3bc05d9347,
359 ];
360 let mut divisor = [
361 0x800000000000000,
362 0x580c0c40583c55b5,
363 0x6b16b3fb5bd85ed3,
364 0xcc958c207ce3c96f,
365 ];
366 let quotient = [
367 0x9128464e61d6b5b3,
368 0xd9eea4fc30c5ac6c,
369 0x944a2d832d5a6a08,
370 0x22f06722e8d883b1,
371 ];
372 let remainder = [
373 0x9800000000000000,
374 0x70efd2d3f528c8d9,
375 0x6dad759fcd6af14a,
376 0x5fe38801c609f277,
377 ];
378 div_nxm(&mut numerator, &mut divisor);
379 assert_eq!(&numerator[..quotient.len()], quotient);
380 assert_eq!(divisor, remainder);
381 }
382
383 #[test]
385 fn test_div_nxm_8by4_shift() {
386 let mut numerator = [
387 0xc59c28364a491d22,
388 0x1ab240e2a2a91050,
389 0xe497baaf4e4b16cb,
390 0xd21643d231c590d6,
391 0xda918cd26803c7f1,
392 0xb445074f770b5261,
393 0x37aff2aa32059516,
394 0x3cf254c1,
395 ];
396 let mut divisor = [
397 0xc91e935375a97723,
398 0x86a9ded3044ec12b,
399 0xc7d2c4d3b53bff51,
400 0x6ef0530d,
401 ];
402 let quotient = [
403 0x456b1581ef1a759a,
404 0x88702c90bbe2ef3c,
405 0xff8492ee85dec642,
406 0x8ca39da4ca785f36,
407 ];
408 let remainder = [
409 0x82c3522848567314,
410 0xeaba6edb18db568e,
411 0x18f16cfde22dcefe,
412 0x11296685,
413 ];
414 div_nxm(&mut numerator, &mut divisor);
415 assert_eq!(&numerator[..quotient.len()], quotient);
416 assert_eq!(divisor, remainder);
417 }
418
419 #[test]
421 fn test_div_nxm_8by4_q_high() {
422 let mut numerator = [
423 0x39ea76324ed952cc,
424 0x89b7a0d30e2df1be,
425 0x7011596e8b3f301f,
426 0x11930a89eca68640,
427 0x36a34eca4f73d0e4,
428 0x86d53c52b1108c90,
429 0x6093338b7b667e03,
430 ];
431 let mut divisor = [
432 0x439702d44a8f62a4,
433 0x8dfa6ea7fc41f689,
434 0xc79723ff4dd060e0,
435 0x7d13e204,
436 ];
437 let quotient = [
438 0x181cecbb64efa48b,
439 0x1e97056793a15125,
440 0xe8145d63cd312d02,
441 0xc5a9aced,
442 ];
443 let remainder = [
444 0x682e10f8d0b1b3c0,
445 0xbf46c8b0e5ac8a62,
446 0x5abe292d53acf085,
447 0x699fc911,
448 ];
449 div_nxm(&mut numerator, &mut divisor);
450 assert_eq!(&numerator[..quotient.len()], quotient);
451 assert_eq!(divisor, remainder);
452 }
453
454 #[test]
456 fn test_div_nxm_4by4() {
457 let mut numerator = [
458 0x55a8f128f187ecee,
459 0xe059a1f3fe52e559,
460 0x570ab3b2aac5c5d9,
461 0xf7ea0c73b80ddca1,
462 ];
463 let mut divisor = [
464 0x6c8cd670adcae7da,
465 0x458d6428c7fd36d3,
466 0x4a73ad64cc703a1d,
467 0x33bf790f92ed51fe,
468 ];
469 let quotient = [0x4];
470 let remainder = [
471 0xa37597663a5c4d86,
472 0xca241150de5e0a0b,
473 0x2d3bfe1f7904dd64,
474 0x28ec28356c5894a8,
475 ];
476 div_nxm(&mut numerator, &mut divisor);
477 assert_eq!(&numerator[..quotient.len()], quotient);
478 assert_eq!(divisor, remainder);
479 }
480
481 #[test]
482 fn test_div_nxm_4by3() {
483 let mut numerator = [
484 0x8000000000000000,
485 0x8000000000000000,
486 0x8000000000000000,
487 0x8000000000000001,
488 ];
489 let mut divisor = [0x8000000000000000, 0x8000000000000000, 0x8000000000000000];
490 let quotient = [0x1, 0x1];
491 let remainder = [0x0, 0x8000000000000000, 0x7fffffffffffffff];
492 div_nxm(&mut numerator, &mut divisor);
493 assert_eq!(&numerator[..quotient.len()], quotient);
494 assert_eq!(divisor, remainder);
495 }
496
497 #[test]
499 fn test_div_nxm() {
500 let quotient = collection::vec(num::u64::ANY, 1..10);
501 let divisor = collection::vec(num::u64::ANY, 3..10);
502 let dr = divisor.prop_flat_map(|divisor| {
503 let d = divisor.clone();
504 let remainder =
505 collection::vec(num::u64::ANY, divisor.len()).prop_map(move |mut vec| {
506 *vec.last_mut().unwrap() %= d.last().unwrap();
507 vec
508 });
509 (Just(divisor), remainder)
510 });
511 proptest!(|(quotient in quotient, (mut divisor, remainder) in dr)| {
512 let mut numerator: Vec<u64> = vec![0; divisor.len() + quotient.len()];
513 numerator[..remainder.len()].copy_from_slice(&remainder);
514 addmul(&mut numerator, quotient.as_slice(), divisor.as_slice());
515
516 div_nxm(numerator.as_mut_slice(), divisor.as_mut_slice());
517 assert_eq!(&numerator[..quotient.len()], quotient);
518 assert_eq!(divisor, remainder);
519 assert!(numerator[quotient.len()..].iter().all(|&x| x == 0));
520 });
521 }
522}