1use core::{
4 fmt::{Display, Formatter},
5 mem,
6 ops::{Div, DivAssign, Rem, RemAssign},
7};
8use dashu_base::{DivRem, DivRemAssign};
9use num_modular::{PreMulInv2by1, PreMulInv3by2};
10
11use crate::{
12 arch::word::{DoubleWord, Word},
13 buffer::Buffer,
14 div,
15 error::panic_divide_by_0,
16 helper_macros::debug_assert_zero,
17 math::{shl_dword, FastDivideNormalized2},
18 memory::MemoryAllocation,
19 primitive::{double_word, extend_word, shrink_dword},
20 repr::Repr,
21 repr::TypedRepr,
22 shift,
23 ubig::UBig,
24 IBig,
25};
26use alloc::boxed::Box;
27
28#[derive(Debug, PartialEq, Eq)]
29pub(crate) struct ConstSingleDivisor(pub(crate) PreMulInv2by1<Word>);
30
31#[derive(Debug, PartialEq, Eq)]
32pub(crate) struct ConstDoubleDivisor(pub(crate) PreMulInv3by2<Word, DoubleWord>);
33
34#[derive(Debug, PartialEq, Eq)]
35pub(crate) struct ConstLargeDivisor {
36 pub(crate) normalized_divisor: Box<[Word]>,
37 pub(crate) shift: u32,
38 pub(crate) fast_div_top: FastDivideNormalized2,
39}
40
41impl ConstSingleDivisor {
42 #[inline]
44 pub const fn new(n: Word) -> Self {
45 debug_assert!(n != 0);
46 Self(PreMulInv2by1::<Word>::new(n))
47 }
48
49 #[inline]
51 pub const fn divisor(&self) -> Word {
52 self.0.divisor() >> self.0.shift()
53 }
54
55 #[inline]
56 pub const fn normalized_divisor(&self) -> Word {
57 self.0.divisor()
58 }
59 pub const fn shift(&self) -> u32 {
60 self.0.shift()
61 }
62
63 #[inline]
65 pub const fn rem_word(&self, word: Word) -> Word {
66 if self.0.shift() == 0 {
67 self.0.divider().div_rem_1by1(word).1
68 } else {
69 self.0
70 .divider()
71 .div_rem_2by1(extend_word(word) << self.0.shift())
72 .1
73 }
74 }
75
76 #[inline]
78 pub const fn rem_dword(&self, dword: DoubleWord) -> Word {
79 if self.0.shift() == 0 {
80 self.0.divider().div_rem_2by1(dword).1
81 } else {
82 let (n0, n1, n2) = shl_dword(dword, self.0.shift());
83 let (_, r1) = self.0.divider().div_rem_2by1(double_word(n1, n2));
84 self.0.divider().div_rem_2by1(double_word(n0, r1)).1
85 }
86 }
87
88 pub fn rem_large(&self, words: &[Word]) -> Word {
90 let mut rem = div::fast_rem_by_normalized_word(words, *self.0.divider());
91 if self.0.shift() != 0 {
92 rem = self
93 .0
94 .divider()
95 .div_rem_2by1(extend_word(rem) << self.0.shift())
96 .1
97 }
98 rem
99 }
100}
101
102impl ConstDoubleDivisor {
103 #[inline]
105 pub const fn new(n: DoubleWord) -> Self {
106 debug_assert!(n > Word::MAX as DoubleWord);
107 Self(PreMulInv3by2::<Word, DoubleWord>::new(n))
108 }
109
110 #[inline]
112 pub const fn divisor(&self) -> DoubleWord {
113 self.0.divisor() >> self.0.shift()
114 }
115
116 #[inline]
117 pub const fn normalized_divisor(&self) -> DoubleWord {
118 self.0.divisor()
119 }
120 pub const fn shift(&self) -> u32 {
121 self.0.shift()
122 }
123
124 #[inline]
126 pub const fn rem_dword(&self, dword: DoubleWord) -> DoubleWord {
127 if self.0.shift() == 0 {
128 self.0.divider().div_rem_2by2(dword).1
129 } else {
130 let (n0, n1, n2) = shl_dword(dword, self.0.shift());
131 self.0.divider().div_rem_3by2(n0, double_word(n1, n2)).1
132 }
133 }
134
135 pub fn rem_large(&self, words: &[Word]) -> DoubleWord {
137 let mut rem = div::fast_rem_by_normalized_dword(words, *self.0.divider());
138 if self.0.shift() != 0 {
139 let (r0, r1, r2) = shl_dword(rem, self.0.shift());
140 rem = self.0.divider().div_rem_3by2(r0, double_word(r1, r2)).1
141 }
142 rem
143 }
144}
145
146impl ConstLargeDivisor {
147 pub fn new(mut n: Buffer) -> Self {
149 let (shift, fast_div_top) = crate::div::normalize(&mut n);
150 Self {
151 normalized_divisor: n.into_boxed_slice(),
152 shift,
153 fast_div_top,
154 }
155 }
156
157 pub fn divisor(&self) -> Buffer {
159 let mut buffer = Buffer::from(self.normalized_divisor.as_ref());
160 debug_assert_zero!(shift::shr_in_place(&mut buffer, self.shift));
161 buffer
162 }
163
164 #[inline]
166 pub fn rem_large(&self, mut words: Buffer) -> Buffer {
167 let carry = shift::shl_in_place(&mut words, self.shift);
169 words.push_resizing(carry);
170
171 let modulus = &self.normalized_divisor;
173 if words.len() >= modulus.len() {
174 let mut allocation =
175 MemoryAllocation::new(div::memory_requirement_exact(words.len(), modulus.len()));
176 let _overflow = div::div_rem_in_place(
177 &mut words,
178 modulus,
179 self.fast_div_top,
180 &mut allocation.memory(),
181 );
182 words.truncate(modulus.len());
183 }
184 words
185 }
186
187 #[inline]
189 pub fn rem_repr(&self, x: TypedRepr) -> Buffer {
190 match x {
191 TypedRepr::Small(dword) => {
192 let (lo, mid, hi) = shl_dword(dword, self.shift);
193 let mut buffer = Buffer::allocate_exact(self.normalized_divisor.len());
194 buffer.push(lo);
195 buffer.push(mid);
196 buffer.push(hi);
197
198 buffer
201 }
202 TypedRepr::Large(words) => self.rem_large(words),
203 }
204 }
205}
206
207#[derive(Debug, PartialEq, Eq)]
208pub(crate) enum ConstDivisorRepr {
209 Single(ConstSingleDivisor),
210 Double(ConstDoubleDivisor),
211 Large(ConstLargeDivisor),
212}
213
214#[derive(Debug, PartialEq, Eq)]
216pub struct ConstDivisor(pub(crate) ConstDivisorRepr);
217
218impl ConstDivisor {
219 pub fn new(n: UBig) -> ConstDivisor {
225 Self(match n.into_repr() {
226 TypedRepr::Small(0) => panic_divide_by_0(),
227 TypedRepr::Small(dword) => {
228 if let Some(word) = shrink_dword(dword) {
229 ConstDivisorRepr::Single(ConstSingleDivisor::new(word))
230 } else {
231 ConstDivisorRepr::Double(ConstDoubleDivisor::new(dword))
232 }
233 }
234 TypedRepr::Large(words) => ConstDivisorRepr::Large(ConstLargeDivisor::new(words)),
235 })
236 }
237
238 #[inline]
244 pub const fn from_word(word: Word) -> Self {
245 if word == 0 {
246 panic_divide_by_0()
247 }
248 Self(ConstDivisorRepr::Single(ConstSingleDivisor::new(word)))
249 }
250
251 #[inline]
257 pub const fn from_dword(dword: DoubleWord) -> Self {
258 if dword == 0 {
259 panic_divide_by_0()
260 }
261
262 Self(if let Some(word) = shrink_dword(dword) {
263 ConstDivisorRepr::Single(ConstSingleDivisor::new(word))
264 } else {
265 ConstDivisorRepr::Double(ConstDoubleDivisor::new(dword))
266 })
267 }
268
269 #[inline]
271 pub fn value(&self) -> UBig {
272 UBig(match &self.0 {
273 ConstDivisorRepr::Single(d) => Repr::from_word(d.divisor()),
274 ConstDivisorRepr::Double(d) => Repr::from_dword(d.divisor()),
275 ConstDivisorRepr::Large(d) => Repr::from_buffer(d.divisor()),
276 })
277 }
278}
279
280impl Display for ConstDivisor {
281 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
282 Display::fmt(&self.value(), f)
283 }
284}
285
286impl Div<&ConstDivisor> for UBig {
287 type Output = UBig;
288
289 #[inline]
290 fn div(self, rhs: &ConstDivisor) -> UBig {
291 UBig(self.into_repr() / &rhs.0)
292 }
293}
294impl Div<&ConstDivisor> for &UBig {
295 type Output = UBig;
296
297 #[inline]
298 fn div(self, rhs: &ConstDivisor) -> UBig {
299 UBig(self.clone().into_repr() / &rhs.0)
300 }
301}
302impl DivAssign<&ConstDivisor> for UBig {
303 #[inline]
304 fn div_assign(&mut self, rhs: &ConstDivisor) {
305 *self = mem::take(self) / rhs;
306 }
307}
308
309impl Rem<&ConstDivisor> for UBig {
310 type Output = UBig;
311
312 #[inline]
313 fn rem(self, rhs: &ConstDivisor) -> UBig {
314 UBig(self.into_repr() % &rhs.0)
315 }
316}
317impl Rem<&ConstDivisor> for &UBig {
318 type Output = UBig;
319
320 #[inline]
321 fn rem(self, rhs: &ConstDivisor) -> UBig {
322 UBig(self.repr() % &rhs.0)
323 }
324}
325impl RemAssign<&ConstDivisor> for UBig {
326 #[inline]
327 fn rem_assign(&mut self, rhs: &ConstDivisor) {
328 *self = mem::take(self) % rhs;
329 }
330}
331
332impl DivRem<&ConstDivisor> for UBig {
333 type OutputDiv = UBig;
334 type OutputRem = UBig;
335
336 #[inline]
337 fn div_rem(self, rhs: &ConstDivisor) -> (UBig, UBig) {
338 let (q, r) = self.into_repr().div_rem(&rhs.0);
339 (UBig(q), UBig(r))
340 }
341}
342impl DivRem<&ConstDivisor> for &UBig {
343 type OutputDiv = UBig;
344 type OutputRem = UBig;
345
346 #[inline]
347 fn div_rem(self, rhs: &ConstDivisor) -> (UBig, UBig) {
348 let (q, r) = self.clone().into_repr().div_rem(&rhs.0);
349 (UBig(q), UBig(r))
350 }
351}
352impl DivRemAssign<&ConstDivisor> for UBig {
353 type OutputRem = UBig;
354 #[inline]
355 fn div_rem_assign(&mut self, rhs: &ConstDivisor) -> UBig {
356 let (q, r) = mem::take(self).div_rem(rhs);
357 *self = q;
358 r
359 }
360}
361
362impl Div<&ConstDivisor> for IBig {
363 type Output = IBig;
364
365 #[inline]
366 fn div(self, rhs: &ConstDivisor) -> IBig {
367 let (sign, repr) = self.into_sign_repr();
368 IBig((repr / &rhs.0).with_sign(sign))
369 }
370}
371impl Div<&ConstDivisor> for &IBig {
372 type Output = IBig;
373
374 #[inline]
375 fn div(self, rhs: &ConstDivisor) -> IBig {
376 let (sign, repr) = self.clone().into_sign_repr();
377 IBig((repr / &rhs.0).with_sign(sign))
378 }
379}
380impl DivAssign<&ConstDivisor> for IBig {
381 #[inline]
382 fn div_assign(&mut self, rhs: &ConstDivisor) {
383 *self = mem::take(self) / rhs;
384 }
385}
386
387impl Rem<&ConstDivisor> for IBig {
388 type Output = IBig;
389
390 #[inline]
391 fn rem(self, rhs: &ConstDivisor) -> IBig {
392 let (sign, repr) = self.into_sign_repr();
393 IBig((repr % &rhs.0).with_sign(sign))
394 }
395}
396impl Rem<&ConstDivisor> for &IBig {
397 type Output = IBig;
398
399 #[inline]
400 fn rem(self, rhs: &ConstDivisor) -> IBig {
401 let (sign, repr) = self.as_sign_repr();
402 IBig((repr % &rhs.0).with_sign(sign))
403 }
404}
405impl RemAssign<&ConstDivisor> for IBig {
406 #[inline]
407 fn rem_assign(&mut self, rhs: &ConstDivisor) {
408 *self = mem::take(self) % rhs;
409 }
410}
411
412impl DivRem<&ConstDivisor> for IBig {
413 type OutputDiv = IBig;
414 type OutputRem = IBig;
415
416 #[inline]
417 fn div_rem(self, rhs: &ConstDivisor) -> (IBig, IBig) {
418 let (sign, repr) = self.into_sign_repr();
419 let (q, r) = repr.div_rem(&rhs.0);
420 (IBig(q.with_sign(sign)), IBig(r.with_sign(sign)))
421 }
422}
423impl DivRem<&ConstDivisor> for &IBig {
424 type OutputDiv = IBig;
425 type OutputRem = IBig;
426
427 #[inline]
428 fn div_rem(self, rhs: &ConstDivisor) -> (IBig, IBig) {
429 let (sign, repr) = self.clone().into_sign_repr();
430 let (q, r) = repr.div_rem(&rhs.0);
431 (IBig(q.with_sign(sign)), IBig(r.with_sign(sign)))
432 }
433}
434impl DivRemAssign<&ConstDivisor> for IBig {
435 type OutputRem = IBig;
436 #[inline]
437 fn div_rem_assign(&mut self, rhs: &ConstDivisor) -> IBig {
438 let (q, r) = mem::take(self).div_rem(rhs);
439 *self = q;
440 r
441 }
442}
443
444mod repr {
445 use super::*;
446 use crate::repr::{
447 Repr,
448 TypedRepr::{self, *},
449 TypedReprRef::{self, *},
450 };
451
452 impl Div<&ConstDivisorRepr> for TypedRepr {
453 type Output = Repr;
454 fn div(self, rhs: &ConstDivisorRepr) -> Repr {
455 match (self, rhs) {
456 (Small(dword), ConstDivisorRepr::Single(div)) => {
457 Repr::from_dword(div_rem_small_single(dword, div).0)
458 }
459 (Small(dword), ConstDivisorRepr::Double(div)) => {
460 Repr::from_word(div_rem_small_double(dword, div).0)
461 }
462 (Small(_), ConstDivisorRepr::Large(_)) => {
463 Repr::zero()
465 }
466 (Large(mut buffer), ConstDivisorRepr::Single(div)) => {
467 let _rem = div::fast_div_by_word_in_place(
468 &mut buffer,
469 div.0.shift(),
470 *div.0.divider(),
471 );
472 Repr::from_buffer(buffer)
473 }
474 (Large(mut buffer), ConstDivisorRepr::Double(div)) => {
475 let _rem = div::fast_div_by_dword_in_place(
476 &mut buffer,
477 div.0.shift(),
478 *div.0.divider(),
479 );
480 Repr::from_buffer(buffer)
481 }
482 (Large(mut buffer), ConstDivisorRepr::Large(div)) => {
483 let div_len = div.normalized_divisor.len();
484 if buffer.len() < div_len {
485 Repr::zero()
486 } else {
487 let mut allocation = MemoryAllocation::new(div::memory_requirement_exact(
488 buffer.len(),
489 div_len,
490 ));
491 let q_top = div::div_rem_unshifted_in_place(
492 &mut buffer,
493 &div.normalized_divisor,
494 div.shift,
495 div.fast_div_top,
496 &mut allocation.memory(),
497 );
498 buffer.erase_front(div_len);
499 buffer.push_resizing(q_top);
500 Repr::from_buffer(buffer)
501 }
502 }
503 }
504 }
505 }
506
507 impl Rem<&ConstDivisorRepr> for TypedRepr {
508 type Output = Repr;
509
510 fn rem(self, rhs: &ConstDivisorRepr) -> Repr {
511 match (self, rhs) {
512 (Small(dword), ConstDivisorRepr::Single(div)) => {
513 Repr::from_word(div.rem_dword(dword) >> div.0.shift())
514 }
515 (Small(dword), ConstDivisorRepr::Double(div)) => {
516 Repr::from_dword(div.rem_dword(dword) >> div.0.shift())
517 }
518 (Small(dword), ConstDivisorRepr::Large(_)) => {
519 Repr::from_dword(dword)
521 }
522 (Large(buffer), ConstDivisorRepr::Single(div)) => {
523 Repr::from_word(div.rem_large(&buffer) >> div.0.shift())
524 }
525 (Large(buffer), ConstDivisorRepr::Double(div)) => {
526 Repr::from_dword(div.rem_large(&buffer) >> div.0.shift())
527 }
528 (Large(buffer), ConstDivisorRepr::Large(div)) => rem_large_large(buffer, div),
529 }
530 }
531 }
532
533 impl<'l, 'r> Rem<&'r ConstDivisorRepr> for TypedReprRef<'l> {
534 type Output = Repr;
535
536 fn rem(self, rhs: &ConstDivisorRepr) -> Repr {
537 match (self, rhs) {
538 (RefSmall(dword), ConstDivisorRepr::Single(div)) => {
539 Repr::from_word(div.rem_dword(dword) >> div.0.shift())
540 }
541 (RefSmall(dword), ConstDivisorRepr::Double(div)) => {
542 Repr::from_dword(div.rem_dword(dword) >> div.0.shift())
543 }
544 (RefSmall(dword), ConstDivisorRepr::Large(_)) => {
545 Repr::from_dword(dword)
547 }
548 (RefLarge(words), ConstDivisorRepr::Single(div)) => {
549 Repr::from_word(div.rem_large(words) >> div.0.shift())
550 }
551 (RefLarge(words), ConstDivisorRepr::Double(div)) => {
552 Repr::from_dword(div.rem_large(words) >> div.0.shift())
553 }
554 (RefLarge(words), ConstDivisorRepr::Large(div)) => {
555 rem_large_large(words.into(), div)
556 }
557 }
558 }
559 }
560
561 impl DivRem<&ConstDivisorRepr> for TypedRepr {
562 type OutputDiv = Repr;
563 type OutputRem = Repr;
564
565 fn div_rem(self, rhs: &ConstDivisorRepr) -> (Repr, Repr) {
566 match (self, rhs) {
567 (Small(dword), ConstDivisorRepr::Single(div)) => {
568 let (q, r) = div_rem_small_single(dword, div);
569 (Repr::from_dword(q), Repr::from_word(r))
570 }
571 (Small(dword), ConstDivisorRepr::Double(div)) => {
572 let (q, r) = div_rem_small_double(dword, div);
573 (Repr::from_word(q), Repr::from_dword(r))
574 }
575 (Small(dword), ConstDivisorRepr::Large(_)) => {
576 (Repr::zero(), Repr::from_dword(dword))
578 }
579 (Large(mut buffer), ConstDivisorRepr::Single(div)) => {
580 let r = div::fast_div_by_word_in_place(
581 &mut buffer,
582 div.0.shift(),
583 *div.0.divider(),
584 );
585 (Repr::from_buffer(buffer), Repr::from_word(r))
586 }
587 (Large(mut buffer), ConstDivisorRepr::Double(div)) => {
588 let r = div::fast_div_by_dword_in_place(
589 &mut buffer,
590 div.0.shift(),
591 *div.0.divider(),
592 );
593 (Repr::from_buffer(buffer), Repr::from_dword(r))
594 }
595 (Large(mut buffer), ConstDivisorRepr::Large(div)) => {
596 let div_len = div.normalized_divisor.len();
597 if buffer.len() < div_len {
598 (Repr::zero(), Repr::from_buffer(buffer))
599 } else {
600 let mut allocation = MemoryAllocation::new(div::memory_requirement_exact(
601 buffer.len(),
602 div_len,
603 ));
604 let q_top = div::div_rem_unshifted_in_place(
605 &mut buffer,
606 &div.normalized_divisor,
607 div.shift,
608 div.fast_div_top,
609 &mut allocation.memory(),
610 );
611
612 let mut q = Buffer::from(&buffer[div_len..]);
613 q.push_resizing(q_top);
614 buffer.truncate(div_len);
615 debug_assert_zero!(shift::shr_in_place(&mut buffer, div.shift));
616 (Repr::from_buffer(q), Repr::from_buffer(buffer))
617 }
618 }
619 }
620 }
621 }
622
623 fn div_rem_small_single(lhs: DoubleWord, rhs: &ConstSingleDivisor) -> (DoubleWord, Word) {
624 let (lo, mid, hi) = shl_dword(lhs, rhs.0.shift());
625 let (q1, r1) = rhs.0.divider().div_rem_2by1(double_word(mid, hi));
626 let (q0, r0) = rhs.0.divider().div_rem_2by1(double_word(lo, r1));
627 (double_word(q0, q1), r0 >> rhs.0.shift())
628 }
629
630 fn div_rem_small_double(lhs: DoubleWord, rhs: &ConstDoubleDivisor) -> (Word, DoubleWord) {
631 let (lo, mid, hi) = shl_dword(lhs, rhs.0.shift());
632 let (q, r) = rhs.0.divider().div_rem_3by2(lo, double_word(mid, hi));
633 (q, r >> rhs.0.shift())
634 }
635
636 fn rem_large_large(mut lhs: Buffer, rhs: &ConstLargeDivisor) -> Repr {
637 let modulus = &rhs.normalized_divisor;
638
639 if lhs.len() >= modulus.len() {
641 let mut allocation =
642 MemoryAllocation::new(div::memory_requirement_exact(lhs.len(), modulus.len()));
643 let _qtop = div::div_rem_unshifted_in_place(
644 &mut lhs,
645 modulus,
646 rhs.shift,
647 rhs.fast_div_top,
648 &mut allocation.memory(),
649 );
650
651 lhs.truncate(modulus.len());
652 debug_assert_zero!(shift::shr_in_place(&mut lhs, rhs.shift));
653 }
654 Repr::from_buffer(lhs)
655 }
656}