1use crate::primes::{
16 ODD_PRIME_DIVIDERS_U16, ODD_PRIME_DIVIDERS_U32, ODD_PRIME_DIVIDERS_U64, ODD_PRIMES,
17 known_odd_prime_factor_indices,
18};
19use crate::util::OddDivider;
20use crate::{Denom, DenomRef};
21use num_bigint::{BigInt, BigUint, Sign};
22use num_integer::Integer;
23use num_traits::{One, Zero};
24use std::cmp::Ordering;
25use std::ops::{Div, DivAssign, Mul, MulAssign};
26
27#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct DenomArray<const NUM_PRIMES: usize> {
32 primes: [u8; NUM_PRIMES],
35 remainder: Option<BigUint>,
36}
37
38pub type DenomArray24 = DenomArray<24>;
42
43impl<const NUM_PRIMES: usize> DenomRef<DenomArray<NUM_PRIMES>> for &DenomArray<NUM_PRIMES> {}
44
45impl<const NUM_PRIMES: usize> Denom for DenomArray<NUM_PRIMES> {
46 const ONE: Self = Self {
47 primes: [0; NUM_PRIMES],
48 remainder: None,
49 };
50
51 fn into_biguint(self) -> BigUint {
52 self.into()
53 }
54
55 fn to_biguint(&self) -> BigUint {
56 self.into()
57 }
58
59 fn normalize(lnum: &mut BigInt, rnum: &mut BigInt, ldenom: &Self, rdenom: &Self) -> Self {
60 const {
61 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
62 }
63
64 let mut primes = [0; NUM_PRIMES];
65 let mut ltmp = 1_usize;
66 let mut rtmp = 1_usize;
67 for i in 0..NUM_PRIMES {
68 let p = if i == 0 {
69 2
70 } else {
71 ODD_PRIMES[i - 1] as usize
72 };
73 let lcount = ldenom.primes[i];
74 let rcount = rdenom.primes[i];
75 match lcount.cmp(&rcount) {
76 Ordering::Equal => {
77 primes[i] = lcount;
78 }
79 Ordering::Less => {
80 Self::accum_pow(lnum, &mut ltmp, p, rcount - lcount);
81 primes[i] = rcount;
82 }
83 Ordering::Greater => {
84 Self::accum_pow(rnum, &mut rtmp, p, lcount - rcount);
85 primes[i] = lcount;
86 }
87 }
88 }
89
90 *lnum *= ltmp;
91 *rnum *= rtmp;
92 let remainder = match (&ldenom.remainder, &rdenom.remainder) {
93 (None, None) => None,
94 (None, Some(r)) => {
95 *lnum *= BigInt::from_biguint(Sign::Plus, r.clone());
96 Some(r.clone())
97 }
98 (Some(l), None) => {
99 *rnum *= BigInt::from_biguint(Sign::Plus, l.clone());
100 Some(l.clone())
101 }
102 (Some(l), Some(r)) => {
103 if l == r {
104 Some(l.clone())
105 } else {
106 *lnum *= BigInt::from_biguint(Sign::Plus, r.clone());
107 *rnum *= BigInt::from_biguint(Sign::Plus, l.clone());
108 Some(l * r)
109 }
110 }
111 };
112 Self { primes, remainder }
113 }
114
115 fn gcd_reduce(&mut self, num: &mut BigInt) {
116 const {
117 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
118 }
119
120 if let Some(remainder) = &mut self.remainder {
121 let gcd = remainder.gcd(num.magnitude());
122 if !gcd.is_one() {
123 *remainder /= &gcd;
124 if remainder.is_one() {
125 self.remainder = None;
126 }
127 let gcd: BigInt = gcd.into();
128 *num /= gcd;
129 }
130 }
131
132 'outer: for i in 0..NUM_PRIMES {
133 let p = if i == 0 { 2 } else { ODD_PRIMES[i - 1] };
134 if self.primes[i] != 0 {
135 let p = BigInt::from(p);
136 while self.primes[i] != 0 {
137 let (quo, rem) = num.div_rem(&p);
138 if !rem.is_zero() {
139 break;
140 }
141 *num = quo;
142 self.primes[i] -= 1;
143 if num.magnitude().is_one() {
144 break 'outer;
145 }
146 }
147 }
148 }
149 }
150}
151
152impl<const NUM_PRIMES: usize> DenomArray<NUM_PRIMES> {
153 fn decompose(mut x: BigUint) -> Self {
154 const {
155 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
156 }
157
158 let bits = x.bits();
159 if bits <= 8 {
160 return Self::decompose_u8(x.try_into().unwrap());
161 } else if bits <= 16 {
162 return Self::decompose_u16(x.try_into().unwrap());
163 } else if bits <= 32 {
164 return Self::decompose_u32(x.try_into().unwrap());
165 } else if bits <= 64 {
166 return Self::decompose_u64(x.try_into().unwrap());
167 } else if bits <= 128 {
168 return Self::decompose_u128(x.try_into().unwrap());
169 }
170
171 let mut primes = [0; NUM_PRIMES];
172
173 let mut count2 = x.trailing_zeros().unwrap();
174 if count2 != 0 {
175 x >>= count2;
176 if count2 <= u8::MAX as u64 {
177 primes[0] = count2 as u8;
178 count2 = 0;
179 } else {
180 primes[0] = u8::MAX;
181 count2 -= u8::MAX as u64;
182 }
183 }
184
185 'outer: for i in 1..NUM_PRIMES {
186 let p = BigUint::from(ODD_PRIMES[i - 1]);
187 while primes[i] != u8::MAX {
188 let (quo, rem) = x.div_rem(&p);
189 if !rem.is_zero() {
190 break;
191 }
192 x = quo;
193
194 primes[i] += 1;
195 if x.is_one() {
196 break 'outer;
197 }
198 }
199 }
200
201 let remainder = if x.is_one() && count2 == 0 {
202 None
203 } else {
204 Some(x << count2)
205 };
206 Self { primes, remainder }
207 }
208
209 fn decompose_known_factors(
210 mut primes: [u8; NUM_PRIMES],
211 factor_indices: impl Iterator<Item = (u16, u16)>,
212 ) -> Self {
213 const {
214 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
215 }
216
217 let mut remainder = 1_usize;
218 for (index, count) in factor_indices {
219 let index = index as usize;
220 if index < NUM_PRIMES {
221 primes[index] += count as u8;
222 } else {
223 let p = ODD_PRIMES[index - 1] as usize;
224 for _ in 0..count {
225 remainder *= p;
226 }
227 }
228 }
229
230 let remainder = if remainder == 1 {
231 None
232 } else {
233 Some(remainder.into())
234 };
235 Self { primes, remainder }
236 }
237
238 fn decompose_u8(mut x: u8) -> Self {
239 let mut primes = [0; NUM_PRIMES];
240
241 let count2 = x.trailing_zeros();
242 if count2 != 0 {
243 x >>= count2;
244 primes[0] = count2 as u8;
245 }
246
247 Self::decompose_known_factors(primes, known_odd_prime_factor_indices(x.into()).unwrap())
249 }
250
251 fn decompose_u16(mut x: u16) -> Self {
252 const {
253 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
254 }
255
256 let mut primes = [0; NUM_PRIMES];
257
258 let count2 = x.trailing_zeros();
259 if count2 != 0 {
260 x >>= count2;
261 primes[0] = count2 as u8;
262 }
263
264 'outer: for i in 1..NUM_PRIMES {
265 let p = ODD_PRIMES[i - 1];
266 let divider = OddDivider {
267 divisor: p,
268 multiplier: ODD_PRIME_DIVIDERS_U16[i - 1],
269 shift: p.ilog2(),
270 };
271 while primes[i] != u8::MAX {
272 if let Some(iter) = known_odd_prime_factor_indices(x.into()) {
274 return Self::decompose_known_factors(primes, iter);
275 }
276
277 let (quo, rem) = divider.div_rem(x);
278 if rem != 0 {
279 break;
280 }
281 x = quo;
282
283 primes[i] += 1;
284 if x == 1 {
285 break 'outer;
286 }
287 }
288 }
289
290 let remainder = if x == 1 { None } else { Some(x.into()) };
291 Self { primes, remainder }
292 }
293
294 fn decompose_u32(mut x: u32) -> Self {
295 const {
296 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
297 }
298
299 let mut primes = [0; NUM_PRIMES];
300
301 let count2 = x.trailing_zeros();
302 if count2 != 0 {
303 x >>= count2;
304 primes[0] = count2 as u8;
305 }
306
307 'outer: for i in 1..NUM_PRIMES {
308 let p = ODD_PRIMES[i - 1] as u32;
309 let divider = OddDivider {
310 divisor: p,
311 multiplier: ODD_PRIME_DIVIDERS_U32[i - 1],
312 shift: p.ilog2(),
313 };
314 while primes[i] != u8::MAX {
315 if let Ok(xx) = x.try_into()
317 && let Some(iter) = known_odd_prime_factor_indices(xx)
318 {
319 return Self::decompose_known_factors(primes, iter);
320 }
321
322 let (quo, rem) = divider.div_rem(x);
323 if rem != 0 {
324 break;
325 }
326 x = quo;
327
328 primes[i] += 1;
329 if x == 1 {
330 break 'outer;
331 }
332 }
333 }
334
335 let remainder = if x == 1 { None } else { Some(x.into()) };
336 Self { primes, remainder }
337 }
338
339 fn decompose_u64(mut x: u64) -> Self {
340 const {
341 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
342 }
343
344 let mut primes = [0; NUM_PRIMES];
345
346 let count2 = x.trailing_zeros();
347 if count2 != 0 {
348 x >>= count2;
349 primes[0] = count2 as u8;
350 }
351
352 'outer: for i in 1..NUM_PRIMES {
353 let p = ODD_PRIMES[i - 1] as u64;
354 let divider = OddDivider {
355 divisor: p,
356 multiplier: ODD_PRIME_DIVIDERS_U64[i - 1],
357 shift: p.ilog2(),
358 };
359 while primes[i] != u8::MAX {
360 if let Ok(xx) = x.try_into()
362 && let Some(iter) = known_odd_prime_factor_indices(xx)
363 {
364 return Self::decompose_known_factors(primes, iter);
365 }
366
367 let (quo, rem) = divider.div_rem(x);
368 if rem != 0 {
369 break;
370 }
371 x = quo;
372
373 primes[i] += 1;
374 if x == 1 {
375 break 'outer;
376 }
377 }
378 }
379
380 let remainder = if x == 1 { None } else { Some(x.into()) };
381 Self { primes, remainder }
382 }
383
384 fn decompose_u128(mut x: u128) -> Self {
385 const {
386 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
387 }
388
389 let mut primes = [0; NUM_PRIMES];
390
391 let count2 = x.trailing_zeros();
392 if count2 != 0 {
393 x >>= count2;
394 primes[0] = count2 as u8;
395 }
396
397 'outer: for i in 1..NUM_PRIMES {
398 let p = ODD_PRIMES[i - 1] as u128;
399 while primes[i] != u8::MAX {
400 if let Ok(xx) = x.try_into()
402 && let Some(iter) = known_odd_prime_factor_indices(xx)
403 {
404 return Self::decompose_known_factors(primes, iter);
405 }
406
407 if !x.is_multiple_of(p) {
408 break;
409 }
410 x /= p;
411
412 primes[i] += 1;
413 if x == 1 {
414 break 'outer;
415 }
416 }
417 }
418
419 let remainder = if x == 1 { None } else { Some(x.into()) };
420 Self { primes, remainder }
421 }
422
423 fn decompose_usize(mut x: usize) -> Self {
424 const {
425 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
426 }
427
428 let mut primes = [0; NUM_PRIMES];
429
430 let count2 = x.trailing_zeros();
431 if count2 != 0 {
432 x >>= count2;
433 primes[0] = count2 as u8;
434 }
435
436 'outer: for i in 1..NUM_PRIMES {
437 let p = ODD_PRIMES[i - 1] as usize;
438 while primes[i] != u8::MAX {
439 if let Some(iter) = known_odd_prime_factor_indices(x) {
441 return Self::decompose_known_factors(primes, iter);
442 }
443
444 if !x.is_multiple_of(p) {
445 break;
446 }
447 x /= p;
448
449 primes[i] += 1;
450 if x == 1 {
451 break 'outer;
452 }
453 }
454 }
455
456 let remainder = if x == 1 { None } else { Some(x.into()) };
457 Self { primes, remainder }
458 }
459
460 fn decompose_mask(
462 remainder: &mut Option<BigUint>,
463 primes: &mut [u8; NUM_PRIMES],
464 mask: [bool; NUM_PRIMES],
465 ) {
466 const {
467 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
468 }
469
470 let x: &mut BigUint = match remainder {
471 None => return,
472 Some(x) => x,
473 };
474
475 'outer: for i in 0..NUM_PRIMES {
476 let p = if i == 0 { 2 } else { ODD_PRIMES[i - 1] };
477 if !mask[i] || primes[i] == u8::MAX {
478 continue;
479 }
480 let p = BigUint::from(p);
481 while primes[i] != u8::MAX {
482 let (quo, rem) = x.div_rem(&p);
483 if !rem.is_zero() {
484 break;
485 }
486 *x = quo;
487
488 primes[i] += 1;
489 if x.is_one() {
490 break 'outer;
491 }
492 }
493 }
494
495 if x.is_one() {
496 *remainder = None;
497 }
498 }
499
500 fn accum_pow(numerator: &mut BigInt, tmp: &mut usize, prime: usize, exponent: u8) {
503 for _ in 0..exponent {
504 match tmp.checked_mul(prime) {
505 Some(prod) => *tmp = prod,
506 None => {
507 *numerator *= *tmp;
508 *tmp = prime;
509 }
510 }
511 }
512 }
513
514 fn pow_primes(
515 this: &[u8; NUM_PRIMES],
516 exponent: u32,
517 remainder: &mut Option<BigUint>,
518 ) -> [u8; NUM_PRIMES] {
519 const {
520 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
521 }
522
523 let mut primes = [0; NUM_PRIMES];
524 for i in 0..NUM_PRIMES {
525 let p = if i == 0 { 2 } else { ODD_PRIMES[i - 1] };
526 let product = (this[i] as u32).strict_mul(exponent);
527 if product <= u8::MAX as u32 {
528 primes[i] = product as u8;
529 } else {
530 primes[i] = u8::MAX;
531 let factor = BigUint::from(p).pow(product - u8::MAX as u32);
532 match remainder {
533 None => *remainder = Some(factor),
534 Some(r) => *r *= factor,
535 };
536 }
537 }
538 primes
539 }
540
541 fn mul_primes(
542 lhs: &[u8; NUM_PRIMES],
543 rhs: &[u8; NUM_PRIMES],
544 remainder: &mut Option<BigUint>,
545 ) -> [u8; NUM_PRIMES] {
546 const {
547 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
548 }
549
550 let mut primes = [0; NUM_PRIMES];
551 for i in 0..NUM_PRIMES {
552 let p = if i == 0 { 2 } else { ODD_PRIMES[i - 1] };
553 let sum = lhs[i] as u32 + rhs[i] as u32;
554 if sum <= u8::MAX as u32 {
555 primes[i] = sum as u8;
556 } else {
557 primes[i] = u8::MAX;
558 let factor = BigUint::from(p).pow(sum - u8::MAX as u32);
559 match remainder {
560 None => *remainder = Some(factor),
561 Some(r) => *r *= factor,
562 };
563 }
564 }
565 primes
566 }
567
568 fn div_primes(
569 num: &[u8; NUM_PRIMES],
570 denom: &[u8; NUM_PRIMES],
571 mut remainder: Option<BigUint>,
572 ) -> (Self, [bool; NUM_PRIMES]) {
573 const {
574 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
575 }
576
577 let mut primes = [0; NUM_PRIMES];
578 let mut mask = [false; NUM_PRIMES];
579 for i in 0..NUM_PRIMES {
580 let p = if i == 0 { 2 } else { ODD_PRIMES[i - 1] };
581 mask[i] = num[i] == u8::MAX;
582 if num[i] >= denom[i] {
583 primes[i] = num[i] - denom[i];
584 } else {
585 primes[i] = 0;
586 let factor = BigUint::from(p).pow(denom[i] as u32 - num[i] as u32);
587 remainder = match remainder {
588 None => Some(factor),
589 Some(r) => Some(r * factor),
590 };
591 }
592 }
593 (Self { primes, remainder }, mask)
594 }
595}
596
597impl<const NUM_PRIMES: usize> From<u8> for DenomArray<NUM_PRIMES> {
598 fn from(value: u8) -> Self {
599 if value == 0 {
600 panic!("Attempted to create a denominator of zero");
601 }
602 Self::decompose_u8(value)
603 }
604}
605
606impl<const NUM_PRIMES: usize> From<u16> for DenomArray<NUM_PRIMES> {
607 fn from(value: u16) -> Self {
608 if value == 0 {
609 panic!("Attempted to create a denominator of zero");
610 }
611 Self::decompose_u16(value)
612 }
613}
614
615impl<const NUM_PRIMES: usize> From<u32> for DenomArray<NUM_PRIMES> {
616 fn from(value: u32) -> Self {
617 if value == 0 {
618 panic!("Attempted to create a denominator of zero");
619 }
620 Self::decompose_u32(value)
621 }
622}
623
624impl<const NUM_PRIMES: usize> From<u64> for DenomArray<NUM_PRIMES> {
625 fn from(value: u64) -> Self {
626 if value == 0 {
627 panic!("Attempted to create a denominator of zero");
628 }
629 Self::decompose_u64(value)
630 }
631}
632
633impl<const NUM_PRIMES: usize> From<u128> for DenomArray<NUM_PRIMES> {
634 fn from(value: u128) -> Self {
635 if value == 0 {
636 panic!("Attempted to create a denominator of zero");
637 }
638 Self::decompose_u128(value)
639 }
640}
641
642impl<const NUM_PRIMES: usize> From<usize> for DenomArray<NUM_PRIMES> {
643 fn from(value: usize) -> Self {
644 if value == 0 {
645 panic!("Attempted to create a denominator of zero");
646 }
647 Self::decompose_usize(value)
648 }
649}
650
651impl<const NUM_PRIMES: usize> From<BigUint> for DenomArray<NUM_PRIMES> {
652 fn from(value: BigUint) -> Self {
653 if value.is_zero() {
654 panic!("Attempted to create a denominator of zero");
655 }
656 Self::decompose(value)
657 }
658}
659
660impl<const NUM_PRIMES: usize> From<&BigUint> for DenomArray<NUM_PRIMES> {
661 fn from(value: &BigUint) -> Self {
662 if value.is_zero() {
663 panic!("Attempted to create a denominator of zero");
664 }
665 Self::decompose(value.clone())
666 }
667}
668
669impl<const NUM_PRIMES: usize> From<DenomArray<NUM_PRIMES>> for BigUint {
670 fn from(value: DenomArray<NUM_PRIMES>) -> BigUint {
671 const {
672 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
673 }
674
675 let mut result = match value.remainder {
676 Some(x) => x,
677 None => BigUint::ONE,
678 };
679 let mut tmp = 1_usize;
680 for (i, &count) in value.primes.iter().enumerate() {
681 let p = if i == 0 {
682 2
683 } else {
684 ODD_PRIMES[i - 1] as usize
685 };
686 for _ in 0..count {
687 match tmp.checked_mul(p) {
688 Some(prod) => tmp = prod,
689 None => {
690 result *= tmp;
691 tmp = p;
692 }
693 }
694 }
695 }
696 result * tmp
697 }
698}
699
700impl<const NUM_PRIMES: usize> From<&DenomArray<NUM_PRIMES>> for BigUint {
701 fn from(value: &DenomArray<NUM_PRIMES>) -> BigUint {
702 const {
703 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
704 }
705
706 let mut result = match &value.remainder {
707 Some(x) => x.clone(),
708 None => BigUint::ONE,
709 };
710 let mut tmp = 1_usize;
711 for (i, &count) in value.primes.iter().enumerate() {
712 let p = if i == 0 {
713 2
714 } else {
715 ODD_PRIMES[i - 1] as usize
716 };
717 for _ in 0..count {
718 match tmp.checked_mul(p) {
719 Some(prod) => tmp = prod,
720 None => {
721 result *= tmp;
722 tmp = p;
723 }
724 }
725 }
726 }
727 result * tmp
728 }
729}
730
731impl<const NUM_PRIMES: usize> One for DenomArray<NUM_PRIMES> {
732 fn one() -> Self {
733 Self::ONE
734 }
735}
736
737impl<const NUM_PRIMES: usize> num_traits::Pow<u32> for DenomArray<NUM_PRIMES> {
738 type Output = Self;
739
740 fn pow(mut self, rhs: u32) -> Self {
741 if rhs == 0 {
742 return Self::ONE;
743 }
744 let primes = Self::pow_primes(&self.primes, rhs, &mut self.remainder);
745 Self {
746 primes,
747 remainder: self.remainder,
748 }
749 }
750}
751
752impl<const NUM_PRIMES: usize> num_traits::Pow<u32> for &DenomArray<NUM_PRIMES> {
753 type Output = DenomArray<NUM_PRIMES>;
754
755 fn pow(self, rhs: u32) -> DenomArray<NUM_PRIMES> {
756 if rhs == 0 {
757 return DenomArray::ONE;
758 }
759 let mut remainder = self.remainder.clone();
760 let primes = DenomArray::pow_primes(&self.primes, rhs, &mut remainder);
761 DenomArray { primes, remainder }
762 }
763}
764
765impl<const NUM_PRIMES: usize> Mul for DenomArray<NUM_PRIMES> {
766 type Output = Self;
767
768 fn mul(self, rhs: Self) -> Self {
769 let mut remainder = match (self.remainder, rhs.remainder) {
770 (None, None) => None,
771 (None, Some(r)) => Some(r),
772 (Some(l), None) => Some(l),
773 (Some(l), Some(r)) => Some(l * r),
774 };
775 let primes = Self::mul_primes(&self.primes, &rhs.primes, &mut remainder);
776 Self { primes, remainder }
777 }
778}
779
780impl<const NUM_PRIMES: usize> Mul<&Self> for DenomArray<NUM_PRIMES> {
781 type Output = Self;
782
783 fn mul(self, rhs: &Self) -> Self {
784 let mut remainder = match (self.remainder, &rhs.remainder) {
785 (None, None) => None,
786 (None, Some(r)) => Some(r.clone()),
787 (Some(l), None) => Some(l),
788 (Some(l), Some(r)) => Some(l * r),
789 };
790 let primes = Self::mul_primes(&self.primes, &rhs.primes, &mut remainder);
791 Self { primes, remainder }
792 }
793}
794
795impl<const NUM_PRIMES: usize> Mul for &DenomArray<NUM_PRIMES> {
796 type Output = DenomArray<NUM_PRIMES>;
797
798 fn mul(self, rhs: Self) -> DenomArray<NUM_PRIMES> {
799 let mut remainder = match (&self.remainder, &rhs.remainder) {
800 (None, None) => None,
801 (None, Some(r)) => Some(r.clone()),
802 (Some(l), None) => Some(l.clone()),
803 (Some(l), Some(r)) => Some(l * r),
804 };
805 let primes = DenomArray::mul_primes(&self.primes, &rhs.primes, &mut remainder);
806 DenomArray { primes, remainder }
807 }
808}
809
810impl<const NUM_PRIMES: usize> Mul<DenomArray<NUM_PRIMES>> for &DenomArray<NUM_PRIMES> {
811 type Output = DenomArray<NUM_PRIMES>;
812
813 fn mul(self, rhs: DenomArray<NUM_PRIMES>) -> DenomArray<NUM_PRIMES> {
814 let mut remainder = match (&self.remainder, rhs.remainder) {
815 (None, None) => None,
816 (None, Some(r)) => Some(r),
817 (Some(l), None) => Some(l.clone()),
818 (Some(l), Some(r)) => Some(l * r),
819 };
820 let primes = DenomArray::mul_primes(&self.primes, &rhs.primes, &mut remainder);
821 DenomArray { primes, remainder }
822 }
823}
824
825impl<const NUM_PRIMES: usize> MulAssign for DenomArray<NUM_PRIMES> {
826 fn mul_assign(&mut self, rhs: Self) {
827 match (&mut self.remainder, rhs.remainder) {
828 (_, None) => (),
829 (None, Some(r)) => self.remainder = Some(r),
830 (Some(l), Some(r)) => *l *= r,
831 };
832 self.primes = Self::mul_primes(&self.primes, &rhs.primes, &mut self.remainder);
833 }
834}
835
836impl<const NUM_PRIMES: usize> MulAssign<&Self> for DenomArray<NUM_PRIMES> {
837 fn mul_assign(&mut self, rhs: &Self) {
838 match (&mut self.remainder, &rhs.remainder) {
839 (_, None) => (),
840 (None, Some(r)) => self.remainder = Some(r.clone()),
841 (Some(l), Some(r)) => *l *= r,
842 };
843 self.primes = Self::mul_primes(&self.primes, &rhs.primes, &mut self.remainder);
844 }
845}
846
847impl<const NUM_PRIMES: usize> Div for DenomArray<NUM_PRIMES> {
848 type Output = Self;
849
850 fn div(self, rhs: Self) -> Self {
854 let (
855 Self {
856 mut primes,
857 remainder: rhs_remainder,
858 },
859 mask,
860 ) = Self::div_primes(&self.primes, &rhs.primes, rhs.remainder);
861
862 let mut remainder = match (self.remainder, rhs_remainder) {
863 (None, None) => None,
864 (None, Some(r)) => {
865 if !r.is_one() {
866 panic!("Attempted to divide a denominator by a non-divisor");
867 }
868 None
869 }
870 (Some(l), None) => Some(l),
871 (Some(l), Some(r)) => {
872 let (quo, rem) = l.div_rem(&r);
873 if !rem.is_zero() {
874 panic!("Attempted to divide a denominator by a non-divisor");
875 }
876 if quo.is_one() { None } else { Some(quo) }
877 }
878 };
879
880 Self::decompose_mask(&mut remainder, &mut primes, mask);
881 Self { primes, remainder }
882 }
883}
884
885impl<const NUM_PRIMES: usize> Div<&Self> for DenomArray<NUM_PRIMES> {
886 type Output = Self;
887
888 fn div(self, rhs: &Self) -> Self {
892 let (
893 Self {
894 mut primes,
895 remainder: rhs_remainder,
896 },
897 mask,
898 ) = Self::div_primes(&self.primes, &rhs.primes, rhs.remainder.clone());
899
900 let mut remainder = match (self.remainder, rhs_remainder) {
901 (None, None) => None,
902 (None, Some(r)) => {
903 if !r.is_one() {
904 panic!("Attempted to divide a denominator by a non-divisor");
905 }
906 None
907 }
908 (Some(l), None) => Some(l),
909 (Some(l), Some(r)) => {
910 let (quo, rem) = l.div_rem(&r);
911 if !rem.is_zero() {
912 panic!("Attempted to divide a denominator by a non-divisor");
913 }
914 if quo.is_one() { None } else { Some(quo) }
915 }
916 };
917
918 Self::decompose_mask(&mut remainder, &mut primes, mask);
919 Self { primes, remainder }
920 }
921}
922
923impl<const NUM_PRIMES: usize> Div for &DenomArray<NUM_PRIMES> {
924 type Output = DenomArray<NUM_PRIMES>;
925
926 fn div(self, rhs: Self) -> DenomArray<NUM_PRIMES> {
930 let (
931 DenomArray {
932 mut primes,
933 remainder: rhs_remainder,
934 },
935 mask,
936 ) = DenomArray::div_primes(&self.primes, &rhs.primes, rhs.remainder.clone());
937
938 let mut remainder = match (&self.remainder, rhs_remainder) {
939 (None, None) => None,
940 (None, Some(r)) => {
941 if !r.is_one() {
942 panic!("Attempted to divide a denominator by a non-divisor");
943 }
944 None
945 }
946 (Some(l), None) => Some(l.clone()),
947 (Some(l), Some(r)) => {
948 let (quo, rem) = l.div_rem(&r);
949 if !rem.is_zero() {
950 panic!("Attempted to divide a denominator by a non-divisor");
951 }
952 if quo.is_one() { None } else { Some(quo) }
953 }
954 };
955
956 DenomArray::decompose_mask(&mut remainder, &mut primes, mask);
957 DenomArray { primes, remainder }
958 }
959}
960
961impl<const NUM_PRIMES: usize> Div<DenomArray<NUM_PRIMES>> for &DenomArray<NUM_PRIMES> {
962 type Output = DenomArray<NUM_PRIMES>;
963
964 fn div(self, rhs: DenomArray<NUM_PRIMES>) -> DenomArray<NUM_PRIMES> {
968 let (
969 DenomArray {
970 mut primes,
971 remainder: rhs_remainder,
972 },
973 mask,
974 ) = DenomArray::div_primes(&self.primes, &rhs.primes, rhs.remainder);
975
976 let mut remainder = match (&self.remainder, rhs_remainder) {
977 (None, None) => None,
978 (None, Some(r)) => {
979 if !r.is_one() {
980 panic!("Attempted to divide a denominator by a non-divisor");
981 }
982 None
983 }
984 (Some(l), None) => Some(l.clone()),
985 (Some(l), Some(r)) => {
986 let (quo, rem) = l.div_rem(&r);
987 if !rem.is_zero() {
988 panic!("Attempted to divide a denominator by a non-divisor");
989 }
990 if quo.is_one() { None } else { Some(quo) }
991 }
992 };
993
994 DenomArray::decompose_mask(&mut remainder, &mut primes, mask);
995 DenomArray { primes, remainder }
996 }
997}
998
999impl<const NUM_PRIMES: usize> DivAssign for DenomArray<NUM_PRIMES> {
1000 fn div_assign(&mut self, rhs: Self) {
1004 let (
1005 Self {
1006 primes,
1007 remainder: rhs_remainder,
1008 },
1009 mask,
1010 ) = Self::div_primes(&self.primes, &rhs.primes, rhs.remainder);
1011 self.primes = primes;
1012
1013 match (&mut self.remainder, rhs_remainder) {
1014 (_, None) => (),
1015 (None, Some(r)) => {
1016 if !r.is_one() {
1017 panic!("Attempted to divide a denominator by a non-divisor");
1018 }
1019 }
1020 (Some(l), Some(r)) => {
1021 let (quo, rem) = l.div_rem(&r);
1022 if !rem.is_zero() {
1023 panic!("Attempted to divide a denominator by a non-divisor");
1024 }
1025 if quo.is_one() {
1026 self.remainder = None
1027 } else {
1028 *l = quo;
1029 }
1030 }
1031 };
1032
1033 Self::decompose_mask(&mut self.remainder, &mut self.primes, mask);
1034 }
1035}
1036
1037impl<const NUM_PRIMES: usize> DivAssign<&Self> for DenomArray<NUM_PRIMES> {
1038 fn div_assign(&mut self, rhs: &Self) {
1042 let (
1043 Self {
1044 primes,
1045 remainder: rhs_remainder,
1046 },
1047 mask,
1048 ) = Self::div_primes(&self.primes, &rhs.primes, rhs.remainder.clone());
1049 self.primes = primes;
1050
1051 match (&mut self.remainder, rhs_remainder) {
1052 (_, None) => (),
1053 (None, Some(r)) => {
1054 if !r.is_one() {
1055 panic!("Attempted to divide a denominator by a non-divisor");
1056 }
1057 }
1058 (Some(l), Some(r)) => {
1059 let (quo, rem) = l.div_rem(&r);
1060 if !rem.is_zero() {
1061 panic!("Attempted to divide a denominator by a non-divisor");
1062 }
1063 if quo.is_one() {
1064 self.remainder = None
1065 } else {
1066 *l = quo;
1067 }
1068 }
1069 };
1070
1071 Self::decompose_mask(&mut self.remainder, &mut self.primes, mask);
1072 }
1073}
1074
1075impl<const NUM_PRIMES: usize> Mul<DenomArray<NUM_PRIMES>> for BigInt {
1076 type Output = Self;
1077
1078 fn mul(mut self, rhs: DenomArray<NUM_PRIMES>) -> Self {
1079 const {
1080 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1081 }
1082
1083 let mut tmp = 1_usize;
1084 for i in 0..NUM_PRIMES {
1085 let p = if i == 0 {
1086 2
1087 } else {
1088 ODD_PRIMES[i - 1] as usize
1089 };
1090 let count = rhs.primes[i];
1091 if count != 0 {
1092 DenomArray::<NUM_PRIMES>::accum_pow(&mut self, &mut tmp, p, count);
1093 }
1094 }
1095
1096 self *= tmp;
1097 if let Some(remainder) = rhs.remainder {
1098 self *= BigInt::from_biguint(Sign::Plus, remainder);
1099 }
1100 self
1101 }
1102}
1103
1104impl<const NUM_PRIMES: usize> Mul<&DenomArray<NUM_PRIMES>> for BigInt {
1105 type Output = Self;
1106
1107 fn mul(mut self, rhs: &DenomArray<NUM_PRIMES>) -> Self {
1108 const {
1109 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1110 }
1111
1112 let mut tmp = 1_usize;
1113 for i in 0..NUM_PRIMES {
1114 let p = if i == 0 {
1115 2
1116 } else {
1117 ODD_PRIMES[i - 1] as usize
1118 };
1119 let count = rhs.primes[i];
1120 if count != 0 {
1121 DenomArray::<NUM_PRIMES>::accum_pow(&mut self, &mut tmp, p, count);
1122 }
1123 }
1124
1125 self *= tmp;
1126 if let Some(remainder) = &rhs.remainder {
1127 self *= BigInt::from_biguint(Sign::Plus, remainder.clone());
1128 }
1129 self
1130 }
1131}
1132
1133impl<const NUM_PRIMES: usize> Mul<DenomArray<NUM_PRIMES>> for &BigInt {
1134 type Output = BigInt;
1135
1136 fn mul(self, rhs: DenomArray<NUM_PRIMES>) -> BigInt {
1137 const {
1138 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1139 }
1140
1141 let mut this = self.clone();
1142 let mut tmp = 1_usize;
1143 for i in 0..NUM_PRIMES {
1144 let p = if i == 0 {
1145 2
1146 } else {
1147 ODD_PRIMES[i - 1] as usize
1148 };
1149 let count = rhs.primes[i];
1150 if count != 0 {
1151 DenomArray::<NUM_PRIMES>::accum_pow(&mut this, &mut tmp, p, count);
1152 }
1153 }
1154
1155 this *= tmp;
1156 if let Some(remainder) = rhs.remainder {
1157 this *= BigInt::from_biguint(Sign::Plus, remainder);
1158 }
1159 this
1160 }
1161}
1162
1163impl<const NUM_PRIMES: usize> Mul<&DenomArray<NUM_PRIMES>> for &BigInt {
1164 type Output = BigInt;
1165
1166 fn mul(self, rhs: &DenomArray<NUM_PRIMES>) -> BigInt {
1167 const {
1168 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1169 }
1170
1171 let mut this = self.clone();
1172 let mut tmp = 1_usize;
1173 for i in 0..NUM_PRIMES {
1174 let p = if i == 0 {
1175 2
1176 } else {
1177 ODD_PRIMES[i - 1] as usize
1178 };
1179 let count = rhs.primes[i];
1180 if count != 0 {
1181 DenomArray::<NUM_PRIMES>::accum_pow(&mut this, &mut tmp, p, count);
1182 }
1183 }
1184
1185 this *= tmp;
1186 if let Some(remainder) = &rhs.remainder {
1187 this *= BigInt::from_biguint(Sign::Plus, remainder.clone());
1188 }
1189 this
1190 }
1191}
1192
1193impl<const NUM_PRIMES: usize> Mul<BigInt> for DenomArray<NUM_PRIMES> {
1194 type Output = BigInt;
1195
1196 fn mul(self, mut rhs: BigInt) -> BigInt {
1197 const {
1198 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1199 }
1200
1201 let mut tmp = 1_usize;
1202 for i in 0..NUM_PRIMES {
1203 let p = if i == 0 {
1204 2
1205 } else {
1206 ODD_PRIMES[i - 1] as usize
1207 };
1208 let count = self.primes[i];
1209 if count != 0 {
1210 Self::accum_pow(&mut rhs, &mut tmp, p, count);
1211 }
1212 }
1213
1214 rhs *= tmp;
1215 if let Some(remainder) = self.remainder {
1216 rhs *= BigInt::from_biguint(Sign::Plus, remainder);
1217 }
1218 rhs
1219 }
1220}
1221
1222impl<const NUM_PRIMES: usize> Mul<&BigInt> for DenomArray<NUM_PRIMES> {
1223 type Output = BigInt;
1224
1225 fn mul(self, rhs: &BigInt) -> BigInt {
1226 const {
1227 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1228 }
1229
1230 let mut rhs = rhs.clone();
1231 let mut tmp = 1_usize;
1232 for i in 0..NUM_PRIMES {
1233 let p = if i == 0 {
1234 2
1235 } else {
1236 ODD_PRIMES[i - 1] as usize
1237 };
1238 let count = self.primes[i];
1239 if count != 0 {
1240 Self::accum_pow(&mut rhs, &mut tmp, p, count);
1241 }
1242 }
1243
1244 rhs *= tmp;
1245 if let Some(remainder) = self.remainder {
1246 rhs *= BigInt::from_biguint(Sign::Plus, remainder);
1247 }
1248 rhs
1249 }
1250}
1251
1252impl<const NUM_PRIMES: usize> Mul<BigInt> for &DenomArray<NUM_PRIMES> {
1253 type Output = BigInt;
1254
1255 fn mul(self, mut rhs: BigInt) -> BigInt {
1256 const {
1257 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1258 }
1259
1260 let mut tmp = 1_usize;
1261 for i in 0..NUM_PRIMES {
1262 let p = if i == 0 {
1263 2
1264 } else {
1265 ODD_PRIMES[i - 1] as usize
1266 };
1267 let count = self.primes[i];
1268 if count != 0 {
1269 DenomArray::<NUM_PRIMES>::accum_pow(&mut rhs, &mut tmp, p, count);
1270 }
1271 }
1272
1273 rhs *= tmp;
1274 if let Some(remainder) = &self.remainder {
1275 rhs *= BigInt::from_biguint(Sign::Plus, remainder.clone());
1276 }
1277 rhs
1278 }
1279}
1280
1281impl<const NUM_PRIMES: usize> Mul<&BigInt> for &DenomArray<NUM_PRIMES> {
1282 type Output = BigInt;
1283
1284 fn mul(self, rhs: &BigInt) -> BigInt {
1285 const {
1286 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1287 }
1288
1289 let mut rhs = rhs.clone();
1290 let mut tmp = 1_usize;
1291 for i in 0..NUM_PRIMES {
1292 let p = if i == 0 {
1293 2
1294 } else {
1295 ODD_PRIMES[i - 1] as usize
1296 };
1297 let count = self.primes[i];
1298 if count != 0 {
1299 DenomArray::<NUM_PRIMES>::accum_pow(&mut rhs, &mut tmp, p, count);
1300 }
1301 }
1302
1303 rhs *= tmp;
1304 if let Some(remainder) = &self.remainder {
1305 rhs *= BigInt::from_biguint(Sign::Plus, remainder.clone());
1306 }
1307 rhs
1308 }
1309}
1310
1311impl<const NUM_PRIMES: usize> MulAssign<DenomArray<NUM_PRIMES>> for BigInt {
1312 fn mul_assign(&mut self, rhs: DenomArray<NUM_PRIMES>) {
1313 const {
1314 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1315 }
1316
1317 let mut tmp = 1_usize;
1318 for i in 0..NUM_PRIMES {
1319 let p = if i == 0 {
1320 2
1321 } else {
1322 ODD_PRIMES[i - 1] as usize
1323 };
1324 let count = rhs.primes[i];
1325 if count != 0 {
1326 DenomArray::<NUM_PRIMES>::accum_pow(self, &mut tmp, p, count);
1327 }
1328 }
1329
1330 *self *= tmp;
1331 if let Some(remainder) = rhs.remainder {
1332 *self *= BigInt::from_biguint(Sign::Plus, remainder);
1333 }
1334 }
1335}
1336
1337impl<const NUM_PRIMES: usize> MulAssign<&DenomArray<NUM_PRIMES>> for BigInt {
1338 fn mul_assign(&mut self, rhs: &DenomArray<NUM_PRIMES>) {
1339 const {
1340 assert!(NUM_PRIMES <= ODD_PRIMES.len() + 1);
1341 }
1342
1343 let mut tmp = 1_usize;
1344 for i in 0..NUM_PRIMES {
1345 let p = if i == 0 {
1346 2
1347 } else {
1348 ODD_PRIMES[i - 1] as usize
1349 };
1350 let count = rhs.primes[i];
1351 if count != 0 {
1352 DenomArray::<NUM_PRIMES>::accum_pow(self, &mut tmp, p, count);
1353 }
1354 }
1355
1356 *self *= tmp;
1357 if let Some(remainder) = &rhs.remainder {
1358 *self *= BigInt::from_biguint(Sign::Plus, remainder.clone());
1359 }
1360 }
1361}
1362
1363#[cfg(test)]
1364mod tests {
1365 use super::*;
1366
1367 macro_rules! tests {
1368 (
1369 $mod:ident,
1370 $num_primes:expr,
1371 $( $case:ident ,)*
1372 ) => {
1373 mod $mod {
1374 $(
1375 #[test]
1376 fn $case() {
1377 $crate::denom_array::tests::$case::<$num_primes>();
1378 }
1379 )*
1380 }
1381 };
1382 }
1383
1384 macro_rules! all_tests {
1385 (
1386 $mod:ident,
1387 $num_primes:expr
1388 ) => {
1389 tests!(
1390 $mod,
1391 $num_primes,
1392 test_decompose_is_correct,
1393 test_decompose_prime_powers,
1394 test_mul_prime_powers,
1395 test_div_prime_powers,
1396 test_to_biguint,
1397 test_product,
1398 test_normalize,
1399 test_gcd_reduce,
1400 );
1401 };
1402 }
1403
1404 all_tests!(denom24, 24);
1405 all_tests!(denom6542, 6542);
1406
1407 fn test_decompose_is_correct<const NUM_PRIMES: usize>() {
1408 for i in 1_usize..=1000 {
1409 let bigi = BigUint::from(i);
1410 let x = DenomArray::<NUM_PRIMES>::from(&bigi);
1411 let mut recomposed = x.remainder.unwrap_or_else(BigUint::one);
1412 for i in 0..NUM_PRIMES {
1413 let prime = if i == 0 { 2 } else { ODD_PRIMES[i - 1] };
1414 for _ in 0..x.primes[i] {
1415 recomposed *= prime;
1416 }
1417 }
1418 assert_eq!(recomposed, bigi);
1419 }
1420 }
1421
1422 #[test]
1423 fn test_decompose_known_values() {
1424 assert_eq!(
1425 DenomArray24::from(BigUint::from(128_usize)),
1426 DenomArray24 {
1427 primes: [
1428 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1429 ],
1430 remainder: None,
1431 }
1432 );
1433 assert_eq!(
1434 DenomArray24::from(BigUint::from(89_usize)),
1435 DenomArray24 {
1436 primes: [
1437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
1438 ],
1439 remainder: None,
1440 }
1441 );
1442 assert_eq!(
1443 DenomArray24::from(BigUint::from(97_usize)),
1444 DenomArray24 {
1445 primes: [
1446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1447 ],
1448 remainder: Some(BigUint::from(97_usize)),
1449 }
1450 );
1451 assert_eq!(
1452 DenomArray24::from(BigUint::from(97000_usize)),
1453 DenomArray24 {
1454 primes: [
1455 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1456 ],
1457 remainder: Some(BigUint::from(97_usize)),
1458 }
1459 );
1460 }
1461
1462 fn test_decompose_prime_powers<const NUM_PRIMES: usize>() {
1463 for i in 0..24 {
1464 let p = if i == 0 { 2 } else { ODD_PRIMES[i - 1] };
1465 let p = BigUint::from(p);
1466 for power in 1..=255 {
1467 assert_eq!(
1468 DenomArray::<NUM_PRIMES>::from(p.pow(power as u32)),
1469 DenomArray {
1470 primes: std::array::from_fn(|j| if i == j { power } else { 0 }),
1471 remainder: None,
1472 }
1473 );
1474 }
1475 for power in 1..=64 {
1476 assert_eq!(
1477 DenomArray::<NUM_PRIMES>::from(p.pow(255 + power)),
1478 DenomArray {
1479 primes: std::array::from_fn(|j| if i == j { 255 } else { 0 }),
1480 remainder: Some(p.pow(power)),
1481 }
1482 );
1483 }
1484 }
1485 }
1486
1487 fn test_mul_prime_powers<const NUM_PRIMES: usize>() {
1488 let p = BigUint::from(2u32);
1489 for a in 1..=256 {
1490 let denom_a = DenomArray::<NUM_PRIMES>::from(p.pow(a));
1491 for b in 1..=256 {
1492 let denom_b = DenomArray::<NUM_PRIMES>::from(p.pow(b));
1493 let denom_ab = DenomArray::<NUM_PRIMES>::from(p.pow(a + b));
1494 assert_eq!(&denom_a * denom_b, denom_ab);
1495 }
1496 }
1497 }
1498
1499 fn test_div_prime_powers<const NUM_PRIMES: usize>() {
1500 let p = BigUint::from(2u32);
1501 for a in 1..=256 {
1502 let denom_a = DenomArray::<NUM_PRIMES>::from(p.pow(a));
1503 for b in 1..=256 {
1504 let denom_b = DenomArray::<NUM_PRIMES>::from(p.pow(b));
1505 let denom_ab = DenomArray::<NUM_PRIMES>::from(p.pow(a + b));
1506 assert_eq!(denom_ab / denom_b, denom_a);
1507 }
1508 }
1509 }
1510
1511 fn test_to_biguint<const NUM_PRIMES: usize>() {
1512 for i in 1_usize..=1000 {
1513 let bigi = BigUint::from(i);
1514 let x = DenomArray::<NUM_PRIMES>::from(&bigi);
1515 assert_eq!(x.to_biguint(), bigi);
1516 }
1517 }
1518
1519 fn test_product<const NUM_PRIMES: usize>() {
1520 let values = (100..200)
1521 .map(|i: usize| DenomArray::<NUM_PRIMES>::from(BigUint::from(i)))
1522 .collect::<Vec<_>>();
1523 for (i, x) in values.iter().enumerate().map(|(i, x)| (i + 100, x)) {
1524 for (j, y) in values.iter().enumerate().map(|(j, y)| (j + 100, y)) {
1525 let z = x * y;
1526 assert_eq!(z, DenomArray::<NUM_PRIMES>::from(BigUint::from(i * j)));
1527 for k in 0..NUM_PRIMES {
1528 assert_eq!(z.primes[k], x.primes[k] + y.primes[k]);
1529 }
1530 }
1531 }
1532 }
1533
1534 fn test_normalize<const NUM_PRIMES: usize>() {
1535 let values = (100..200)
1536 .map(|i: usize| DenomArray::<NUM_PRIMES>::from(BigUint::from(i)))
1537 .collect::<Vec<_>>();
1538 for x in &values {
1539 for y in &values {
1540 let mut xnum = BigInt::one();
1541 let mut ynum = BigInt::one();
1542 let lcm = DenomArray::<NUM_PRIMES>::normalize(&mut xnum, &mut ynum, x, y);
1543 let lcm_bigint = lcm.to_biguint();
1544 let xnum = xnum.to_biguint().unwrap();
1545 let ynum = ynum.to_biguint().unwrap();
1546
1547 assert_eq!(xnum * x.to_biguint(), lcm_bigint);
1548 assert_eq!(ynum * y.to_biguint(), lcm_bigint);
1549 for k in 0..NUM_PRIMES {
1550 assert_eq!(lcm.primes[k], std::cmp::max(x.primes[k], y.primes[k]));
1551 }
1552 }
1553 }
1554 }
1555
1556 fn test_gcd_reduce<const NUM_PRIMES: usize>() {
1557 let mut num = BigInt::from(-3 * 97);
1558 let mut denom = DenomArray::<NUM_PRIMES>::from(BigUint::from(3u32 * 5 * 97));
1559 denom.gcd_reduce(&mut num);
1560 assert_eq!(num, BigInt::from(-1));
1561 assert_eq!(denom, DenomArray::<NUM_PRIMES>::from(BigUint::from(5u32)));
1562 }
1563}