1use std::cmp::Ordering;
18use std::fmt;
19
20#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
23enum Sign {
24 Neg,
25 Zero,
26 Pos,
27}
28
29#[derive(Clone, PartialEq, Eq, Hash)]
31pub struct BigInt {
32 sign: Sign,
33 mag: Mag,
34}
35
36#[derive(Clone, PartialEq, Eq, Hash)]
44enum Mag {
45 Inline(u64),
46 Heap(Vec<u64>),
47}
48
49impl Mag {
50 fn from_vec(mut v: Vec<u64>) -> Mag {
52 while v.last() == Some(&0) {
53 v.pop();
54 }
55 match v.len() {
56 0 => Mag::Inline(0),
57 1 => Mag::Inline(v[0]),
58 _ => Mag::Heap(v),
59 }
60 }
61
62 fn limbs(&self) -> &[u64] {
64 match self {
65 Mag::Inline(0) => &[],
66 Mag::Inline(x) => std::slice::from_ref(x),
67 Mag::Heap(v) => v,
68 }
69 }
70
71 fn as_single(&self) -> Option<u64> {
74 match self {
75 Mag::Inline(x) => Some(*x),
76 Mag::Heap(_) => None,
77 }
78 }
79}
80
81fn normalize(mut mag: Vec<u64>) -> Vec<u64> {
85 while mag.last() == Some(&0) {
86 mag.pop();
87 }
88 mag
89}
90
91fn mag_cmp(a: &[u64], b: &[u64]) -> Ordering {
93 match a.len().cmp(&b.len()) {
94 Ordering::Equal => {
95 for i in (0..a.len()).rev() {
96 match a[i].cmp(&b[i]) {
97 Ordering::Equal => {}
98 other => return other,
99 }
100 }
101 Ordering::Equal
102 }
103 other => other,
104 }
105}
106
107fn mag_add(a: &[u64], b: &[u64]) -> Vec<u64> {
109 let mut out = Vec::with_capacity(a.len().max(b.len()) + 1);
110 let mut carry = 0u128;
111 for i in 0..a.len().max(b.len()) {
112 let av = *a.get(i).unwrap_or(&0) as u128;
113 let bv = *b.get(i).unwrap_or(&0) as u128;
114 let sum = av + bv + carry;
115 out.push(sum as u64);
116 carry = sum >> 64;
117 }
118 if carry != 0 {
119 out.push(carry as u64);
120 }
121 normalize(out)
122}
123
124fn mag_sub(a: &[u64], b: &[u64]) -> Vec<u64> {
126 debug_assert!(mag_cmp(a, b) != Ordering::Less, "mag_sub underflow");
127 let mut out = Vec::with_capacity(a.len());
128 let mut borrow = 0i128;
129 for i in 0..a.len() {
130 let av = a[i] as i128;
131 let bv = *b.get(i).unwrap_or(&0) as i128;
132 let mut diff = av - bv - borrow;
133 if diff < 0 {
134 diff += 1i128 << 64;
135 borrow = 1;
136 } else {
137 borrow = 0;
138 }
139 out.push(diff as u64);
140 }
141 debug_assert_eq!(borrow, 0, "mag_sub left a borrow");
142 normalize(out)
143}
144
145fn mag_mul(a: &[u64], b: &[u64]) -> Vec<u64> {
147 if a.is_empty() || b.is_empty() {
148 return Vec::new();
149 }
150 let mut out = vec![0u64; a.len() + b.len()];
151 for (i, &av) in a.iter().enumerate() {
152 let mut carry = 0u128;
153 for (j, &bv) in b.iter().enumerate() {
154 let cur = out[i + j] as u128 + (av as u128) * (bv as u128) + carry;
155 out[i + j] = cur as u64;
156 carry = cur >> 64;
157 }
158 out[i + b.len()] += carry as u64;
159 }
160 normalize(out)
161}
162
163fn mag_shl1(a: &[u64], bit: u64) -> Vec<u64> {
165 let mut out = Vec::with_capacity(a.len() + 1);
166 let mut carry = bit & 1;
167 for &limb in a {
168 out.push((limb << 1) | carry);
169 carry = limb >> 63;
170 }
171 if carry != 0 {
172 out.push(carry);
173 }
174 normalize(out)
175}
176
177fn mag_divrem(a: &[u64], b: &[u64]) -> (Vec<u64>, Vec<u64>) {
181 debug_assert!(!b.is_empty(), "division by zero magnitude");
182 if mag_cmp(a, b) == Ordering::Less {
183 return (Vec::new(), a.to_vec());
184 }
185 let nbits = a.len() * 64;
186 let mut q = vec![0u64; a.len()];
187 let mut r: Vec<u64> = Vec::new();
188 for i in (0..nbits).rev() {
189 let bit = (a[i / 64] >> (i % 64)) & 1;
190 r = mag_shl1(&r, bit);
191 if mag_cmp(&r, b) != Ordering::Less {
192 r = mag_sub(&r, b);
193 q[i / 64] |= 1u64 << (i % 64);
194 }
195 }
196 (normalize(q), normalize(r))
197}
198
199impl BigInt {
200 pub fn zero() -> Self {
202 BigInt { sign: Sign::Zero, mag: Mag::Inline(0) }
203 }
204
205 fn from_sign_mag(neg: bool, mag: Vec<u64>) -> Self {
208 let mag = Mag::from_vec(mag);
209 let sign = if mag.limbs().is_empty() {
210 Sign::Zero
211 } else if neg {
212 Sign::Neg
213 } else {
214 Sign::Pos
215 };
216 BigInt { sign, mag }
217 }
218
219 fn from_sign_mag_u128(neg: bool, m: u128) -> Self {
222 if m == 0 {
223 return Self::zero();
224 }
225 let lo = m as u64;
226 let hi = (m >> 64) as u64;
227 let mag = if hi == 0 { Mag::Inline(lo) } else { Mag::Heap(vec![lo, hi]) };
228 BigInt { sign: if neg { Sign::Neg } else { Sign::Pos }, mag }
229 }
230
231 pub fn from_i64(x: i64) -> Self {
233 Self::from_sign_mag_u128(x < 0, (x as i128).unsigned_abs())
234 }
235
236 pub fn from_u64(x: u64) -> Self {
238 Self::from_sign_mag_u128(false, x as u128)
239 }
240
241 pub fn to_i64(&self) -> Option<i64> {
244 let m = self.mag.as_single()? as i128;
245 let v = if self.sign == Sign::Neg { -m } else { m };
246 if (i64::MIN as i128..=i64::MAX as i128).contains(&v) {
247 Some(v as i64)
248 } else {
249 None
250 }
251 }
252
253 pub fn is_zero(&self) -> bool {
254 self.sign == Sign::Zero
255 }
256
257 pub fn is_odd(&self) -> bool {
259 self.mag.limbs().first().is_some_and(|limb| limb & 1 == 1)
260 }
261
262 pub fn to_f64(&self) -> f64 {
264 const TWO64: f64 = 18_446_744_073_709_551_616.0; let mut acc = 0.0f64;
266 for &limb in self.mag.limbs().iter().rev() {
267 acc = acc * TWO64 + limb as f64;
268 }
269 if self.sign == Sign::Neg {
270 -acc
271 } else {
272 acc
273 }
274 }
275
276 pub fn is_negative(&self) -> bool {
277 self.sign == Sign::Neg
278 }
279
280 pub fn is_positive(&self) -> bool {
281 self.sign == Sign::Pos
282 }
283
284 pub fn abs(&self) -> Self {
286 BigInt { sign: if self.sign == Sign::Zero { Sign::Zero } else { Sign::Pos }, mag: self.mag.clone() }
287 }
288
289 pub fn negated(&self) -> Self {
291 let sign = match self.sign {
292 Sign::Neg => Sign::Pos,
293 Sign::Zero => Sign::Zero,
294 Sign::Pos => Sign::Neg,
295 };
296 BigInt { sign, mag: self.mag.clone() }
297 }
298
299 pub fn add(&self, other: &Self) -> Self {
301 if let (Some(a), Some(b)) = (self.mag.as_single(), other.mag.as_single()) {
304 let av = if self.sign == Sign::Neg { -(a as i128) } else { a as i128 };
305 let bv = if other.sign == Sign::Neg { -(b as i128) } else { b as i128 };
306 let sum = av + bv;
307 return Self::from_sign_mag_u128(sum < 0, sum.unsigned_abs());
308 }
309 match (self.sign, other.sign) {
310 (Sign::Zero, _) => other.clone(),
311 (_, Sign::Zero) => self.clone(),
312 (a, b) if a == b => {
314 Self::from_sign_mag(a == Sign::Neg, mag_add(self.mag.limbs(), other.mag.limbs()))
315 }
316 _ => match mag_cmp(self.mag.limbs(), other.mag.limbs()) {
319 Ordering::Equal => Self::zero(),
320 Ordering::Greater => Self::from_sign_mag(
321 self.sign == Sign::Neg,
322 mag_sub(self.mag.limbs(), other.mag.limbs()),
323 ),
324 Ordering::Less => Self::from_sign_mag(
325 other.sign == Sign::Neg,
326 mag_sub(other.mag.limbs(), self.mag.limbs()),
327 ),
328 },
329 }
330 }
331
332 pub fn sub(&self, other: &Self) -> Self {
334 self.add(&other.negated())
335 }
336
337 pub fn mul(&self, other: &Self) -> Self {
339 let neg = (self.sign == Sign::Neg) ^ (other.sign == Sign::Neg);
340 if let (Some(a), Some(b)) = (self.mag.as_single(), other.mag.as_single()) {
342 return Self::from_sign_mag_u128(neg, (a as u128) * (b as u128));
343 }
344 if self.is_zero() || other.is_zero() {
345 return Self::zero();
346 }
347 Self::from_sign_mag(neg, mag_mul(self.mag.limbs(), other.mag.limbs()))
348 }
349
350 pub fn div_rem(&self, other: &Self) -> Option<(Self, Self)> {
355 if other.is_zero() {
356 return None;
357 }
358 let q_neg = (self.sign == Sign::Neg) ^ (other.sign == Sign::Neg);
359 if let (Some(a), Some(b)) = (self.mag.as_single(), other.mag.as_single()) {
362 return Some((
363 Self::from_sign_mag_u128(q_neg, (a / b) as u128),
364 Self::from_sign_mag_u128(self.sign == Sign::Neg, (a % b) as u128),
365 ));
366 }
367 if self.is_zero() {
368 return Some((Self::zero(), Self::zero()));
369 }
370 let (qm, rm) = mag_divrem(self.mag.limbs(), other.mag.limbs());
371 let q = Self::from_sign_mag(q_neg, qm);
372 let r = Self::from_sign_mag(self.sign == Sign::Neg, rm);
374 Some((q, r))
375 }
376
377 pub fn parse_decimal(s: &str) -> Option<Self> {
379 let bytes = s.as_bytes();
380 let (neg, digits) = match bytes.first() {
381 Some(b'-') => (true, &bytes[1..]),
382 Some(b'+') => (false, &bytes[1..]),
383 _ => (false, bytes),
384 };
385 if digits.is_empty() {
386 return None;
387 }
388 let ten = BigInt::from_u64(10);
389 let mut acc = BigInt::zero();
390 for &d in digits {
391 if !d.is_ascii_digit() {
392 return None;
393 }
394 acc = acc.mul(&ten).add(&BigInt::from_u64((d - b'0') as u64));
395 }
396 Some(if neg { acc.negated() } else { acc })
397 }
398
399 pub fn pow(&self, mut exp: u32) -> BigInt {
402 let mut result = BigInt::from_u64(1);
403 let mut base = self.clone();
404 while exp > 0 {
405 if exp & 1 == 1 {
406 result = result.mul(&base);
407 }
408 exp >>= 1;
409 if exp > 0 {
410 base = base.mul(&base);
411 }
412 }
413 result
414 }
415
416 pub fn to_le_bytes(&self) -> (bool, Vec<u8>) {
420 let limbs = self.mag.limbs();
421 let mut bytes = Vec::with_capacity(limbs.len() * 8);
422 for &limb in limbs {
423 bytes.extend_from_slice(&limb.to_le_bytes());
424 }
425 (self.sign == Sign::Neg, bytes)
426 }
427
428 pub fn from_le_bytes(negative: bool, bytes: &[u8]) -> Self {
431 let mut mag = Vec::with_capacity(bytes.len().div_ceil(8));
432 for chunk in bytes.chunks(8) {
433 let mut limb = [0u8; 8];
434 limb[..chunk.len()].copy_from_slice(chunk);
435 mag.push(u64::from_le_bytes(limb));
436 }
437 Self::from_sign_mag(negative, mag)
438 }
439}
440
441impl Ord for BigInt {
442 fn cmp(&self, other: &Self) -> Ordering {
443 let rank = |s: Sign| match s {
445 Sign::Neg => -1i8,
446 Sign::Zero => 0,
447 Sign::Pos => 1,
448 };
449 match rank(self.sign).cmp(&rank(other.sign)) {
450 Ordering::Equal => match self.sign {
451 Sign::Zero => Ordering::Equal,
452 Sign::Pos => mag_cmp(self.mag.limbs(), other.mag.limbs()),
453 Sign::Neg => mag_cmp(other.mag.limbs(), self.mag.limbs()),
454 },
455 other => other,
456 }
457 }
458}
459
460impl PartialOrd for BigInt {
461 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
462 Some(self.cmp(other))
463 }
464}
465
466impl fmt::Display for BigInt {
467 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
468 if self.is_zero() {
469 return write!(f, "0");
470 }
471 const TEN19: u64 = 10_000_000_000_000_000_000;
474 let ten19 = BigInt::from_u64(TEN19);
475 let mut chunks: Vec<u64> = Vec::new();
476 let mut cur = self.abs();
477 while !cur.is_zero() {
478 let (q, r) = cur.div_rem(&ten19).expect("10^19 is nonzero");
479 chunks.push(r.mag.limbs().first().copied().unwrap_or(0));
482 cur = q;
483 }
484 if self.is_negative() {
485 write!(f, "-")?;
486 }
487 write!(f, "{}", chunks.last().unwrap())?;
489 for &chunk in chunks.iter().rev().skip(1) {
490 write!(f, "{chunk:019}")?;
491 }
492 Ok(())
493 }
494}
495
496impl fmt::Debug for BigInt {
497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498 write!(f, "BigInt({self})")
499 }
500}
501
502impl From<i64> for BigInt {
503 fn from(x: i64) -> Self {
504 BigInt::from_i64(x)
505 }
506}
507
508fn bigint_gcd(a: &BigInt, b: &BigInt) -> BigInt {
514 let mut a = a.abs();
515 let mut b = b.abs();
516 while !b.is_zero() {
517 let (_q, r) = a.div_rem(&b).expect("b is nonzero inside the loop");
518 a = b;
519 b = r;
520 }
521 a
522}
523
524#[derive(Clone, PartialEq, Eq, Hash)]
534pub struct Rational {
535 num: BigInt,
537 den: BigInt,
541}
542
543impl Rational {
544 pub fn new(num: BigInt, den: BigInt) -> Option<Rational> {
548 if den.is_zero() {
549 return None;
550 }
551 let (mut num, mut den) = (num, den);
552 if den.is_negative() {
553 num = num.negated();
554 den = den.negated();
555 }
556 if num.is_zero() {
557 return Some(Rational { num: BigInt::zero(), den: BigInt::from_i64(1) });
558 }
559 let g = bigint_gcd(&num, &den);
560 let (num, _) = num.div_rem(&g).expect("gcd divides the numerator exactly");
561 let (den, _) = den.div_rem(&g).expect("gcd divides the denominator exactly");
562 Some(Rational { num, den })
563 }
564
565 pub fn from_bigint(n: BigInt) -> Rational {
567 Rational { num: n, den: BigInt::from_i64(1) }
568 }
569
570 pub fn from_i64(x: i64) -> Rational {
571 Rational::from_bigint(BigInt::from_i64(x))
572 }
573
574 pub fn from_ratio_i64(n: i64, d: i64) -> Option<Rational> {
576 Rational::new(BigInt::from_i64(n), BigInt::from_i64(d))
577 }
578
579 pub fn zero() -> Rational {
580 Rational { num: BigInt::zero(), den: BigInt::from_i64(1) }
581 }
582
583 pub fn one() -> Rational {
584 Rational::from_i64(1)
585 }
586
587 pub fn numerator(&self) -> &BigInt {
588 &self.num
589 }
590
591 pub fn denominator(&self) -> &BigInt {
592 &self.den
593 }
594
595 pub fn is_integer(&self) -> bool {
597 self.den == BigInt::from_i64(1)
598 }
599
600 pub fn is_zero(&self) -> bool {
601 self.num.is_zero()
602 }
603
604 pub fn is_negative(&self) -> bool {
605 self.num.is_negative()
606 }
607
608 pub fn is_positive(&self) -> bool {
609 self.num.is_positive()
610 }
611
612 pub fn to_bigint(&self) -> Option<BigInt> {
615 if self.is_integer() {
616 Some(self.num.clone())
617 } else {
618 None
619 }
620 }
621
622 pub fn to_i64(&self) -> Option<i64> {
624 if self.is_integer() {
625 self.num.to_i64()
626 } else {
627 None
628 }
629 }
630
631 pub fn to_f64(&self) -> f64 {
634 self.num.to_f64() / self.den.to_f64()
635 }
636
637 pub fn floor(&self) -> BigInt {
640 let (q, r) = self.num.div_rem(&self.den).expect("denominator is nonzero");
641 if self.num.is_negative() && !r.is_zero() {
642 q.sub(&BigInt::from_i64(1))
643 } else {
644 q
645 }
646 }
647
648 pub fn ceil(&self) -> BigInt {
651 let (q, r) = self.num.div_rem(&self.den).expect("denominator is nonzero");
652 if !self.num.is_negative() && !r.is_zero() {
653 q.add(&BigInt::from_i64(1))
654 } else {
655 q
656 }
657 }
658
659 pub fn round(&self) -> BigInt {
662 let two = BigInt::from_i64(2);
663 let numerator = self.num.abs().mul(&two).add(&self.den);
664 let denominator = self.den.mul(&two);
665 let (mag, _) = numerator.div_rem(&denominator).expect("denominator is nonzero");
666 if self.num.is_negative() {
667 mag.negated()
668 } else {
669 mag
670 }
671 }
672
673 pub fn negated(&self) -> Rational {
674 Rational { num: self.num.negated(), den: self.den.clone() }
675 }
676
677 pub fn abs(&self) -> Rational {
678 Rational { num: self.num.abs(), den: self.den.clone() }
679 }
680
681 pub fn recip(&self) -> Option<Rational> {
683 Rational::new(self.den.clone(), self.num.clone())
684 }
685
686 pub fn add(&self, other: &Rational) -> Rational {
687 let num = self.num.mul(&other.den).add(&other.num.mul(&self.den));
689 let den = self.den.mul(&other.den);
690 Rational::new(num, den).expect("product of positive denominators is nonzero")
691 }
692
693 pub fn sub(&self, other: &Rational) -> Rational {
694 let num = self.num.mul(&other.den).sub(&other.num.mul(&self.den));
695 let den = self.den.mul(&other.den);
696 Rational::new(num, den).expect("product of positive denominators is nonzero")
697 }
698
699 pub fn mul(&self, other: &Rational) -> Rational {
700 let num = self.num.mul(&other.num);
701 let den = self.den.mul(&other.den);
702 Rational::new(num, den).expect("product of positive denominators is nonzero")
703 }
704
705 pub fn div(&self, other: &Rational) -> Option<Rational> {
707 let num = self.num.mul(&other.den);
709 let den = self.den.mul(&other.num);
710 Rational::new(num, den)
711 }
712
713 pub fn pow(&self, exp: i32) -> Option<Rational> {
716 if exp >= 0 {
717 let k = exp as u32;
718 Some(
719 Rational::new(self.num.pow(k), self.den.pow(k))
720 .expect("denominator^k stays positive"),
721 )
722 } else {
723 if self.num.is_zero() {
724 return None;
725 }
726 let k = exp.unsigned_abs();
727 Rational::new(self.den.pow(k), self.num.pow(k))
729 }
730 }
731
732 pub fn parse(s: &str) -> Option<Rational> {
735 let s = s.trim();
736 if let Some((n, d)) = s.split_once('/') {
737 let num = BigInt::parse_decimal(n.trim())?;
738 let den = BigInt::parse_decimal(d.trim())?;
739 Rational::new(num, den)
740 } else {
741 Some(Rational::from_bigint(BigInt::parse_decimal(s)?))
742 }
743 }
744}
745
746impl Ord for Rational {
747 fn cmp(&self, other: &Self) -> Ordering {
748 self.num.mul(&other.den).cmp(&other.num.mul(&self.den))
750 }
751}
752
753impl PartialOrd for Rational {
754 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
755 Some(self.cmp(other))
756 }
757}
758
759impl fmt::Display for Rational {
760 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
761 if self.is_integer() {
762 write!(f, "{}", self.num)
763 } else {
764 write!(f, "{}/{}", self.num, self.den)
765 }
766 }
767}
768
769impl fmt::Debug for Rational {
770 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
771 write!(f, "Rational({}/{})", self.num, self.den)
772 }
773}
774
775impl From<i64> for Rational {
776 fn from(x: i64) -> Self {
777 Rational::from_i64(x)
778 }
779}
780
781impl From<BigInt> for Rational {
782 fn from(x: BigInt) -> Self {
783 Rational::from_bigint(x)
784 }
785}
786
787#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
795pub enum RoundingMode {
796 Down,
798 Up,
800 Floor,
802 Ceiling,
804 HalfUp,
806 HalfDown,
808 HalfEven,
810}
811
812fn ten_pow(k: u32) -> BigInt {
814 BigInt::from_u64(10).pow(k)
815}
816
817fn round_rational_to_bigint(x: &Rational, mode: RoundingMode) -> BigInt {
821 let num = x.numerator();
822 let den = x.denominator(); let (q, r) = num.div_rem(den).expect("rational denominator is nonzero");
824 if r.is_zero() {
825 return q; }
827 let neg = num.is_negative();
828 let twice = r.abs().mul(&BigInt::from_i64(2));
830 let half = twice.cmp(den);
831 let away = match mode {
832 RoundingMode::Down => false,
833 RoundingMode::Up => true,
834 RoundingMode::Floor => neg,
835 RoundingMode::Ceiling => !neg,
836 RoundingMode::HalfUp => half != Ordering::Less,
837 RoundingMode::HalfDown => half == Ordering::Greater,
838 RoundingMode::HalfEven => half == Ordering::Greater || (half == Ordering::Equal && q.is_odd()),
839 };
840 if away {
841 if neg { q.sub(&BigInt::from_i64(1)) } else { q.add(&BigInt::from_i64(1)) }
843 } else {
844 q
845 }
846}
847
848#[derive(Clone)]
859pub struct Decimal {
860 coeff: BigInt,
861 scale: u32,
863}
864
865impl Decimal {
866 pub fn from_bigint(coeff: BigInt) -> Decimal {
868 Decimal { coeff, scale: 0 }
869 }
870
871 pub fn from_i64(x: i64) -> Decimal {
872 Decimal::from_bigint(BigInt::from_i64(x))
873 }
874
875 pub fn from_coeff_scale(coeff: BigInt, scale: u32) -> Decimal {
877 Decimal { coeff, scale }
878 }
879
880 pub fn zero() -> Decimal {
881 Decimal::from_i64(0)
882 }
883
884 pub fn one() -> Decimal {
885 Decimal::from_i64(1)
886 }
887
888 pub fn scale(&self) -> u32 {
889 self.scale
890 }
891
892 pub fn coefficient(&self) -> &BigInt {
893 &self.coeff
894 }
895
896 pub fn is_zero(&self) -> bool {
897 self.coeff.is_zero()
898 }
899
900 pub fn is_negative(&self) -> bool {
901 self.coeff.is_negative()
902 }
903
904 pub fn negated(&self) -> Decimal {
905 Decimal { coeff: self.coeff.negated(), scale: self.scale }
906 }
907
908 pub fn abs(&self) -> Decimal {
909 Decimal { coeff: self.coeff.abs(), scale: self.scale }
910 }
911
912 pub fn to_rational(&self) -> Rational {
915 Rational::new(self.coeff.clone(), ten_pow(self.scale)).expect("10^scale is nonzero")
916 }
917
918 pub fn from_rational(value: &Rational, scale: u32, mode: RoundingMode) -> Decimal {
920 let scaled = value.mul(&Rational::from_bigint(ten_pow(scale)));
921 Decimal { coeff: round_rational_to_bigint(&scaled, mode), scale }
922 }
923
924 pub fn rescale(&self, scale: u32, mode: RoundingMode) -> Decimal {
927 if scale >= self.scale {
928 Decimal { coeff: self.coeff.mul(&ten_pow(scale - self.scale)), scale }
929 } else {
930 Decimal::from_rational(&self.to_rational(), scale, mode)
931 }
932 }
933
934 fn aligned(&self, other: &Decimal) -> (BigInt, BigInt, u32) {
936 let s = self.scale.max(other.scale);
937 let a = self.coeff.mul(&ten_pow(s - self.scale));
938 let b = other.coeff.mul(&ten_pow(s - other.scale));
939 (a, b, s)
940 }
941
942 pub fn add(&self, other: &Decimal) -> Decimal {
943 let (a, b, s) = self.aligned(other);
944 Decimal { coeff: a.add(&b), scale: s }
945 }
946
947 pub fn sub(&self, other: &Decimal) -> Decimal {
948 let (a, b, s) = self.aligned(other);
949 Decimal { coeff: a.sub(&b), scale: s }
950 }
951
952 pub fn mul(&self, other: &Decimal) -> Decimal {
954 Decimal { coeff: self.coeff.mul(&other.coeff), scale: self.scale + other.scale }
955 }
956
957 pub fn div(&self, other: &Decimal, scale: u32, mode: RoundingMode) -> Option<Decimal> {
960 let q = self.to_rational().div(&other.to_rational())?;
961 Some(Decimal::from_rational(&q, scale, mode))
962 }
963
964 fn normalized(&self) -> (BigInt, u32) {
967 if self.coeff.is_zero() {
968 return (BigInt::zero(), 0);
969 }
970 let ten = BigInt::from_u64(10);
971 let mut c = self.coeff.clone();
972 let mut s = self.scale;
973 while s > 0 {
974 let (q, r) = c.div_rem(&ten).expect("ten is nonzero");
975 if !r.is_zero() {
976 break;
977 }
978 c = q;
979 s -= 1;
980 }
981 (c, s)
982 }
983
984 pub fn to_le_bytes(&self) -> (bool, Vec<u8>, u32) {
987 let (neg, bytes) = self.coeff.to_le_bytes();
988 (neg, bytes, self.scale)
989 }
990
991 pub fn from_le_bytes(negative: bool, bytes: &[u8], scale: u32) -> Decimal {
992 Decimal { coeff: BigInt::from_le_bytes(negative, bytes), scale }
993 }
994
995 pub fn parse(s: &str) -> Option<Decimal> {
999 let s = s.trim();
1000 let (neg, body) = match s.as_bytes().first() {
1001 Some(b'-') => (true, &s[1..]),
1002 Some(b'+') => (false, &s[1..]),
1003 _ => (false, s),
1004 };
1005 if body.is_empty() {
1006 return None;
1007 }
1008 let (int_part, frac_part) = match body.split_once('.') {
1009 Some((i, f)) => (i, f),
1010 None => (body, ""),
1011 };
1012 if int_part.is_empty() && frac_part.is_empty() {
1013 return None; }
1015 if !int_part.bytes().all(|c| c.is_ascii_digit()) || !frac_part.bytes().all(|c| c.is_ascii_digit()) {
1016 return None;
1017 }
1018 let digits = format!("{int_part}{frac_part}");
1019 let mag = if digits.is_empty() { BigInt::zero() } else { BigInt::parse_decimal(&digits)? };
1020 let coeff = if neg { mag.negated() } else { mag };
1021 Some(Decimal { coeff, scale: frac_part.len() as u32 })
1022 }
1023}
1024
1025impl PartialEq for Decimal {
1026 fn eq(&self, other: &Self) -> bool {
1027 self.normalized() == other.normalized()
1028 }
1029}
1030
1031impl Eq for Decimal {}
1032
1033impl std::hash::Hash for Decimal {
1034 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1035 self.normalized().hash(state);
1036 }
1037}
1038
1039impl Ord for Decimal {
1040 fn cmp(&self, other: &Self) -> Ordering {
1041 self.to_rational().cmp(&other.to_rational())
1043 }
1044}
1045
1046impl PartialOrd for Decimal {
1047 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1048 Some(self.cmp(other))
1049 }
1050}
1051
1052impl fmt::Display for Decimal {
1053 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1054 if self.scale == 0 {
1055 return write!(f, "{}", self.coeff);
1056 }
1057 let neg = self.coeff.is_negative();
1058 let mut digits = self.coeff.abs().to_string();
1059 let scale = self.scale as usize;
1060 if digits.len() <= scale {
1061 digits = format!("{}{}", "0".repeat(scale + 1 - digits.len()), digits);
1063 }
1064 let point = digits.len() - scale;
1065 if neg {
1066 write!(f, "-")?;
1067 }
1068 write!(f, "{}.{}", &digits[..point], &digits[point..])
1069 }
1070}
1071
1072impl fmt::Debug for Decimal {
1073 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1074 write!(f, "Decimal({self})")
1075 }
1076}
1077
1078impl From<i64> for Decimal {
1079 fn from(x: i64) -> Self {
1080 Decimal::from_i64(x)
1081 }
1082}
1083
1084impl From<BigInt> for Decimal {
1085 fn from(x: BigInt) -> Self {
1086 Decimal::from_bigint(x)
1087 }
1088}
1089
1090#[derive(Clone, PartialEq, Eq, Hash)]
1102pub struct Complex {
1103 re: Rational,
1104 im: Rational,
1105}
1106
1107impl Complex {
1108 pub fn new(re: Rational, im: Rational) -> Complex {
1109 Complex { re, im }
1110 }
1111
1112 pub fn from_rational(re: Rational) -> Complex {
1114 Complex { re, im: Rational::zero() }
1115 }
1116
1117 pub fn from_i64(x: i64) -> Complex {
1118 Complex::from_rational(Rational::from_i64(x))
1119 }
1120
1121 pub fn zero() -> Complex {
1122 Complex { re: Rational::zero(), im: Rational::zero() }
1123 }
1124
1125 pub fn one() -> Complex {
1126 Complex::from_i64(1)
1127 }
1128
1129 pub fn i() -> Complex {
1131 Complex { re: Rational::zero(), im: Rational::one() }
1132 }
1133
1134 pub fn re(&self) -> &Rational {
1135 &self.re
1136 }
1137
1138 pub fn im(&self) -> &Rational {
1139 &self.im
1140 }
1141
1142 pub fn is_zero(&self) -> bool {
1143 self.re.is_zero() && self.im.is_zero()
1144 }
1145
1146 pub fn is_real(&self) -> bool {
1148 self.im.is_zero()
1149 }
1150
1151 pub fn conjugate(&self) -> Complex {
1153 Complex { re: self.re.clone(), im: self.im.negated() }
1154 }
1155
1156 pub fn norm_sqr(&self) -> Rational {
1158 self.re.mul(&self.re).add(&self.im.mul(&self.im))
1159 }
1160
1161 pub fn abs_f64(&self) -> f64 {
1164 self.norm_sqr().to_f64().sqrt()
1165 }
1166
1167 pub fn negated(&self) -> Complex {
1168 Complex { re: self.re.negated(), im: self.im.negated() }
1169 }
1170
1171 pub fn add(&self, other: &Complex) -> Complex {
1172 Complex { re: self.re.add(&other.re), im: self.im.add(&other.im) }
1173 }
1174
1175 pub fn sub(&self, other: &Complex) -> Complex {
1176 Complex { re: self.re.sub(&other.re), im: self.im.sub(&other.im) }
1177 }
1178
1179 pub fn mul(&self, other: &Complex) -> Complex {
1181 let (a, b, c, d) = (&self.re, &self.im, &other.re, &other.im);
1182 Complex { re: a.mul(c).sub(&b.mul(d)), im: a.mul(d).add(&b.mul(c)) }
1183 }
1184
1185 pub fn recip(&self) -> Option<Complex> {
1187 let n = self.norm_sqr();
1188 if n.is_zero() {
1189 return None;
1190 }
1191 let inv = n.recip().expect("norm is nonzero here");
1192 Some(Complex { re: self.re.mul(&inv), im: self.im.negated().mul(&inv) })
1193 }
1194
1195 pub fn div(&self, other: &Complex) -> Option<Complex> {
1197 Some(self.mul(&other.recip()?))
1198 }
1199
1200 pub fn pow(&self, exp: i32) -> Option<Complex> {
1203 if exp < 0 {
1204 return self.recip()?.pow(-exp);
1205 }
1206 let mut result = Complex::one();
1207 let mut base = self.clone();
1208 let mut e = exp as u32;
1209 while e > 0 {
1210 if e & 1 == 1 {
1211 result = result.mul(&base);
1212 }
1213 e >>= 1;
1214 if e > 0 {
1215 base = base.mul(&base);
1216 }
1217 }
1218 Some(result)
1219 }
1220
1221 pub fn parse(s: &str) -> Option<Complex> {
1224 let s = s.trim();
1225 if s.is_empty() {
1226 return None;
1227 }
1228 let bytes = s.as_bytes();
1229 if bytes[bytes.len() - 1] != b'i' {
1230 return Some(Complex::from_rational(Rational::parse(s)?));
1232 }
1233 let body = &s[..s.len() - 1]; let split = body
1236 .bytes()
1237 .enumerate()
1238 .rev()
1239 .find(|&(i, c)| i > 0 && (c == b'+' || c == b'-'))
1240 .map(|(i, _)| i);
1241 let (real_str, imag_str) = match split {
1242 Some(i) => (&body[..i], &body[i..]),
1243 None => ("", body),
1244 };
1245 let re = if real_str.is_empty() { Rational::zero() } else { Rational::parse(real_str)? };
1246 let im = match imag_str {
1247 "" | "+" => Rational::one(),
1248 "-" => Rational::from_i64(-1),
1249 other => Rational::parse(other)?,
1250 };
1251 Some(Complex { re, im })
1252 }
1253}
1254
1255impl fmt::Display for Complex {
1256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1257 if self.im.is_zero() {
1258 return write!(f, "{}", self.re);
1259 }
1260 let mag = self.im.abs();
1261 let unit = mag == Rational::one(); if self.re.is_zero() {
1263 return if self.im.is_negative() {
1265 if unit { write!(f, "-i") } else { write!(f, "-{mag}i") }
1266 } else if unit {
1267 write!(f, "i")
1268 } else {
1269 write!(f, "{mag}i")
1270 };
1271 }
1272 let sign = if self.im.is_negative() { "-" } else { "+" };
1273 if unit {
1274 write!(f, "{}{}i", self.re, sign)
1275 } else {
1276 write!(f, "{}{}{}i", self.re, sign, mag)
1277 }
1278 }
1279}
1280
1281impl fmt::Debug for Complex {
1282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1283 write!(f, "Complex({self})")
1284 }
1285}
1286
1287impl From<i64> for Complex {
1288 fn from(x: i64) -> Self {
1289 Complex::from_i64(x)
1290 }
1291}
1292
1293impl From<Rational> for Complex {
1294 fn from(x: Rational) -> Self {
1295 Complex::from_rational(x)
1296 }
1297}
1298
1299fn bigint_egcd(a: &BigInt, b: &BigInt) -> (BigInt, BigInt, BigInt) {
1306 let (mut old_r, mut r) = (a.clone(), b.clone());
1307 let (mut old_s, mut s) = (BigInt::from_i64(1), BigInt::zero());
1308 let (mut old_t, mut t) = (BigInt::zero(), BigInt::from_i64(1));
1309 while !r.is_zero() {
1310 let (q, _) = old_r.div_rem(&r).expect("r is nonzero inside the loop");
1311 let nr = old_r.sub(&q.mul(&r));
1312 old_r = std::mem::replace(&mut r, nr);
1313 let ns = old_s.sub(&q.mul(&s));
1314 old_s = std::mem::replace(&mut s, ns);
1315 let nt = old_t.sub(&q.mul(&t));
1316 old_t = std::mem::replace(&mut t, nt);
1317 }
1318 (old_r, old_s, old_t)
1319}
1320
1321#[derive(Clone, PartialEq, Eq, Hash)]
1331pub struct Modular {
1332 value: BigInt,
1333 modulus: BigInt,
1334}
1335
1336fn mod_reduce(value: BigInt, modulus: &BigInt) -> BigInt {
1338 let (_, r) = value.div_rem(modulus).expect("modulus is nonzero");
1339 if r.is_negative() {
1340 r.add(modulus)
1341 } else {
1342 r
1343 }
1344}
1345
1346impl Modular {
1347 pub fn new(value: BigInt, modulus: BigInt) -> Option<Modular> {
1349 if modulus.is_zero() || modulus.is_negative() {
1350 return None;
1351 }
1352 let value = mod_reduce(value, &modulus);
1353 Some(Modular { value, modulus })
1354 }
1355
1356 pub fn from_i64(value: i64, modulus: i64) -> Option<Modular> {
1358 Modular::new(BigInt::from_i64(value), BigInt::from_i64(modulus))
1359 }
1360
1361 pub fn value(&self) -> &BigInt {
1363 &self.value
1364 }
1365
1366 pub fn modulus(&self) -> &BigInt {
1367 &self.modulus
1368 }
1369
1370 pub fn is_zero(&self) -> bool {
1371 self.value.is_zero()
1372 }
1373
1374 pub fn add(&self, other: &Modular) -> Option<Modular> {
1376 if self.modulus != other.modulus {
1377 return None;
1378 }
1379 Modular::new(self.value.add(&other.value), self.modulus.clone())
1380 }
1381
1382 pub fn sub(&self, other: &Modular) -> Option<Modular> {
1383 if self.modulus != other.modulus {
1384 return None;
1385 }
1386 Modular::new(self.value.sub(&other.value), self.modulus.clone())
1387 }
1388
1389 pub fn mul(&self, other: &Modular) -> Option<Modular> {
1390 if self.modulus != other.modulus {
1391 return None;
1392 }
1393 Modular::new(self.value.mul(&other.value), self.modulus.clone())
1394 }
1395
1396 pub fn negated(&self) -> Modular {
1398 Modular::new(self.value.negated(), self.modulus.clone()).expect("modulus stays valid")
1399 }
1400
1401 pub fn pow(&self, mut exp: u64) -> Modular {
1403 let one = Modular::new(BigInt::from_i64(1), self.modulus.clone()).expect("modulus valid");
1404 let mut result = one;
1405 let mut base = self.clone();
1406 while exp > 0 {
1407 if exp & 1 == 1 {
1408 result = result.mul(&base).expect("same modulus");
1409 }
1410 exp >>= 1;
1411 if exp > 0 {
1412 base = base.mul(&base).expect("same modulus");
1413 }
1414 }
1415 result
1416 }
1417
1418 pub fn inverse(&self) -> Option<Modular> {
1421 let (g, x, _) = bigint_egcd(&self.value, &self.modulus);
1422 if g != BigInt::from_i64(1) {
1423 return None;
1424 }
1425 Modular::new(x, self.modulus.clone())
1426 }
1427
1428 pub fn div(&self, other: &Modular) -> Option<Modular> {
1430 if self.modulus != other.modulus {
1431 return None;
1432 }
1433 self.mul(&other.inverse()?)
1434 }
1435}
1436
1437impl fmt::Display for Modular {
1438 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1439 write!(f, "{} (mod {})", self.value, self.modulus)
1440 }
1441}
1442
1443impl fmt::Debug for Modular {
1444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1445 write!(f, "Modular({} mod {})", self.value, self.modulus)
1446 }
1447}
1448
1449pub const NUMERIC_HASH_P: u64 = (1u64 << 61) - 1;
1462
1463fn decompose_f64(f: f64) -> Option<(bool, u64, i32)> {
1466 if !f.is_finite() {
1467 return None;
1468 }
1469 let bits = f.to_bits();
1470 let neg = bits >> 63 == 1;
1471 let biased = ((bits >> 52) & 0x7ff) as i32;
1472 let frac = bits & ((1u64 << 52) - 1);
1473 let (m, e) = if biased == 0 {
1474 (frac, -1074) } else {
1476 (frac | (1u64 << 52), biased - 1075)
1477 };
1478 Some((neg, m, e))
1479}
1480
1481pub fn rational_from_f64_exact(f: f64) -> Option<Rational> {
1483 let (neg, m, e) = decompose_f64(f)?;
1484 let mag = BigInt::from_u64(m);
1485 let two = BigInt::from_u64(2);
1486 let (num, den) = if e >= 0 {
1487 (mag.mul(&two.pow(e as u32)), BigInt::from_i64(1))
1488 } else {
1489 (mag, two.pow((-e) as u32))
1490 };
1491 let num = if neg { num.negated() } else { num };
1492 Rational::new(num, den)
1493}
1494
1495pub fn cmp_i64_f64_exact(i: i64, f: f64) -> Option<Ordering> {
1497 if f.is_nan() {
1498 return None;
1499 }
1500 if f == f64::INFINITY {
1501 return Some(Ordering::Less);
1502 }
1503 if f == f64::NEG_INFINITY {
1504 return Some(Ordering::Greater);
1505 }
1506 if i.unsigned_abs() <= (1u64 << 53) {
1509 return (i as f64).partial_cmp(&f);
1510 }
1511 let fr = rational_from_f64_exact(f).expect("finite f64 is an exact rational");
1512 Some(Rational::from_i64(i).cmp(&fr))
1513}
1514
1515pub fn cmp_bigint_f64_exact(b: &BigInt, f: f64) -> Option<Ordering> {
1517 if f.is_nan() {
1518 return None;
1519 }
1520 if f == f64::INFINITY {
1521 return Some(Ordering::Less);
1522 }
1523 if f == f64::NEG_INFINITY {
1524 return Some(Ordering::Greater);
1525 }
1526 let fr = rational_from_f64_exact(f).expect("finite f64 is an exact rational");
1527 Some(Rational::from_bigint(b.clone()).cmp(&fr))
1528}
1529
1530pub fn cmp_rational_f64_exact(r: &Rational, f: f64) -> Option<Ordering> {
1532 if f.is_nan() {
1533 return None;
1534 }
1535 if f == f64::INFINITY {
1536 return Some(Ordering::Less);
1537 }
1538 if f == f64::NEG_INFINITY {
1539 return Some(Ordering::Greater);
1540 }
1541 let fr = rational_from_f64_exact(f).expect("finite f64 is an exact rational");
1542 Some(r.cmp(&fr))
1543}
1544
1545fn mod_p(x: u64) -> u64 {
1547 let r = (x & NUMERIC_HASH_P) + (x >> 61);
1548 if r >= NUMERIC_HASH_P { r - NUMERIC_HASH_P } else { r }
1549}
1550
1551fn mul_mod_p(a: u64, b: u64) -> u64 {
1552 ((a as u128 * b as u128) % (NUMERIC_HASH_P as u128)) as u64
1553}
1554
1555fn pow_mod_p(mut base: u64, mut exp: u64) -> u64 {
1556 let mut acc = 1u64;
1557 base %= NUMERIC_HASH_P;
1558 while exp > 0 {
1559 if exp & 1 == 1 {
1560 acc = mul_mod_p(acc, base);
1561 }
1562 base = mul_mod_p(base, base);
1563 exp >>= 1;
1564 }
1565 acc
1566}
1567
1568fn signed_hash(neg: bool, h: u64) -> u64 {
1571 if neg && h != 0 { NUMERIC_HASH_P - h } else { h }
1572}
1573
1574pub fn numeric_hash_i64(n: i64) -> u64 {
1576 signed_hash(n < 0, mod_p(n.unsigned_abs()))
1577}
1578
1579pub fn numeric_hash_bigint(b: &BigInt) -> u64 {
1582 let mut acc: u64 = 0;
1583 for &limb in b.mag.limbs().iter().rev() {
1584 let t = (acc as u128) * 8 + (mod_p(limb) as u128);
1585 acc = (t % (NUMERIC_HASH_P as u128)) as u64;
1586 }
1587 signed_hash(b.is_negative(), acc)
1588}
1589
1590pub fn numeric_hash_f64(f: f64) -> u64 {
1594 if f.is_nan() {
1595 return 0x6e616e; }
1597 if f == f64::INFINITY {
1598 return 314159;
1599 }
1600 if f == f64::NEG_INFINITY {
1601 return NUMERIC_HASH_P - 314159;
1602 }
1603 let (neg, m, e) = decompose_f64(f).expect("finite");
1604 let h = mul_mod_p(mod_p(m), pow_mod_p(2, e.rem_euclid(61) as u64));
1605 signed_hash(neg, h)
1606}
1607
1608pub fn numeric_hash_rational(r: &Rational) -> u64 {
1612 let num = numeric_hash_bigint(&r.numerator().abs());
1613 let den = numeric_hash_bigint(&r.denominator().abs());
1614 let inv = pow_mod_p(den, NUMERIC_HASH_P - 2);
1615 signed_hash(r.is_negative(), mul_mod_p(num, inv))
1616}
1617
1618#[cfg(test)]
1619mod tests {
1620 use super::*;
1621
1622 fn b(x: i64) -> BigInt {
1623 BigInt::from_i64(x)
1624 }
1625
1626 #[test]
1627 fn from_to_i64_round_trips_the_extremes() {
1628 for x in [0i64, 1, -1, 42, -42, i64::MAX, i64::MIN, i64::MAX - 1, i64::MIN + 1] {
1629 assert_eq!(BigInt::from_i64(x).to_i64(), Some(x), "round trip {x}");
1630 }
1631 }
1632
1633 #[test]
1634 fn to_i64_is_none_just_past_the_boundary() {
1635 let over = b(i64::MAX).add(&b(1));
1638 let under = b(i64::MIN).sub(&b(1));
1639 assert_eq!(over.to_i64(), None);
1640 assert_eq!(under.to_i64(), None);
1641 assert_eq!(over.to_string(), "9223372036854775808");
1643 assert_eq!(under.to_string(), "-9223372036854775809");
1644 }
1645
1646 #[test]
1647 fn add_sub_mul_match_i128_on_a_dense_grid() {
1648 let xs: [i64; 11] =
1651 [0, 1, -1, 2, -2, 1000, -1000, i32::MAX as i64, i32::MIN as i64, i64::MAX, i64::MIN];
1652 for &x in &xs {
1653 for &y in &xs {
1654 let (bx, by) = (b(x), b(y));
1655 assert_eq!(bx.add(&by).to_string(), (x as i128 + y as i128).to_string(), "{x}+{y}");
1656 assert_eq!(bx.sub(&by).to_string(), (x as i128 - y as i128).to_string(), "{x}-{y}");
1657 assert_eq!(bx.mul(&by).to_string(), (x as i128 * y as i128).to_string(), "{x}*{y}");
1658 }
1659 }
1660 }
1661
1662 #[test]
1663 fn div_rem_matches_i64_truncation_including_signs() {
1664 let xs = [0i64, 1, -1, 7, -7, 100, -100, 9_999_999, -9_999_999, i64::MAX, i64::MIN];
1665 let ys = [1i64, -1, 2, -2, 3, -3, 7, -7, 1000, -1000];
1666 for &x in &xs {
1667 for &y in &ys {
1668 let (q, r) = b(x).div_rem(&b(y)).expect("nonzero divisor");
1669 let (eq, er) = ((x as i128) / (y as i128), (x as i128) % (y as i128));
1671 assert_eq!(q.to_string(), eq.to_string(), "{x}/{y} quotient");
1672 assert_eq!(r.to_string(), er.to_string(), "{x}%{y} remainder");
1673 assert_eq!(b(x), q.mul(&b(y)).add(&r), "x = q*y + r for {x},{y}");
1675 }
1676 }
1677 }
1678
1679 #[test]
1680 fn division_by_zero_is_none_not_a_panic() {
1681 assert!(b(5).div_rem(&BigInt::zero()).is_none());
1682 assert!(BigInt::zero().div_rem(&BigInt::zero()).is_none());
1683 }
1684
1685 #[test]
1686 fn huge_factorial_is_exact() {
1687 let mut acc = BigInt::from_u64(1);
1689 for k in 1..=50u64 {
1690 acc = acc.mul(&BigInt::from_u64(k));
1691 }
1692 assert_eq!(acc.to_string(), "30414093201713378043612608166064768844377641568960512000000000000");
1693 for k in 1..=50u64 {
1695 let (q, r) = acc.div_rem(&BigInt::from_u64(k)).unwrap();
1696 assert!(r.is_zero(), "{k}! divides cleanly");
1697 acc = q;
1698 }
1699 assert_eq!(acc, BigInt::from_u64(1));
1700 }
1701
1702 #[test]
1703 fn parse_and_display_round_trip_big_decimals() {
1704 for s in [
1705 "0",
1706 "-0",
1707 "7",
1708 "-7",
1709 "9223372036854775808",
1710 "-9223372036854775809",
1711 "123456789012345678901234567890",
1712 "-100000000000000000000000000000000000000000",
1713 ] {
1714 let parsed = BigInt::parse_decimal(s).expect("parse");
1715 let expected = if s == "-0" { "0" } else { s };
1717 assert_eq!(parsed.to_string(), expected, "round trip {s}");
1718 }
1719 assert!(BigInt::parse_decimal("12x3").is_none());
1720 assert!(BigInt::parse_decimal("").is_none());
1721 assert!(BigInt::parse_decimal("-").is_none());
1722 }
1723
1724 struct Rng(u64);
1727 impl Rng {
1728 fn next(&mut self) -> u64 {
1729 self.0 = self.0.wrapping_add(0x9E37_79B9_7F4A_7C15);
1730 let mut z = self.0;
1731 z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
1732 z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
1733 z ^ (z >> 31)
1734 }
1735 fn big(&mut self) -> BigInt {
1738 let limbs = (self.next() % 4) as usize;
1739 let mut bytes = Vec::new();
1740 for _ in 0..limbs {
1741 bytes.extend_from_slice(&self.next().to_le_bytes());
1742 }
1743 BigInt::from_le_bytes(self.next() & 1 == 1, &bytes)
1744 }
1745 }
1746
1747 #[test]
1748 fn fuzz_algebraic_laws_hold_for_random_bigints() {
1749 let mut r = Rng(0x0BAD_F00D_DEAD_BEEF);
1750 for _ in 0..3000 {
1751 let (a, b, c) = (r.big(), r.big(), r.big());
1752 assert_eq!(a.add(&b), b.add(&a), "add commutes");
1754 assert_eq!(a.mul(&b), b.mul(&a), "mul commutes");
1755 assert_eq!(a.add(&b).add(&c), a.add(&b.add(&c)), "add associates");
1757 assert_eq!(a.mul(&b).mul(&c), a.mul(&b.mul(&c)), "mul associates");
1758 assert_eq!(a.mul(&b.add(&c)), a.mul(&b).add(&a.mul(&c)), "mul distributes over add");
1760 assert_eq!(a.add(&BigInt::zero()), a, "0 is the additive identity");
1762 assert_eq!(a.mul(&BigInt::from_u64(1)), a, "1 is the multiplicative identity");
1763 assert!(a.mul(&BigInt::zero()).is_zero(), "x*0 = 0");
1764 assert_eq!(a.sub(&a), BigInt::zero(), "x - x = 0");
1765 assert_eq!(a.add(&a.negated()), BigInt::zero(), "x + (-x) = 0");
1766 assert_eq!(a.negated().negated(), a, "double negation");
1767 assert!(!a.abs().is_negative(), "|x| >= 0");
1769 assert_eq!(a.negated().mul(&b), a.mul(&b).negated(), "(-a)*b = -(a*b)");
1770 if !b.is_zero() {
1772 let (q, rem) = a.div_rem(&b).unwrap();
1773 assert_eq!(q.mul(&b).add(&rem), a, "a = q*b + r exactly");
1774 assert!(rem.is_zero() || rem.abs() < b.abs(), "|r| < |b|");
1775 }
1776 let (neg, bytes) = a.to_le_bytes();
1778 assert_eq!(BigInt::from_le_bytes(neg, &bytes), a, "byte round-trip");
1779 assert_eq!(BigInt::parse_decimal(&a.to_string()).unwrap(), a, "decimal round-trip");
1780 assert_eq!(a < b, b > a, "antisymmetry");
1782 if a < b && b < c {
1783 assert!(a < c, "transitivity");
1784 }
1785 }
1786 }
1787
1788 #[test]
1789 fn fuzz_differential_against_i128() {
1790 let mut r = Rng(0xC0FF_EE00_1234_5678);
1792 for _ in 0..5000 {
1793 let x = r.next() as i64;
1794 let y = r.next() as i64;
1795 assert_eq!(b(x).add(&b(y)).to_string(), (x as i128 + y as i128).to_string(), "{x}+{y}");
1796 assert_eq!(b(x).sub(&b(y)).to_string(), (x as i128 - y as i128).to_string(), "{x}-{y}");
1797 assert_eq!(b(x).mul(&b(y)).to_string(), (x as i128 * y as i128).to_string(), "{x}*{y}");
1798 if y != 0 {
1799 let (q, rem) = b(x).div_rem(&b(y)).unwrap();
1800 assert_eq!(q.to_string(), (x as i128 / y as i128).to_string(), "{x}/{y}");
1801 assert_eq!(rem.to_string(), (x as i128 % y as i128).to_string(), "{x}%{y}");
1802 }
1803 }
1804 }
1805
1806 #[test]
1807 fn limb_boundary_edge_cases_are_exact() {
1808 let two64 = BigInt::parse_decimal("18446744073709551616").unwrap(); assert_eq!(two64.sub(&BigInt::from_u64(1)).to_string(), "18446744073709551615");
1811 let two128 = two64.mul(&two64);
1813 assert_eq!(two128.to_string(), "340282366920938463463374607431768211456");
1814 assert_eq!(two128.sub(&BigInt::from_u64(1)).to_string(), "340282366920938463463374607431768211455");
1816 assert_eq!(BigInt::from_u64(u64::MAX).add(&BigInt::from_u64(1)), two64);
1818 let (q, rem) = two128.div_rem(&two64).unwrap();
1820 assert_eq!(q, two64);
1821 assert!(rem.is_zero());
1822 }
1823
1824 #[test]
1825 fn pow_is_exact_and_unbounded() {
1826 assert_eq!(b(2).pow(63).to_string(), "9223372036854775808"); assert_eq!(b(2).pow(100).to_string(), "1267650600228229401496703205376");
1828 assert_eq!(b(10).pow(0).to_string(), "1");
1829 assert_eq!(b(0).pow(0).to_string(), "1");
1830 assert_eq!(b(-3).pow(3).to_string(), "-27");
1831 assert_eq!(b(-2).pow(10).to_string(), "1024");
1832 let mut acc = BigInt::from_u64(1);
1834 for _ in 0..50 {
1835 acc = acc.mul(&b(3));
1836 }
1837 assert_eq!(b(3).pow(50), acc);
1838 }
1839
1840 #[test]
1841 fn ordering_is_total_and_sign_aware() {
1842 let mut v = vec![b(3), b(-5), BigInt::zero(), b(i64::MAX), b(i64::MIN), b(-5).mul(&b(i64::MAX))];
1843 v.sort();
1844 let as_str: Vec<String> = v.iter().map(|x| x.to_string()).collect();
1845 assert_eq!(
1846 as_str,
1847 vec![
1848 "-46116860184273879035", "-9223372036854775808", "-5",
1851 "0",
1852 "3",
1853 "9223372036854775807", ]
1855 );
1856 }
1857
1858 fn r(n: i64, d: i64) -> Rational {
1863 Rational::from_ratio_i64(n, d).expect("nonzero denominator in test")
1864 }
1865
1866 #[test]
1867 fn rational_reduces_to_lowest_terms_on_construction() {
1868 assert_eq!(r(6, 8).to_string(), "3/4");
1869 assert_eq!(r(10, 5).to_string(), "2");
1870 assert_eq!(r(0, 7).to_string(), "0");
1871 assert_eq!(r(100, 1000).to_string(), "1/10");
1872 assert_eq!(r(6, 8), r(3, 4));
1874 assert_eq!(r(0, 7), r(0, 1));
1875 }
1876
1877 #[test]
1878 fn rational_normalizes_sign_onto_a_positive_denominator() {
1879 assert_eq!(r(1, -2).to_string(), "-1/2");
1880 assert_eq!(r(-1, -2).to_string(), "1/2");
1881 assert_eq!(r(-3, 4), r(3, -4));
1882 assert!(r(1, -2).is_negative());
1883 assert!(!r(-1, -2).is_negative());
1884 assert!(!r(1, -2).denominator().is_negative());
1886 }
1887
1888 #[test]
1889 fn rational_zero_denominator_is_none() {
1890 assert!(Rational::from_ratio_i64(5, 0).is_none());
1891 assert!(Rational::new(BigInt::from_i64(1), BigInt::zero()).is_none());
1892 assert!(r(3, 4).div(&Rational::zero()).is_none());
1893 assert!(Rational::zero().recip().is_none());
1894 assert!(Rational::parse("7/0").is_none());
1895 }
1896
1897 #[test]
1898 fn rational_arithmetic_is_exact() {
1899 assert_eq!(r(1, 3).add(&r(1, 6)).to_string(), "1/2");
1900 assert_eq!(r(1, 2).sub(&r(1, 3)).to_string(), "1/6");
1901 assert_eq!(r(2, 3).mul(&r(3, 4)).to_string(), "1/2");
1902 assert_eq!(r(1, 2).div(&r(3, 4)).unwrap().to_string(), "2/3");
1903 assert!(r(5, 7).add(&r(5, 7).negated()).is_zero());
1905 assert_eq!(r(5, 7).mul(&r(5, 7).recip().unwrap()), Rational::one());
1906 }
1907
1908 #[test]
1909 fn one_third_stays_exact_where_a_json_double_would_round() {
1910 let third = r(1, 3);
1912 let sum = third.add(&third).add(&third);
1913 assert_eq!(sum, Rational::one());
1914 assert_eq!(third.to_string(), "1/3");
1915 assert_ne!(0.1_f64 + 0.2, 0.3);
1917 assert_eq!(r(1, 10).add(&r(2, 10)), r(3, 10));
1918 }
1919
1920 #[test]
1921 fn rational_ordering_cross_multiplies_without_rounding() {
1922 assert!(r(1, 3) < r(1, 2));
1923 assert!(r(-1, 2) < r(1, 3));
1924 assert!(r(2, 4) == r(1, 2));
1925 let mut v = vec![r(1, 2), r(1, 3), r(-1, 4), r(2, 3), Rational::zero(), r(1, 2)];
1926 v.sort();
1927 let s: Vec<String> = v.iter().map(|x| x.to_string()).collect();
1928 assert_eq!(s, ["-1/4", "0", "1/3", "1/2", "1/2", "2/3"]);
1929 }
1930
1931 #[test]
1932 fn rational_terms_overflow_i64_into_bigint() {
1933 let big = Rational::new(BigInt::from_i64(1), BigInt::from_i64(i64::MAX)).unwrap();
1935 let twice = big.add(&big);
1936 assert_eq!(twice.numerator().to_string(), "2");
1937 assert_eq!(twice.denominator().to_string(), i64::MAX.to_string());
1938 let p = r(i64::MAX, 1).mul(&r(3, 1));
1940 assert_eq!(p.numerator().to_i64(), None);
1941 assert_eq!(p.numerator().to_string(), (i64::MAX as i128 * 3).to_string());
1942 }
1943
1944 #[test]
1945 fn rational_pow_handles_negative_and_zero_exponents() {
1946 assert_eq!(r(2, 3).pow(3).unwrap().to_string(), "8/27");
1947 assert_eq!(r(2, 3).pow(0).unwrap(), Rational::one());
1948 assert_eq!(r(2, 3).pow(-2).unwrap().to_string(), "9/4");
1949 assert_eq!(r(-2, 3).pow(-3).unwrap().to_string(), "-27/8");
1950 assert!(Rational::zero().pow(-1).is_none());
1951 assert_eq!(Rational::zero().pow(3).unwrap(), Rational::zero());
1952 }
1953
1954 #[test]
1955 fn rational_parse_round_trips_and_rejects_garbage() {
1956 assert_eq!(Rational::parse("3/4").unwrap().to_string(), "3/4");
1957 assert_eq!(Rational::parse("-3/4").unwrap().to_string(), "-3/4");
1958 assert_eq!(Rational::parse("6/8").unwrap().to_string(), "3/4");
1959 assert_eq!(Rational::parse("5").unwrap().to_string(), "5");
1960 assert_eq!(Rational::parse(" 7 / 14 ").unwrap().to_string(), "1/2");
1961 assert!(Rational::parse("abc").is_none());
1962 assert!(Rational::parse("1/2/3").is_none());
1963 }
1964
1965 #[test]
1966 fn rational_integer_predicate_and_narrowing() {
1967 assert!(r(10, 2).is_integer());
1968 assert_eq!(r(10, 2).to_i64(), Some(5));
1969 assert_eq!(r(10, 2).to_bigint().unwrap().to_string(), "5");
1970 assert!(!r(3, 4).is_integer());
1971 assert_eq!(r(3, 4).to_i64(), None);
1972 assert!(r(3, 4).to_bigint().is_none());
1973 }
1974
1975 #[test]
1976 fn rational_floor_and_ceil_round_toward_neg_and_pos_infinity() {
1977 assert_eq!(r(7, 2).floor().to_string(), "3");
1978 assert_eq!(r(7, 2).ceil().to_string(), "4");
1979 assert_eq!(r(-7, 2).floor().to_string(), "-4");
1980 assert_eq!(r(-7, 2).ceil().to_string(), "-3");
1981 assert_eq!(r(6, 2).floor().to_string(), "3");
1983 assert_eq!(r(6, 2).ceil().to_string(), "3");
1984 assert_eq!(r(7, 2).round().to_string(), "4");
1986 assert_eq!(r(-7, 2).round().to_string(), "-4");
1987 assert_eq!(r(1, 3).round().to_string(), "0");
1988 assert_eq!(r(2, 3).round().to_string(), "1");
1989 for n in -9i64..=9 {
1991 for d in 1i64..=9 {
1992 let q = r(n, d);
1993 assert_eq!(q.floor().to_i64(), Some((n as f64 / d as f64).floor() as i64), "{n}/{d} floor");
1994 assert_eq!(q.ceil().to_i64(), Some((n as f64 / d as f64).ceil() as i64), "{n}/{d} ceil");
1995 assert_eq!(q.round().to_i64(), Some((n as f64 / d as f64).round() as i64), "{n}/{d} round");
1996 }
1997 }
1998 }
1999
2000 #[test]
2001 fn rational_to_f64_matches_the_division_on_small_terms() {
2002 for n in -8i64..=8 {
2003 for d in 1i64..=8 {
2004 let approx = r(n, d).to_f64();
2005 assert!((approx - (n as f64 / d as f64)).abs() < 1e-12, "{n}/{d}");
2006 }
2007 }
2008 }
2009
2010 #[test]
2011 fn rational_obeys_the_field_laws_over_random_fractions() {
2012 let mut rng = Rng(0x5A7F_104E_2C19_8B63);
2015 for _ in 0..2000 {
2016 let pick = |rng: &mut Rng| -> i64 { (rng.next() % 4001) as i64 - 2000 };
2017 let (a, b, c, d, e, g) = (pick(&mut rng), pick(&mut rng), pick(&mut rng), pick(&mut rng), pick(&mut rng), pick(&mut rng));
2018 let (Some(x), Some(y), Some(z)) =
2019 (Rational::from_ratio_i64(a, b.max(1)), Rational::from_ratio_i64(c, d.max(1)), Rational::from_ratio_i64(e, g.max(1)))
2020 else { continue };
2021 assert_eq!(x.add(&y), y.add(&x));
2023 assert_eq!(x.mul(&y), y.mul(&x));
2024 assert_eq!(x.add(&y).add(&z), x.add(&y.add(&z)));
2026 assert_eq!(x.mul(&y).mul(&z), x.mul(&y.mul(&z)));
2027 assert_eq!(x.mul(&y.add(&z)), x.mul(&y).add(&x.mul(&z)));
2029 assert!(x.add(&x.negated()).is_zero());
2031 assert_eq!(x.sub(&y), x.add(&y.negated()));
2032 if !x.is_zero() {
2034 assert_eq!(x.mul(&x.recip().unwrap()), Rational::one());
2035 assert_eq!(y.div(&x).unwrap(), y.mul(&x.recip().unwrap()));
2036 }
2037 }
2038 }
2039
2040 fn dec(s: &str) -> Decimal {
2045 Decimal::parse(s).unwrap_or_else(|| panic!("parse decimal {s:?}"))
2046 }
2047
2048 #[test]
2049 fn decimal_parse_and_display_round_trip() {
2050 for s in ["0", "19.99", "0.05", "-0.005", "1999", "100.00", "-7", "0.10", "3.14159"] {
2051 assert_eq!(dec(s).to_string(), s, "round trip {s}");
2052 }
2053 assert_eq!(dec("-0").to_string(), "0");
2055 assert_eq!(dec("+5").to_string(), "5");
2056 assert_eq!(dec(".5").to_string(), "0.5");
2058 assert_eq!(dec("5.").to_string(), "5");
2059 assert!(Decimal::parse("1.2.3").is_none());
2061 assert!(Decimal::parse("abc").is_none());
2062 assert!(Decimal::parse("").is_none());
2063 assert!(Decimal::parse("-").is_none());
2064 assert!(Decimal::parse(".").is_none());
2065 }
2066
2067 #[test]
2068 fn decimal_has_no_binary_float_drift() {
2069 assert_ne!(0.1_f64 + 0.2, 0.3);
2071 assert_eq!(dec("0.1").add(&dec("0.2")), dec("0.3"));
2072 assert_eq!(dec("0.1").add(&dec("0.2")).to_string(), "0.3");
2073 }
2074
2075 #[test]
2076 fn decimal_add_sub_align_scales() {
2077 assert_eq!(dec("19.99").add(&dec("0.01")).to_string(), "20.00");
2078 assert_eq!(dec("1.1").add(&dec("2.22")).to_string(), "3.32");
2079 assert_eq!(dec("5").add(&dec("0.5")).to_string(), "5.5");
2080 assert_eq!(dec("20.00").sub(&dec("0.01")).to_string(), "19.99");
2081 assert_eq!(dec("0").sub(&dec("0.005")).to_string(), "-0.005");
2082 }
2083
2084 #[test]
2085 fn decimal_mul_adds_scales_and_is_exact() {
2086 assert_eq!(dec("1.1").mul(&dec("1.1")).to_string(), "1.21");
2087 assert_eq!(dec("0.05").mul(&dec("0.05")).to_string(), "0.0025");
2088 assert_eq!(dec("19.99").mul(&Decimal::from_i64(3)).to_string(), "59.97");
2089 assert_eq!(dec("-2.5").mul(&dec("4")).to_string(), "-10.0");
2090 }
2091
2092 #[test]
2093 fn decimal_div_rounds_to_scale() {
2094 assert_eq!(dec("10").div(&dec("3"), 2, RoundingMode::HalfEven).unwrap().to_string(), "3.33");
2096 assert_eq!(dec("1").div(&dec("8"), 3, RoundingMode::HalfEven).unwrap().to_string(), "0.125");
2098 assert_eq!(dec("1").div(&dec("8"), 2, RoundingMode::HalfEven).unwrap().to_string(), "0.12");
2100 assert_eq!(dec("1").div(&dec("8"), 2, RoundingMode::HalfUp).unwrap().to_string(), "0.13");
2101 assert!(dec("1").div(&dec("0"), 2, RoundingMode::HalfEven).is_none());
2103 }
2104
2105 #[test]
2106 fn decimal_rescale_quantizes_with_rounding() {
2107 assert_eq!(dec("19.999").rescale(2, RoundingMode::HalfEven).to_string(), "20.00");
2108 assert_eq!(dec("2.5").rescale(0, RoundingMode::HalfEven).to_string(), "2");
2110 assert_eq!(dec("3.5").rescale(0, RoundingMode::HalfEven).to_string(), "4");
2111 assert_eq!(dec("-2.5").rescale(0, RoundingMode::HalfEven).to_string(), "-2");
2112 assert_eq!(dec("1.5").rescale(4, RoundingMode::HalfEven).to_string(), "1.5000");
2114 }
2115
2116 #[test]
2117 fn decimal_rounding_modes_on_a_tie_and_a_non_tie() {
2118 let tie = dec("2.5");
2120 for (mode, want) in [
2121 (RoundingMode::Down, "2"),
2122 (RoundingMode::Up, "3"),
2123 (RoundingMode::Floor, "2"),
2124 (RoundingMode::Ceiling, "3"),
2125 (RoundingMode::HalfUp, "3"),
2126 (RoundingMode::HalfDown, "2"),
2127 (RoundingMode::HalfEven, "2"),
2128 ] {
2129 assert_eq!(tie.rescale(0, mode).to_string(), want, "2.5 under {mode:?}");
2130 }
2131 let ntie = dec("-2.5");
2133 assert_eq!(ntie.rescale(0, RoundingMode::Floor).to_string(), "-3");
2134 assert_eq!(ntie.rescale(0, RoundingMode::Ceiling).to_string(), "-2");
2135 assert_eq!(ntie.rescale(0, RoundingMode::HalfUp).to_string(), "-3");
2136 assert_eq!(ntie.rescale(0, RoundingMode::Down).to_string(), "-2");
2137 }
2138
2139 #[test]
2140 fn decimal_equality_is_value_based_and_hash_agrees() {
2141 use std::collections::HashSet;
2142 assert_eq!(dec("1.0"), dec("1.00"));
2144 assert_eq!(dec("1.0"), dec("1"));
2145 assert_eq!(dec("0.0"), dec("0"));
2146 let mut set = HashSet::new();
2148 set.insert(dec("1.00"));
2149 assert!(set.contains(&dec("1")));
2150 assert!(set.contains(&dec("1.0")));
2151 assert_ne!(dec("1.0"), dec("1.01"));
2153 }
2154
2155 #[test]
2156 fn decimal_ordering_compares_across_scales_without_rounding() {
2157 assert!(dec("0.1") < dec("0.11"));
2158 assert!(dec("1.5") < dec("2"));
2159 assert!(dec("-0.005") < dec("0"));
2160 assert!(dec("1.00") == dec("1.0"));
2161 let mut v = vec![dec("0.5"), dec("0.05"), dec("-0.1"), dec("2"), dec("0.50")];
2162 v.sort();
2163 let s: Vec<String> = v.iter().map(|x| x.to_string()).collect();
2164 assert_eq!(s, ["-0.1", "0.05", "0.5", "0.50", "2"]);
2166 }
2167
2168 #[test]
2169 fn decimal_to_and_from_rational_is_exact() {
2170 assert_eq!(dec("19.99").to_rational(), Rational::from_ratio_i64(1999, 100).unwrap());
2171 assert_eq!(dec("0.125").to_rational(), Rational::from_ratio_i64(1, 8).unwrap());
2172 assert_eq!(dec("-0.005").to_rational(), Rational::from_ratio_i64(-1, 200).unwrap());
2173 let third = Rational::from_ratio_i64(1, 3).unwrap();
2175 assert_eq!(Decimal::from_rational(&third, 4, RoundingMode::HalfEven).to_string(), "0.3333");
2176 }
2177
2178 #[test]
2179 fn decimal_wire_components_round_trip() {
2180 for s in ["0", "19.99", "-0.005", "100.00", "123456789.000001", "-7"] {
2181 let d = dec(s);
2182 let (neg, bytes, scale) = d.to_le_bytes();
2183 let back = Decimal::from_le_bytes(neg, &bytes, scale);
2184 assert_eq!(back, d, "value round-trip {s}");
2185 assert_eq!(back.to_string(), d.to_string(), "display round-trip {s}");
2186 }
2187 }
2188
2189 #[test]
2190 fn decimal_money_scenario_is_exact() {
2191 let subtotal = dec("19.99").mul(&Decimal::from_i64(3)); assert_eq!(subtotal.to_string(), "59.97");
2194 let tax = subtotal.mul(&dec("0.08")).rescale(2, RoundingMode::HalfEven); assert_eq!(tax.to_string(), "4.80");
2196 assert_eq!(subtotal.add(&tax).to_string(), "64.77");
2197 }
2198
2199 #[test]
2200 fn decimal_add_sub_mul_match_the_rational_oracle_under_fuzz() {
2201 let mut rng = Rng(0xDEC1_2A1B_0000_FACE);
2204 for _ in 0..3000 {
2205 let ca = (rng.next() % 2_000_001) as i64 - 1_000_000;
2206 let cb = (rng.next() % 2_000_001) as i64 - 1_000_000;
2207 let sa = (rng.next() % 6) as u32;
2208 let sb = (rng.next() % 6) as u32;
2209 let a = Decimal::from_coeff_scale(BigInt::from_i64(ca), sa);
2210 let b = Decimal::from_coeff_scale(BigInt::from_i64(cb), sb);
2211 let (ra, rb) = (a.to_rational(), b.to_rational());
2212 assert_eq!(a.add(&b).to_rational(), ra.add(&rb), "add {a} {b}");
2213 assert_eq!(a.sub(&b).to_rational(), ra.sub(&rb), "sub {a} {b}");
2214 assert_eq!(a.mul(&b).to_rational(), ra.mul(&rb), "mul {a} {b}");
2215 if !b.is_zero() {
2217 let scale = 8u32;
2218 let q = a.div(&b, scale, RoundingMode::HalfEven).unwrap();
2219 let exact = ra.div(&rb).unwrap();
2220 let ulp = Rational::new(BigInt::from_i64(1), BigInt::from_u64(10).pow(scale)).unwrap();
2221 let err = q.to_rational().sub(&exact).abs();
2222 assert!(err.mul(&Rational::from_i64(2)) <= ulp, "div within half-ulp {a}/{b}");
2224 }
2225 }
2226 }
2227
2228 fn c(re: i64, im: i64) -> Complex {
2233 Complex::new(Rational::from_i64(re), Rational::from_i64(im))
2234 }
2235
2236 fn cq(rn: i64, rd: i64, in_: i64, id: i64) -> Complex {
2237 Complex::new(Rational::from_ratio_i64(rn, rd).unwrap(), Rational::from_ratio_i64(in_, id).unwrap())
2238 }
2239
2240 #[test]
2241 fn complex_i_squared_is_minus_one() {
2242 assert_eq!(Complex::i().mul(&Complex::i()), c(-1, 0));
2244 assert_eq!(Complex::i().mul(&Complex::i()), Complex::from_i64(-1));
2245 }
2246
2247 #[test]
2248 fn complex_construction_and_accessors() {
2249 let z = c(3, 4);
2250 assert_eq!(z.re(), &Rational::from_i64(3));
2251 assert_eq!(z.im(), &Rational::from_i64(4));
2252 assert!(!z.is_real());
2253 assert!(c(5, 0).is_real());
2254 assert!(Complex::zero().is_zero());
2255 assert!(!Complex::i().is_zero());
2256 assert_eq!(Complex::from_i64(7), c(7, 0));
2257 }
2258
2259 #[test]
2260 fn complex_add_sub_mul_are_exact() {
2261 assert_eq!(c(2, 3).add(&c(1, -1)), c(3, 2));
2262 assert_eq!(c(2, 3).sub(&c(1, -1)), c(1, 4));
2263 assert_eq!(c(1, 1).mul(&c(1, -1)), c(2, 0));
2265 assert_eq!(c(2, 3).mul(&c(4, 5)), c(-7, 22));
2267 }
2268
2269 #[test]
2270 fn complex_div_recip_and_zero_guard() {
2271 assert_eq!(c(2, 3).div(&c(2, 3)).unwrap(), Complex::one());
2273 assert_eq!(Complex::i().recip().unwrap(), c(0, -1));
2275 assert_eq!(c(3, 4).div(&c(1, 2)).unwrap(), cq(11, 5, -2, 5));
2277 assert!(c(1, 1).div(&Complex::zero()).is_none());
2279 assert!(Complex::zero().recip().is_none());
2280 }
2281
2282 #[test]
2283 fn complex_conjugate_and_norm_are_exact() {
2284 assert_eq!(c(3, 4).conjugate(), c(3, -4));
2285 assert_eq!(c(3, 4).norm_sqr(), Rational::from_i64(25));
2286 assert!((c(3, 4).abs_f64() - 5.0).abs() < 1e-12);
2288 let z = c(2, -5);
2290 assert_eq!(z.mul(&z.conjugate()), Complex::from_rational(z.norm_sqr()));
2291 }
2292
2293 #[test]
2294 fn complex_pow_handles_the_cycle_and_negatives() {
2295 assert_eq!(Complex::i().pow(2).unwrap(), c(-1, 0));
2296 assert_eq!(Complex::i().pow(3).unwrap(), c(0, -1));
2297 assert_eq!(Complex::i().pow(4).unwrap(), c(1, 0));
2298 assert_eq!(Complex::i().pow(0).unwrap(), Complex::one());
2299 assert_eq!(Complex::i().pow(-1).unwrap(), c(0, -1)); assert_eq!(c(1, 1).pow(2).unwrap(), c(0, 2));
2302 assert_eq!(Complex::zero().pow(0).unwrap(), Complex::one());
2304 assert!(Complex::zero().pow(-1).is_none());
2305 }
2306
2307 #[test]
2308 fn complex_display_round_trips_every_form() {
2309 for (z, want) in [
2310 (c(0, 0), "0"),
2311 (c(3, 0), "3"),
2312 (c(0, 1), "i"),
2313 (c(0, -1), "-i"),
2314 (c(0, 4), "4i"),
2315 (c(0, -4), "-4i"),
2316 (c(3, 4), "3+4i"),
2317 (c(3, -4), "3-4i"),
2318 (c(3, 1), "3+i"),
2319 (c(3, -1), "3-i"),
2320 (c(-2, 5), "-2+5i"),
2321 ] {
2322 assert_eq!(z.to_string(), want, "display");
2323 assert_eq!(Complex::parse(want).unwrap(), z, "parse round-trip of {want}");
2324 }
2325 let z = cq(1, 2, -3, 4);
2327 assert_eq!(z.to_string(), "1/2-3/4i");
2328 assert_eq!(Complex::parse("1/2-3/4i").unwrap(), z);
2329 assert!(Complex::parse("").is_none());
2331 assert!(Complex::parse("3+xi").is_none());
2332 }
2333
2334 #[test]
2335 fn complex_equality_and_hash_are_structural() {
2336 use std::collections::HashSet;
2337 assert_eq!(c(3, 4), c(3, 4));
2338 assert_ne!(c(3, 4), c(3, -4));
2339 assert_eq!(cq(2, 4, 6, 8), cq(1, 2, 3, 4)); let mut set = HashSet::new();
2341 set.insert(cq(2, 4, 6, 8));
2342 assert!(set.contains(&cq(1, 2, 3, 4)));
2343 }
2344
2345 #[test]
2346 fn complex_obeys_the_field_laws_under_fuzz() {
2347 let mut rng = Rng(0xC011_9EE5_A11C_E5ED);
2350 let pick = |rng: &mut Rng| -> Rational {
2351 let n = (rng.next() % 41) as i64 - 20;
2352 let d = ((rng.next() % 9) as i64) + 1;
2353 Rational::from_ratio_i64(n, d).unwrap()
2354 };
2355 let pick_c = |rng: &mut Rng| -> Complex { Complex::new(pick(rng), pick(rng)) };
2356 for _ in 0..2000 {
2357 let (x, y, z) = (pick_c(&mut rng), pick_c(&mut rng), pick_c(&mut rng));
2358 assert_eq!(x.add(&y), y.add(&x));
2360 assert_eq!(x.mul(&y), y.mul(&x));
2361 assert_eq!(x.add(&y).add(&z), x.add(&y.add(&z)));
2363 assert_eq!(x.mul(&y).mul(&z), x.mul(&y.mul(&z)));
2364 assert_eq!(x.mul(&y.add(&z)), x.mul(&y).add(&x.mul(&z)));
2366 assert!(x.add(&x.negated()).is_zero());
2368 assert_eq!(x.sub(&y), x.add(&y.negated()));
2369 assert_eq!(x.conjugate().conjugate(), x);
2371 assert_eq!(x.mul(&y).conjugate(), x.conjugate().mul(&y.conjugate()));
2372 assert_eq!(x.mul(&y).norm_sqr(), x.norm_sqr().mul(&y.norm_sqr()));
2374 if !x.is_zero() {
2376 assert_eq!(x.mul(&x.recip().unwrap()), Complex::one());
2377 assert_eq!(y.div(&x).unwrap(), y.mul(&x.recip().unwrap()));
2378 }
2379 }
2380 }
2381
2382 fn m(v: i64, n: i64) -> Modular {
2387 Modular::from_i64(v, n).unwrap_or_else(|| panic!("bad modulus {n}"))
2388 }
2389
2390 #[test]
2391 fn modular_reduces_into_range_on_construction() {
2392 assert_eq!(m(10, 7).value().to_i64(), Some(3));
2393 assert_eq!(m(7, 7).value().to_i64(), Some(0));
2394 assert_eq!(m(-1, 7).value().to_i64(), Some(6));
2396 assert_eq!(m(-10, 7).value().to_i64(), Some(4));
2397 assert_eq!(m(5, 1).value().to_i64(), Some(0));
2399 assert!(Modular::from_i64(3, 0).is_none());
2401 assert!(Modular::from_i64(3, -7).is_none());
2402 }
2403
2404 #[test]
2405 fn modular_arithmetic_wraps_in_the_ring() {
2406 assert_eq!(m(5, 7).add(&m(4, 7)).unwrap(), m(2, 7)); assert_eq!(m(3, 7).sub(&m(5, 7)).unwrap(), m(5, 7)); assert_eq!(m(4, 7).mul(&m(5, 7)).unwrap(), m(6, 7)); assert_eq!(m(3, 7).negated(), m(4, 7));
2412 assert!(m(3, 7).add(&m(3, 7).negated()).unwrap().is_zero());
2413 assert!(m(3, 7).add(&m(3, 5)).is_none());
2415 assert!(m(3, 7).mul(&m(3, 5)).is_none());
2416 }
2417
2418 #[test]
2419 fn modular_exponentiation_is_fast_and_exact() {
2420 assert_eq!(m(3, 5).pow(4), m(1, 5)); assert_eq!(m(2, 7).pow(3), m(1, 7)); assert_eq!(m(5, 13).pow(0), m(1, 13)); let mut acc = m(1, 13);
2425 for _ in 0..100 {
2426 acc = acc.mul(&m(7, 13)).unwrap();
2427 }
2428 assert_eq!(m(7, 13).pow(100), acc);
2429 }
2430
2431 #[test]
2432 fn modular_inverse_and_division() {
2433 assert_eq!(m(3, 7).inverse().unwrap(), m(5, 7));
2435 assert_eq!(m(3, 7).mul(&m(3, 7).inverse().unwrap()).unwrap(), m(1, 7));
2436 assert_eq!(m(1, 7).div(&m(3, 7)).unwrap(), m(5, 7));
2438 assert_eq!(m(4, 7).div(&m(2, 7)).unwrap(), m(2, 7));
2439 assert!(m(2, 4).inverse().is_none());
2441 assert!(m(1, 4).div(&m(2, 4)).is_none());
2442 assert!(m(1, 7).div(&m(3, 5)).is_none());
2444 }
2445
2446 #[test]
2447 fn modular_generalizes_the_word_wrapping_ring() {
2448 let modulus = 1i64 << 32; let (a, b) = (4_000_000_000u32, 1_000_000_000u32); let word_add = (crate::Word32(a) + crate::Word32(b)).0 as i64;
2452 let mod_add = m(a as i64, modulus).add(&m(b as i64, modulus)).unwrap();
2453 assert_eq!(mod_add.value().to_i64(), Some(word_add), "ℤ/2³² add == Word32 add");
2454 let word_mul = (crate::Word32(a) * crate::Word32(b)).0 as i64;
2455 let mod_mul = m(a as i64, modulus).mul(&m(b as i64, modulus)).unwrap();
2456 assert_eq!(mod_mul.value().to_i64(), Some(word_mul), "ℤ/2³² mul == Word32 mul");
2457 }
2458
2459 #[test]
2460 fn modular_equality_is_per_ring_and_displays_the_modulus() {
2461 assert_ne!(m(3, 7), m(3, 5));
2463 assert_eq!(m(10, 7), m(3, 7));
2464 assert_eq!(m(3, 7).to_string(), "3 (mod 7)");
2465 assert_eq!(m(-1, 7).to_string(), "6 (mod 7)");
2466 }
2467
2468 #[test]
2469 fn modular_obeys_fermats_little_theorem() {
2470 for &p in &[2i64, 3, 5, 7, 13, 97, 101] {
2472 for a in 1..p.min(40) {
2473 assert_eq!(m(a, p).pow((p - 1) as u64), m(1, p), "{a}^({p}-1) ≡ 1 (mod {p})");
2474 }
2475 }
2476 }
2477
2478 #[test]
2479 fn modular_obeys_the_ring_laws_and_inverse_under_fuzz() {
2480 let mut rng = Rng(0x_0DDF_ACE5_ABCD_1234);
2483 for _ in 0..3000 {
2484 let n = ((rng.next() % 50) as i64) + 2; let pick = |rng: &mut Rng| (rng.next() % 1_000_000) as i64 - 500_000;
2486 let (a, b, c) = (m(pick(&mut rng), n), m(pick(&mut rng), n), m(pick(&mut rng), n));
2487 assert_eq!(a.add(&b).unwrap(), b.add(&a).unwrap());
2489 assert_eq!(a.mul(&b).unwrap(), b.mul(&a).unwrap());
2490 assert_eq!(a.add(&b).unwrap().add(&c).unwrap(), a.add(&b.add(&c).unwrap()).unwrap());
2492 assert_eq!(a.mul(&b).unwrap().mul(&c).unwrap(), a.mul(&b.mul(&c).unwrap()).unwrap());
2493 assert_eq!(
2495 a.mul(&b.add(&c).unwrap()).unwrap(),
2496 a.mul(&b).unwrap().add(&a.mul(&c).unwrap()).unwrap()
2497 );
2498 assert!(a.add(&a.negated()).unwrap().is_zero());
2500 if let Some(inv) = a.inverse() {
2502 assert_eq!(a.mul(&inv).unwrap(), m(1, n), "a·a⁻¹ = 1 in ℤ/{n}ℤ");
2503 }
2504 }
2505 }
2506
2507 #[test]
2510 fn exact_rational_from_f64_values() {
2511 assert_eq!(rational_from_f64_exact(0.5).unwrap(), Rational::from_ratio_i64(1, 2).unwrap());
2512 assert_eq!(rational_from_f64_exact(3.0).unwrap(), Rational::from_i64(3));
2513 assert_eq!(rational_from_f64_exact(-2.25).unwrap(), Rational::from_ratio_i64(-9, 4).unwrap());
2514 assert_eq!(rational_from_f64_exact(0.0).unwrap(), Rational::zero());
2515 assert_eq!(rational_from_f64_exact(-0.0).unwrap(), Rational::zero());
2516 assert!(rational_from_f64_exact(f64::NAN).is_none());
2517 assert!(rational_from_f64_exact(f64::INFINITY).is_none());
2518 assert_ne!(rational_from_f64_exact(0.1).unwrap(), Rational::from_ratio_i64(1, 10).unwrap());
2520 }
2521
2522 #[test]
2523 fn exact_i64_f64_cmp_at_the_representability_boundary() {
2524 let big = 9_007_199_254_740_993_i64; let f = 9_007_199_254_740_992.0_f64; assert_eq!(cmp_i64_f64_exact(big, f), Some(Ordering::Greater));
2528 assert_eq!(cmp_i64_f64_exact(big - 1, f), Some(Ordering::Equal));
2529 assert_eq!(cmp_i64_f64_exact(3, 3.5), Some(Ordering::Less));
2530 assert_eq!(cmp_i64_f64_exact(4, 3.5), Some(Ordering::Greater));
2531 assert_eq!(cmp_i64_f64_exact(1, 1.0), Some(Ordering::Equal));
2532 assert_eq!(cmp_i64_f64_exact(0, f64::NAN), None);
2533 assert_eq!(cmp_i64_f64_exact(i64::MAX, f64::INFINITY), Some(Ordering::Less));
2534 assert_eq!(cmp_i64_f64_exact(i64::MIN, f64::NEG_INFINITY), Some(Ordering::Greater));
2535 }
2536
2537 #[test]
2538 fn unified_numeric_hash_coherence() {
2539 for k in [0i64, 1, -1, 2, 42, -42, 1_000_000_007, -(1i64 << 53), 1i64 << 53] {
2541 assert_eq!(
2542 numeric_hash_i64(k),
2543 numeric_hash_f64(k as f64),
2544 "int/float hash mismatch at {k}"
2545 );
2546 assert_eq!(
2547 numeric_hash_i64(k),
2548 numeric_hash_bigint(&BigInt::from_i64(k)),
2549 "int/bigint hash mismatch at {k}"
2550 );
2551 assert_eq!(
2552 numeric_hash_i64(k),
2553 numeric_hash_rational(&Rational::from_i64(k)),
2554 "int/rational hash mismatch at {k}"
2555 );
2556 }
2557 assert_eq!(
2559 numeric_hash_f64(0.5),
2560 numeric_hash_rational(&Rational::from_ratio_i64(1, 2).unwrap())
2561 );
2562 assert_eq!(
2563 numeric_hash_f64(-2.25),
2564 numeric_hash_rational(&Rational::from_ratio_i64(-9, 4).unwrap())
2565 );
2566 assert_eq!(numeric_hash_f64(-0.0), numeric_hash_f64(0.0));
2568 assert_eq!(
2571 numeric_hash_f64(0.1),
2572 numeric_hash_rational(&rational_from_f64_exact(0.1).unwrap())
2573 );
2574 }
2575
2576 #[test]
2579 fn arithmetic_is_exact_across_the_one_limb_boundary() {
2580 let u64max = BigInt::from_u64(u64::MAX);
2581 let two64 = u64max.add(&b(1)); assert_eq!(two64.to_string(), "18446744073709551616");
2583 assert_eq!(two64.sub(&b(1)), u64max);
2585 let two32 = b(1i64 << 32);
2587 assert_eq!(two32.mul(&two32), two64);
2588 assert_eq!(b(1i64 << 62).mul(&b(4)), two64);
2589 let (q, r) = two64.div_rem(&b(2)).expect("nonzero divisor");
2591 assert!(r.is_zero());
2592 assert_eq!(q.to_string(), "9223372036854775808");
2593 let neg = two64.negated();
2595 assert_eq!(neg.add(&two64), BigInt::zero());
2596 assert_eq!(neg.to_string(), "-18446744073709551616");
2597 }
2598
2599 #[test]
2600 fn ordering_and_hash_are_canonical_across_the_limb_boundary() {
2601 let two64 = BigInt::from_u64(u64::MAX).add(&b(1));
2602 let big = two64.mul(&two64); assert!(b(1) < two64);
2604 assert!(two64 < big);
2605 assert!(big.negated() < b(-1));
2606 assert!(two64.negated() < two64);
2607 let via_mul = b(1i64 << 32).mul(&b(1i64 << 32));
2610 let via_add = BigInt::from_u64(u64::MAX).add(&b(1));
2611 assert_eq!(via_mul, via_add);
2612 use std::collections::hash_map::DefaultHasher;
2613 use std::hash::{Hash, Hasher};
2614 let h = |v: &BigInt| {
2615 let mut s = DefaultHasher::new();
2616 v.hash(&mut s);
2617 s.finish()
2618 };
2619 assert_eq!(h(&via_mul), h(&via_add));
2620 let shrunk = two64.sub(&b(1));
2622 assert_eq!(shrunk, BigInt::from_u64(u64::MAX));
2623 assert_eq!(h(&shrunk), h(&BigInt::from_u64(u64::MAX)));
2624 }
2625
2626 #[test]
2627 fn le_bytes_round_trip_across_the_limb_boundary() {
2628 for s in [
2629 "0",
2630 "1",
2631 "-1",
2632 "18446744073709551615",
2633 "18446744073709551616",
2634 "-18446744073709551616",
2635 "340282366920938463463374607431768211456",
2636 ] {
2637 let v = BigInt::parse_decimal(s).expect("valid decimal");
2638 let (neg, bytes) = v.to_le_bytes();
2639 assert_eq!(BigInt::from_le_bytes(neg, &bytes), v, "round trip {s}");
2640 assert_eq!(v.to_string(), s, "display {s}");
2641 }
2642 }
2643
2644 #[test]
2645 fn div_rem_identity_holds_for_multi_limb_values() {
2646 let a = b(1_000_003).pow(7); for dividend in [a.clone(), a.negated()] {
2650 for divisor in [b(97), b(-97), b(1i64 << 40), a.sub(&b(1))] {
2651 let (q, r) = dividend.div_rem(&divisor).expect("nonzero divisor");
2652 assert_eq!(dividend, q.mul(&divisor).add(&r));
2653 assert!(r.abs() < divisor.abs());
2654 assert!(r.is_zero() || r.is_negative() == dividend.is_negative());
2655 }
2656 }
2657 }
2658}