1use dashu_base::{DivRem, Sign, UnsignedAbs};
35use num_modular::{DivExact, DivExactAssign};
36
37use crate::{
38 add,
39 arch::word::{DoubleWord, Word},
40 ibig::IBig,
41 math::inv_mod_pow2,
42 mul::{sub_mul_dword_same_len_in_place, sub_mul_word_same_len_in_place},
43 primitive::{extend_word, shrink_dword, WORD_BITS},
44 repr::{TypedRepr, TypedReprRef},
45 ubig::UBig,
46};
47
48const THRESHOLD_DIV_EXACT_DEFAULT: usize = 180;
53
54mod threshold {
59 #[inline]
60 pub fn div_exact() -> usize {
61 #[cfg(feature = "tuning")]
62 {
63 if let Ok(s) = std::env::var("DASHU_THRESHOLD_DIV_EXACT") {
64 if let Ok(v) = s.parse::<usize>() {
65 return v;
66 }
67 }
68 }
69 super::THRESHOLD_DIV_EXACT_DEFAULT
70 }
71}
72
73impl UBig {
74 fn div_exact_assign_dword(&mut self, divisor: DoubleWord) -> bool {
84 if divisor == 0 {
85 return false; }
87 if self.is_zero() || divisor == 1 {
88 return true; }
90 if shrink_dword(divisor).is_some() {
91 if !self.repr().is_multiple_of(TypedReprRef::RefSmall(divisor)) {
94 return false;
95 }
96 let taken = core::mem::take(self);
97 let q = taken
98 .into_repr()
99 .div_exact(TypedRepr::Small(divisor), &())
100 .expect("the probe passed, so the division is exact");
101 *self = UBig(q);
102 return true;
103 }
104 let backup = self.clone();
107 let taken = core::mem::take(self);
108 match taken.into_repr().div_exact(TypedRepr::Small(divisor), &()) {
109 Some(q) => {
110 *self = UBig(q);
111 true
112 }
113 None => {
114 *self = backup;
115 false
116 }
117 }
118 }
119}
120
121pub(crate) mod repr {
125 use super::*;
126 use crate::{
127 arch::word::{DoubleWord, Word},
128 buffer::Buffer,
129 div,
130 math::inv_mod_pow2,
131 primitive::{extend_word, shrink_dword, split_dword, WORD_BITS, WORD_BITS_USIZE},
132 repr::{Repr, TypedRepr, TypedReprRef},
133 shift,
134 ubig::UBig,
135 };
136
137 impl DivExact<TypedRepr, ()> for TypedRepr {
138 type Output = Repr;
139
140 #[inline]
141 fn div_exact(self, rhs: TypedRepr, _: &()) -> Option<Repr> {
142 match (self, rhs) {
143 (TypedRepr::Small(dword0), TypedRepr::Small(dword1)) => {
144 div_exact_dword(dword0, dword1)
145 }
146 (TypedRepr::Small(_), TypedRepr::Large(_)) => None, (TypedRepr::Large(buffer0), TypedRepr::Small(dword1)) => {
148 if let Some(word) = shrink_dword(dword1) {
149 div_exact_large_word(buffer0, word)
150 } else {
151 div_exact_large_dword(buffer0, dword1)
152 }
153 }
154 (TypedRepr::Large(buffer0), TypedRepr::Large(buffer1)) => {
155 div_exact_large(buffer0, buffer1)
156 }
157 }
158 }
159 }
160
161 impl<'l> DivExact<TypedRepr, ()> for TypedReprRef<'l> {
162 type Output = Repr;
163
164 #[inline]
165 fn div_exact(self, rhs: TypedRepr, _: &()) -> Option<Repr> {
166 match (self, rhs) {
167 (TypedReprRef::RefSmall(dword0), TypedRepr::Small(dword1)) => {
168 div_exact_dword(dword0, dword1)
169 }
170 (TypedReprRef::RefSmall(_), TypedRepr::Large(_)) => None,
171 (TypedReprRef::RefLarge(words0), TypedRepr::Small(dword1)) => {
172 if let Some(word) = shrink_dword(dword1) {
173 div_exact_large_word(words0.into(), word)
174 } else {
175 div_exact_large_dword(words0.into(), dword1)
176 }
177 }
178 (TypedReprRef::RefLarge(words0), TypedRepr::Large(buffer1)) => {
179 div_exact_large(words0.into(), buffer1)
180 }
181 }
182 }
183 }
184
185 impl<'r> DivExact<TypedReprRef<'r>, ()> for TypedRepr {
186 type Output = Repr;
187
188 #[inline]
189 fn div_exact(self, rhs: TypedReprRef, _: &()) -> Option<Repr> {
190 match (self, rhs) {
191 (TypedRepr::Small(dword0), TypedReprRef::RefSmall(dword1)) => {
192 div_exact_dword(dword0, dword1)
193 }
194 (TypedRepr::Small(_), TypedReprRef::RefLarge(_)) => None,
195 (TypedRepr::Large(buffer0), TypedReprRef::RefSmall(dword1)) => {
196 if let Some(word) = shrink_dword(dword1) {
197 div_exact_large_word(buffer0, word)
198 } else {
199 div_exact_large_dword(buffer0, dword1)
200 }
201 }
202 (TypedRepr::Large(buffer0), TypedReprRef::RefLarge(words1)) => {
203 div_exact_large(buffer0, words1.into())
204 }
205 }
206 }
207 }
208
209 impl<'l, 'r> DivExact<TypedReprRef<'r>, ()> for TypedReprRef<'l> {
210 type Output = Repr;
211
212 #[inline]
213 fn div_exact(self, rhs: TypedReprRef, _: &()) -> Option<Repr> {
214 match (self, rhs) {
215 (TypedReprRef::RefSmall(dword0), TypedReprRef::RefSmall(dword1)) => {
216 div_exact_dword(dword0, dword1)
217 }
218 (TypedReprRef::RefSmall(_), TypedReprRef::RefLarge(_)) => None,
219 (TypedReprRef::RefLarge(words0), TypedReprRef::RefSmall(dword1)) => {
220 if let Some(word) = shrink_dword(dword1) {
221 div_exact_large_word(words0.into(), word)
222 } else {
223 div_exact_large_dword(words0.into(), dword1)
224 }
225 }
226 (TypedReprRef::RefLarge(words0), TypedReprRef::RefLarge(words1)) => {
227 div_exact_large(words0.into(), words1.into())
228 }
229 }
230 }
231 }
232
233 #[inline]
235 fn div_exact_dword(lhs: DoubleWord, rhs: DoubleWord) -> Option<Repr> {
236 if rhs == 0 {
237 None
238 } else if rhs == 1 {
239 Some(Repr::from_dword(lhs))
240 } else if lhs % rhs == 0 {
241 Some(Repr::from_dword(lhs / rhs))
242 } else {
243 None
244 }
245 }
246
247 fn div_exact_large_word(mut buffer: Buffer, d: Word) -> Option<Repr> {
253 if d == 0 {
254 return None; }
256 if d == 1 {
257 return Some(Repr::from_buffer(buffer));
258 }
259 let trailing = d.trailing_zeros();
260 let d_odd = d >> trailing;
261 if d_odd == 1 {
262 if trailing_zeros(&buffer) >= trailing as usize {
264 shift::shr_in_place(&mut buffer, trailing);
265 return Some(Repr::from_buffer(buffer));
266 }
267 return None;
268 }
269 if trailing > 0 && trailing_zeros(&buffer) < trailing as usize {
270 return None;
271 }
272 let di = inv_mod_pow2(extend_word(d_odd), WORD_BITS) as Word;
273 if !hensel_div_odd_in_place(&mut buffer, d_odd, di) {
274 return None;
275 }
276 if trailing > 0 {
277 shift::shr_in_place(&mut buffer, trailing);
278 }
279 Some(Repr::from_buffer(buffer))
280 }
281
282 fn div_exact_large_dword(mut buffer: Buffer, d: DoubleWord) -> Option<Repr> {
288 debug_assert!(shrink_dword(d).is_none()); let trailing = d.trailing_zeros();
290 let d_odd = d >> trailing;
291 if d_odd == 1 {
292 if trailing_zeros(&buffer) >= trailing as usize {
294 shr_erase_front(&mut buffer, trailing as usize);
295 return Some(Repr::from_buffer(buffer));
296 }
297 return None;
298 }
299 if trailing > 0 && trailing_zeros(&buffer) < trailing as usize {
300 return None;
301 }
302 if let Some(word) = shrink_dword(d_odd) {
303 let di = inv_mod_pow2(extend_word(word), WORD_BITS) as Word;
304 if !hensel_div_odd_in_place(&mut buffer, word, di) {
305 return None;
306 }
307 } else {
308 let (d_lo, d_hi) = split_dword(d_odd);
309 let di = inv_mod_pow2(extend_word(d_lo), WORD_BITS) as Word;
310 if !hensel_div_odd_dword_in_place(&mut buffer, d_lo, d_hi, di) {
311 return None;
312 }
313 }
314 if trailing > 0 {
315 shr_erase_front(&mut buffer, trailing as usize);
316 }
317 Some(Repr::from_buffer(buffer))
318 }
319
320 fn div_exact_large(mut dividend: Buffer, mut divisor: Buffer) -> Option<Repr> {
330 if dividend.len() < divisor.len() {
331 return None; }
333 if divisor.len() > super::threshold::div_exact() {
334 let (q, r) =
336 UBig(Repr::from_buffer(dividend)).div_rem(UBig(Repr::from_buffer(divisor)));
337 return if r.is_zero() { Some(q.0) } else { None };
338 }
339 let s = trailing_zeros(&divisor);
340 if s > 0 {
341 if trailing_zeros(÷nd) < s {
342 return None; }
344 shr_erase_front(&mut dividend, s);
345 shr_erase_front(&mut divisor, s);
346 divisor.pop_zeros();
347 dividend.pop_zeros();
348 }
349 if dividend.len() < divisor.len() {
350 return None; }
352 match divisor.len() {
353 1 => {
354 let d = divisor[0];
356 debug_assert!(d & 1 == 1, "the common factors of 2 were already stripped");
357 let di = inv_mod_pow2(extend_word(d), WORD_BITS) as Word;
358 if !hensel_div_odd_in_place(&mut dividend, d, di) {
359 return None;
360 }
361 }
362 2 => {
363 let (d_lo, d_hi) = (divisor[0], divisor[1]);
364 debug_assert!(d_lo & 1 == 1, "the common factors of 2 were already stripped");
365 let di = inv_mod_pow2(extend_word(d_lo), WORD_BITS) as Word;
366 if !hensel_div_odd_dword_in_place(&mut dividend, d_lo, d_hi, di) {
367 return None;
368 }
369 }
370 _ => {
371 if !hensel_div_exact_large(&mut dividend, &divisor) {
372 return None;
373 }
374 }
375 }
376 Some(Repr::from_buffer(dividend))
377 }
378
379 impl TypedReprRef<'_> {
380 pub(crate) fn is_multiple_of(&self, rhs: TypedReprRef) -> bool {
387 match (self, rhs) {
388 (TypedReprRef::RefSmall(dword0), TypedReprRef::RefSmall(dword1)) => {
389 dword1 != 0 && dword0 % dword1 == 0
390 }
391 (TypedReprRef::RefSmall(_), TypedReprRef::RefLarge(_)) => false,
392 (TypedReprRef::RefLarge(words0), TypedReprRef::RefSmall(dword1)) => {
393 is_multiple_of_dword(words0, dword1)
394 }
395 (TypedReprRef::RefLarge(words0), TypedReprRef::RefLarge(words1)) => {
396 is_multiple_of_large(words0, words1)
397 }
398 }
399 }
400 }
401
402 fn is_multiple_of_word(words: &[Word], d: Word) -> bool {
404 if d == 0 {
405 return false; }
407 let trailing = d.trailing_zeros();
408 let d_odd = d >> trailing;
409 if d_odd == 1 {
410 return trailing_zeros(words) >= trailing as usize;
412 }
413 if trailing > 0 && trailing_zeros(words) < trailing as usize {
414 return false;
415 }
416 let di = inv_mod_pow2(extend_word(d_odd), WORD_BITS) as Word;
417 hensel_is_multiple_of(words, d_odd, di)
418 }
419
420 fn is_multiple_of_dword(words: &[Word], d: DoubleWord) -> bool {
424 if d == 0 {
425 return false; }
427 if let Some(word) = shrink_dword(d) {
428 return is_multiple_of_word(words, word);
429 }
430 let trailing = d.trailing_zeros();
431 let d_odd = d >> trailing;
432 if d_odd == 1 {
433 return trailing_zeros(words) >= trailing as usize;
434 }
435 if trailing > 0 && trailing_zeros(words) < trailing as usize {
436 return false;
437 }
438 let mut buffer = words.to_vec();
439 if let Some(word) = shrink_dword(d_odd) {
440 let di = inv_mod_pow2(extend_word(word), WORD_BITS) as Word;
444 hensel_div_odd_in_place(&mut buffer, word, di)
445 } else {
446 let (d_lo, d_hi) = split_dword(d_odd);
447 let di = inv_mod_pow2(extend_word(d_lo), WORD_BITS) as Word;
448 hensel_div_odd_dword_in_place(&mut buffer, d_lo, d_hi, di)
449 }
450 }
451
452 fn is_multiple_of_large(words: &[Word], divisor: &[Word]) -> bool {
457 div_exact_large(Buffer::from(words), Buffer::from(divisor)).is_some()
458 }
459
460 fn trailing_zeros(words: &[Word]) -> usize {
463 for (i, &w) in words.iter().enumerate() {
464 if w != 0 {
465 return i * WORD_BITS_USIZE + w.trailing_zeros() as usize;
466 }
467 }
468 usize::MAX
469 }
470
471 fn shr_erase_front(buffer: &mut Buffer, shift: usize) {
476 buffer.erase_front(shift / WORD_BITS_USIZE);
477 if shift % WORD_BITS_USIZE != 0 {
478 shift::shr_in_place(buffer, (shift % WORD_BITS_USIZE) as u32);
479 }
480 }
481
482 impl<'a> TypedReprRef<'a> {
487 pub(crate) const fn is_multiple_of_dword(self, divisor: DoubleWord) -> bool {
488 if let Some(w) = shrink_dword(divisor) {
489 match self {
490 TypedReprRef::RefSmall(dword) => dword % extend_word(w) == 0,
491 TypedReprRef::RefLarge(words) => div::rem_by_word(words, w) == 0,
492 }
493 } else {
494 match self {
495 TypedReprRef::RefSmall(dword) => dword % divisor == 0,
496 TypedReprRef::RefLarge(words) => div::rem_by_dword(words, divisor) == 0,
497 }
498 }
499 }
500 }
501}
502
503pub(crate) fn hensel_div_odd_in_place(words: &mut [Word], d: Word, di: Word) -> bool {
514 let mut c: Word = 0;
515 let mut q_last = words[0].wrapping_mul(di);
516 words[0] = q_last;
517 for word in words.iter_mut().skip(1) {
518 let h = ((extend_word(q_last) * extend_word(d)) >> WORD_BITS) as Word;
519 c = c.wrapping_add(h);
520 let (l, borrow) = word.overflowing_sub(c);
521 c = borrow as Word;
522 q_last = l.wrapping_mul(di);
523 *word = q_last;
524 }
525 let h = ((extend_word(q_last) * extend_word(d)) >> WORD_BITS) as Word;
526 c == 0 && h == 0
527}
528
529pub(crate) fn hensel_is_multiple_of(words: &[Word], d: Word, di: Word) -> bool {
536 let mut c: Word = 0;
537 let mut q_last = words[0].wrapping_mul(di);
538 for word in words.iter().skip(1) {
539 let h = ((extend_word(q_last) * extend_word(d)) >> WORD_BITS) as Word;
540 c = c.wrapping_add(h);
541 let (l, borrow) = word.overflowing_sub(c);
542 c = borrow as Word;
543 q_last = l.wrapping_mul(di);
544 }
545 let h = ((extend_word(q_last) * extend_word(d)) >> WORD_BITS) as Word;
546 c == 0 && h == 0
547}
548
549pub(crate) fn hensel_div_odd_dword_in_place(
558 words: &mut [Word],
559 d_lo: Word,
560 d_hi: Word,
561 di: Word,
562) -> bool {
563 let n = words.len();
564 debug_assert!(n >= 2 && d_lo & 1 == 1);
565 for i in 0..n - 1 {
566 let q = words[i].wrapping_mul(di);
567 let (borrow_lo, borrow_hi) =
570 sub_mul_dword_same_len_in_place(&mut words[i..i + 2], &[d_lo, d_hi], q, 0);
571 debug_assert!(borrow_hi == 0, "the total borrow of q·d is at most one word");
572 if borrow_lo != 0 && (i + 2 >= n || add::sub_word_in_place(&mut words[i + 2..], borrow_lo))
573 {
574 return false; }
576 words[i] = q;
577 }
578 words[n - 1] == 0
579}
580
581pub(crate) fn hensel_div_exact_large(dividend: &mut [Word], divisor: &[Word]) -> bool {
591 let n = dividend.len();
592 let m = divisor.len();
593 debug_assert!(n >= m && m >= 2 && divisor[0] & 1 == 1);
594 let qn = n - m + 1;
595 let di = inv_mod_pow2(extend_word(divisor[0]), WORD_BITS) as Word;
596
597 for i in 0..qn {
598 let q = dividend[i].wrapping_mul(di);
599 let mut borrow = sub_mul_word_same_len_in_place(&mut dividend[i..i + m], q, divisor);
603 if borrow != 0 {
604 for w in dividend[i + m..].iter_mut() {
605 let (l, b) = w.overflowing_sub(borrow);
606 *w = l;
607 borrow = b as Word;
608 if borrow == 0 {
609 break;
610 }
611 }
612 }
613 if borrow != 0 {
614 return false; }
616 dividend[i] = q;
617 }
618 dividend[qn..].iter().all(|&w| w == 0)
619}
620
621impl UBig {
622 #[inline]
640 pub fn is_multiple_of(&self, divisor: &Self) -> bool {
641 assert!(!divisor.is_zero(), "division by zero");
642 self.repr().is_multiple_of(divisor.repr())
643 }
644
645 #[inline]
649 pub const fn is_multiple_of_const(&self, divisor: DoubleWord) -> bool {
650 self.repr().is_multiple_of_dword(divisor)
651 }
652}
653
654impl IBig {
655 #[inline]
670 pub fn is_multiple_of(&self, divisor: &Self) -> bool {
671 self.unsigned_abs().is_multiple_of(&divisor.unsigned_abs())
672 }
673
674 #[inline]
678 pub const fn is_multiple_of_const(&self, divisor: DoubleWord) -> bool {
679 let (_, repr) = self.as_sign_repr();
680 repr.is_multiple_of_dword(divisor)
681 }
682}
683
684impl DivExact<UBig, ()> for UBig {
692 type Output = UBig;
693
694 #[inline]
695 fn div_exact(self, rhs: UBig, _: &()) -> Option<UBig> {
696 self.into_repr().div_exact(rhs.into_repr(), &()).map(UBig)
697 }
698}
699
700impl DivExact<UBig, ()> for &UBig {
701 type Output = UBig;
702
703 #[inline]
704 fn div_exact(self, rhs: UBig, _: &()) -> Option<UBig> {
705 self.clone().div_exact(rhs, &())
706 }
707}
708
709impl DivExactAssign<UBig, ()> for UBig {
710 #[inline]
711 fn div_exact_assign(&mut self, rhs: UBig, _: &()) -> bool {
712 if let TypedReprRef::RefSmall(dword) = rhs.repr() {
713 return self.div_exact_assign_dword(dword);
714 }
715 let backup = self.clone();
718 let taken = core::mem::take(self);
719 match taken.into_repr().div_exact(rhs.into_repr(), &()) {
720 Some(q) => {
721 *self = UBig(q);
722 true
723 }
724 None => {
725 *self = backup;
726 false
727 }
728 }
729 }
730}
731
732macro_rules! impl_div_exact_ubig_with_prim {
733 ($($T:ty)*) => {$(
734 impl DivExact<$T, ()> for UBig {
735 type Output = UBig;
736 #[inline]
737 fn div_exact(self, rhs: $T, _: &()) -> Option<UBig> {
738 match DoubleWord::try_from(rhs) {
739 Ok(dword) => self.into_repr().div_exact(TypedRepr::Small(dword), &()).map(UBig),
740 Err(_) => DivExact::<UBig, ()>::div_exact(self, UBig::from(rhs), &()),
741 }
742 }
743 }
744 impl DivExactAssign<$T, ()> for UBig {
745 #[inline]
746 fn div_exact_assign(&mut self, rhs: $T, _: &()) -> bool {
747 match DoubleWord::try_from(rhs) {
748 Ok(dword) => self.div_exact_assign_dword(dword),
749 Err(_) => {
750 let (q, r) = (&*self).div_rem(&UBig::from(rhs));
751 if r.is_zero() {
752 *self = q;
753 true
754 } else {
755 false
756 }
757 }
758 }
759 }
760 }
761 )*};
762}
763impl_div_exact_ubig_with_prim!(u8 u16 u32 u64 u128 usize);
764
765impl DivExact<IBig, ()> for IBig {
770 type Output = IBig;
771
772 fn div_exact(self, rhs: IBig, _: &()) -> Option<IBig> {
773 let (sign_self, mag_self) = self.into_parts();
774 let (sign_rhs, mag_rhs) = rhs.into_parts();
775 let q_mag = mag_self.div_exact(mag_rhs, &())?;
776 Some(IBig::from_parts(sign_self * sign_rhs, q_mag))
777 }
778}
779
780impl DivExactAssign<IBig, ()> for IBig {
781 fn div_exact_assign(&mut self, rhs: IBig, _: &()) -> bool {
782 if let Some(q) = self.clone().div_exact(rhs, &()) {
783 *self = q;
784 true
785 } else {
786 false
787 }
788 }
789}
790
791impl DivExact<IBig, ()> for &IBig {
792 type Output = IBig;
793
794 #[inline]
795 fn div_exact(self, rhs: IBig, _: &()) -> Option<IBig> {
796 self.clone().div_exact(rhs, &())
797 }
798}
799
800macro_rules! impl_div_exact_ibig_with_prim {
801 ($($T:ty)*) => {$(
802 impl DivExact<$T, ()> for IBig {
803 type Output = IBig;
804 #[inline]
805 fn div_exact(self, rhs: $T, _: &()) -> Option<IBig> {
806 let sign = self.sign();
807 let q_mag = self.unsigned_abs().div_exact(rhs, &())?;
808 Some(IBig::from_parts(sign, q_mag))
809 }
810 }
811 impl DivExactAssign<$T, ()> for IBig {
812 #[inline]
813 fn div_exact_assign(&mut self, rhs: $T, _: &()) -> bool {
814 if let Some(q) = self.clone().div_exact(rhs, &()) {
815 *self = q;
816 true
817 } else {
818 false
819 }
820 }
821 }
822 )*};
823}
824impl_div_exact_ibig_with_prim!(u8 u16 u32 u64 u128 usize);
825
826macro_rules! impl_div_exact_ibig_with_signed_prim {
827 ($($T:ty)*) => {$(
828 impl DivExact<$T, ()> for IBig {
829 type Output = IBig;
830 #[inline]
831 fn div_exact(self, rhs: $T, _: &()) -> Option<IBig> {
832 let sign = if (self.sign() == Sign::Negative) != (rhs < 0) {
833 Sign::Negative
834 } else {
835 Sign::Positive
836 };
837 let q_mag = self.unsigned_abs().div_exact(rhs.unsigned_abs(), &())?;
838 Some(IBig::from_parts(sign, q_mag))
839 }
840 }
841 impl DivExactAssign<$T, ()> for IBig {
842 #[inline]
843 fn div_exact_assign(&mut self, rhs: $T, _: &()) -> bool {
844 if let Some(q) = self.clone().div_exact(rhs, &()) {
845 *self = q;
846 true
847 } else {
848 false
849 }
850 }
851 }
852 )*};
853}
854impl_div_exact_ibig_with_signed_prim!(i8 i16 i32 i64 i128 isize);
855
856#[cfg(test)]
857mod tests {
858 use super::*;
859 use crate::{
860 arch::word::Word,
861 primitive::{extend_word, WORD_BITS_USIZE},
862 };
863
864 #[test]
868 fn test_div_exact_assign_matches_div() {
869 use dashu_base::DivExactAssign;
870
871 for d in [2u16, 3, 5, 7, 10, 12, 16, 25, 255, 1001] {
872 let d = d as Word;
873 for i in 1..10usize {
874 for rest in [1u8, 5, 7, 11] {
875 let n = UBig::from(d).pow(i) * rest;
876 let want = &n / UBig::from_word(d);
877 let mut got = n;
878 assert!(got.div_exact_assign(extend_word(d), &()), "d={d} i={i} rest={rest}");
879 assert_eq!(got, want, "d={d} i={i} rest={rest}");
880 }
881 }
882 let mut n = UBig::from(d).pow(2) + 1u8;
884 let before = n.clone();
885 assert!(!n.div_exact_assign(extend_word(d), &()), "d={d}");
886 assert_eq!(n, before, "d={d}");
887 }
888 }
889
890 #[test]
893 fn test_div_exact_matches_div() {
894 for d in [
896 UBig::from(10u8).pow(8), (UBig::ONE << 64) + 3u8, (UBig::ONE << 70) * 5u8, ] {
900 for i in 1..6usize {
901 let n = d.clone().pow(i) * 7u8;
902 let (q, r) = (&n).div_rem(&d);
903 assert!(r.is_zero(), "d={d:?} i={i}");
904 assert_eq!(n.clone().div_exact(d.clone(), &()), Some(q), "d={d:?} i={i}");
905 }
906 let n = d.clone().pow(2) + 1u8;
907 assert_eq!(n.div_exact(d, &()), None, "d must not divide d^2+1");
908 }
909
910 let big = UBig::from(10u8).pow(50);
912 for (a, b) in [
913 (UBig::from(10u8).pow(80) * 7u8, UBig::from(10u8).pow(80)),
914 (big.clone() * UBig::from(13u8), big.clone()),
915 (UBig::from(2u8).pow(300) * 3u8, UBig::from(8u8)),
916 ] {
917 let (q, r) = (&a).div_rem(&b);
918 assert_eq!(a.div_exact(b, &()), if r.is_zero() { Some(q) } else { None });
919 }
920 assert_eq!(UBig::from(7u8).div_exact(3u8, &()), None);
922 assert_eq!(UBig::from(7u8).div_exact(UBig::from(3u8), &()), None);
923 assert_eq!(UBig::from(7u8).div_exact(big, &()), None);
924 }
925
926 #[test]
929 fn test_hensel_div_exact_large_matches_div() {
930 for d_bits in [70usize, 100, 150, 300] {
931 let d = (UBig::ONE << d_bits) + 1u8;
932 let dw = d.as_words().to_vec();
933 for i in 1..5usize {
934 let n = d.clone().pow(i) * 12345u16;
935 let want = &n / &d;
936 let mut buf = n.as_words().to_vec();
937 assert!(hensel_div_exact_large(&mut buf, &dw), "d={d_bits} i={i}");
938 assert_eq!(UBig::from_words(&buf), want, "d={d_bits} i={i}");
939 }
940 let n = d.clone().pow(2) + 2u8;
942 let mut buf = n.as_words().to_vec();
943 assert!(!hensel_div_exact_large(&mut buf, &dw), "d={d_bits}");
944 }
945
946 for d_bits in [70usize, 130, 300] {
948 let odd = (UBig::ONE << d_bits) + 5u8;
949 let d = &odd * UBig::from(16u8);
950 let n = d.clone().pow(3) * 77u8;
951 let (q, r) = (&n).div_rem(&d);
952 assert!(r.is_zero());
953 assert_eq!(n.clone().div_exact(d.clone(), &()), Some(q));
954 assert_eq!((odd * 7u8).div_exact(d, &()), None);
956 }
957 }
958
959 #[test]
963 fn test_div_exact_assign_dword() {
964 use dashu_base::DivExactAssign;
965
966 let base = extend_word(Word::MAX) * extend_word(Word::MAX); for d in [
968 base + 2, base + 3, (1 as DoubleWord) << (2 * WORD_BITS_USIZE - 1), ] {
972 let d_ubig = UBig::from_dword(d);
973 for i in 1..6usize {
974 let n = d_ubig.clone().pow(i) * 7u8;
975 let want = &n / &d_ubig;
976 let mut got = n;
977 assert!(got.div_exact_assign(d, &()), "d={d:?} i={i}");
978 assert_eq!(got, want, "d={d:?} i={i}");
979 }
980 let mut n = d_ubig.clone().pow(2) + 1u8;
981 let before = n.clone();
982 assert!(!n.div_exact_assign(d, &()), "d={d:?}");
983 assert_eq!(n, before, "d={d:?}");
984 }
985 }
986
987 #[test]
990 fn test_div_exact_trait_impls() {
991 use dashu_base::{DivExact, DivExactAssign};
992
993 let a = UBig::from(10u8).pow(8) * 7u8;
995 assert_eq!(a.clone().div_exact(UBig::from(10u8).pow(8), &()), Some(UBig::from(7u8)));
996 assert_eq!(a.div_exact(UBig::from(3u8), &()), None);
997
998 assert_eq!(UBig::from(10u8).pow(8).div_exact(10u8, &()), Some(UBig::from(10u8).pow(7)));
1000 assert_eq!(UBig::from(10u8).pow(8).div_exact(10u32, &()), Some(UBig::from(10u8).pow(7)));
1001 assert_eq!(UBig::from(10u8).pow(8).div_exact(10u128, &()), Some(UBig::from(10u8).pow(7)));
1002 let wide = 1u128 << 100; assert_eq!(UBig::from(10u8).pow(8).div_exact(wide, &()), None);
1004 assert_eq!(UBig::from(wide).div_exact(1u128, &()), Some(UBig::from(wide)));
1005
1006 let mut b = UBig::from(10u8).pow(8) * 7u8;
1008 assert!(b.div_exact_assign(10u8, &()));
1009 assert_eq!(b, UBig::from(10u8).pow(7) * 7u8);
1010 assert!(!b.div_exact_assign(3u8, &())); assert_eq!(b, UBig::from(10u8).pow(7) * 7u8);
1012
1013 let d = UBig::from(10u8).pow(50);
1015 let mut c = d.clone().pow(2) * 7u8;
1016 assert!(c.div_exact_assign(d.clone(), &()));
1017 assert_eq!(c, &d * 7u8);
1018 let mut c = d.clone().pow(2) * 7u8;
1019 let before = c.clone();
1020 assert!(!c.div_exact_assign(d.clone() + 1u8, &()));
1021 assert_eq!(c, before);
1022
1023 let ref_a = UBig::from(10u8).pow(8) * 7u8;
1025 assert_eq!((&ref_a).div_exact(UBig::from(10u8).pow(8), &()), Some(UBig::from(7u8)));
1026 assert_eq!((&ref_a).div_exact(UBig::from(3u8), &()), None);
1027 assert_eq!(ref_a, UBig::from(10u8).pow(8) * 7u8); }
1029
1030 #[test]
1033 fn test_div_exact_ibig() {
1034 use dashu_base::{DivExact, DivExactAssign};
1035
1036 let a = IBig::from(10u8).pow(8) * 7u8;
1038 assert_eq!(a.clone().div_exact(IBig::from(10u8).pow(8), &()), Some(IBig::from(7u8)));
1039 assert_eq!(a.div_exact(IBig::from(3u8), &()), None);
1040 assert_eq!(IBig::from(-14i32).div_exact(IBig::from(7i32), &()), Some(IBig::from(-2i32)));
1042 assert_eq!(IBig::from(14i32).div_exact(IBig::from(-7i32), &()), Some(IBig::from(-2i32)));
1043 assert_eq!(IBig::from(-14i32).div_exact(IBig::from(-7i32), &()), Some(IBig::from(2i32)));
1044
1045 let ref_a = IBig::from(10u8).pow(8) * 7u8;
1047 assert_eq!((&ref_a).div_exact(IBig::from(10u8).pow(8), &()), Some(IBig::from(7u8)));
1048 assert_eq!((&ref_a).div_exact(IBig::from(3u8), &()), None);
1049 assert_eq!(ref_a, IBig::from(10u8).pow(8) * 7u8); assert_eq!(IBig::from(10u8).pow(8).div_exact(10u8, &()), Some(IBig::from(10u8).pow(7)));
1053 assert_eq!(IBig::from(-20i32).div_exact(5i32, &()), Some(IBig::from(-4i32)));
1054 assert_eq!(IBig::from(20i32).div_exact(-5i32, &()), Some(IBig::from(-4i32)));
1055 assert_eq!(IBig::from(20i32).div_exact(7i32, &()), None);
1056
1057 let mut b = IBig::from(10u8).pow(8) * 7u8;
1059 assert!(b.div_exact_assign(IBig::from(10u8).pow(8), &()));
1060 assert_eq!(b, IBig::from(7u8));
1061 assert!(!b.div_exact_assign(3u8, &())); assert_eq!(b, IBig::from(7u8));
1063 assert!(b.div_exact_assign(-7i32, &()));
1064 assert_eq!(b, IBig::from(-1i32));
1065 }
1066
1067 #[test]
1070 fn test_is_multiple_of_matches_rem() {
1071 for d in [2u16, 3, 5, 7, 10, 12, 16, 25, 255] {
1073 let d = d as Word;
1074 for i in 1..10usize {
1075 for rest in [1u8, 5, 7, 11] {
1076 let n = UBig::from(d).pow(i) * rest;
1077 let want = (&n % UBig::from_word(d)).is_zero();
1078 assert_eq!(
1079 n.is_multiple_of(&UBig::from_word(d)),
1080 want,
1081 "d={d} i={i} rest={rest}"
1082 );
1083 }
1084 }
1085 }
1086
1087 for d in [
1089 (UBig::ONE << 64) + 3u8,
1090 (UBig::ONE << 70) * 5u8,
1091 UBig::ONE << 100,
1092 ] {
1093 for i in 1..8usize {
1094 let n = d.clone().pow(i) * 7u8;
1095 let want = (&n % &d).is_zero();
1096 assert_eq!(n.is_multiple_of(&d), want, "d={d:?} i={i}");
1097 }
1098 let n = d.clone().pow(2) + 1u8;
1099 assert!(!n.is_multiple_of(&d));
1100 }
1101
1102 let d = (UBig::ONE << 200) + 1u8;
1104 for i in 1..6usize {
1105 let n = d.clone().pow(i) * 11u8;
1106 let want = (&n % &d).is_zero();
1107 assert_eq!(n.is_multiple_of(&d), want, "i={i}");
1108 }
1109 assert!(!(d.clone().pow(2) + 2u8).is_multiple_of(&d));
1110 }
1111
1112 #[test]
1114 fn test_is_multiple_of_const_matches_rem() {
1115 for (n, d) in [
1116 (UBig::from(24u8), 6u8),
1117 (UBig::from(24u8), 7u8),
1118 (UBig::from(10u8).pow(8), 10u8),
1119 (UBig::from(10u8).pow(8), 3u8),
1120 ] {
1121 assert_eq!(
1122 n.is_multiple_of_const(d as DoubleWord),
1123 (&n % UBig::from_word(d as Word)).is_zero()
1124 );
1125 }
1126 }
1127}