qualia_core_db/solvers/exact/
bigint.rs1use core::cmp::Ordering;
19use core::fmt;
20
21const BASE_BITS: u32 = 32;
22const BASE: u64 = 1u64 << BASE_BITS; #[derive(Clone, PartialEq, Eq)]
26pub struct BigInt {
27 sign: i8,
29 mag: Vec<u32>,
31}
32
33impl BigInt {
34 pub fn zero() -> Self {
36 BigInt {
37 sign: 0,
38 mag: Vec::new(),
39 }
40 }
41
42 pub fn one() -> Self {
44 BigInt {
45 sign: 1,
46 mag: vec![1],
47 }
48 }
49
50 pub fn from_i64(mut v: i64) -> Self {
52 if v == 0 {
53 return BigInt::zero();
54 }
55 let sign: i8 = if v < 0 { -1 } else { 1 };
56 let mut uv: u64 = if v < 0 {
58 (v as i128).unsigned_abs() as u64
60 } else {
61 v as u64
62 };
63 v = 0; let _ = v;
65 let mut mag = Vec::new();
66 while uv > 0 {
67 mag.push((uv & 0xFFFF_FFFF) as u32);
68 uv >>= BASE_BITS;
69 }
70 let mut out = BigInt { sign, mag };
71 out.normalize();
72 out
73 }
74
75 pub fn from_u64(mut v: u64) -> Self {
77 if v == 0 {
78 return BigInt::zero();
79 }
80 let mut mag = Vec::new();
81 while v > 0 {
82 mag.push((v & 0xFFFF_FFFF) as u32);
83 v >>= BASE_BITS;
84 }
85 BigInt { sign: 1, mag }
86 }
87
88 pub fn from_str(s: &str) -> Option<Self> {
91 let s = s.trim();
92 if s.is_empty() {
93 return None;
94 }
95 let (sign, digits) = match s.as_bytes()[0] {
96 b'+' => (1i8, &s[1..]),
97 b'-' => (-1i8, &s[1..]),
98 _ => (1i8, s),
99 };
100 if digits.is_empty() {
101 return None;
102 }
103 let mut acc = BigInt::zero();
104 let ten = BigInt::from_u64(10);
105 for ch in digits.bytes() {
106 if !ch.is_ascii_digit() {
107 return None;
108 }
109 let d = BigInt::from_u64((ch - b'0') as u64);
110 acc = acc.mul(&ten).add(&d);
111 }
112 if acc.is_zero() {
113 return Some(BigInt::zero());
115 }
116 acc.sign = sign;
117 Some(acc)
118 }
119
120 pub fn to_string(&self) -> String {
122 if self.is_zero() {
123 return "0".to_string();
124 }
125 let chunk = 1_000_000_000u64; let mut limbs = self.mag.clone();
129 let mut groups: Vec<u32> = Vec::new();
130 while !limbs.is_empty() {
131 let mut rem: u64 = 0;
132 for i in (0..limbs.len()).rev() {
134 let cur = (rem << BASE_BITS) | limbs[i] as u64;
135 limbs[i] = (cur / chunk) as u32;
136 rem = cur % chunk;
137 }
138 while let Some(&0) = limbs.last() {
140 limbs.pop();
141 }
142 groups.push(rem as u32);
143 }
144 let mut out = String::new();
145 if self.sign < 0 {
146 out.push('-');
147 }
148 let last = groups.len() - 1;
150 out.push_str(&groups[last].to_string());
151 for i in (0..last).rev() {
152 out.push_str(&format!("{:09}", groups[i]));
153 }
154 out
155 }
156
157 pub fn is_zero(&self) -> bool {
159 self.sign == 0
160 }
161
162 pub fn is_negative(&self) -> bool {
164 self.sign < 0
165 }
166
167 pub fn signum(&self) -> i8 {
169 self.sign
170 }
171
172 pub fn abs(&self) -> Self {
174 BigInt {
175 sign: if self.sign == 0 { 0 } else { 1 },
176 mag: self.mag.clone(),
177 }
178 }
179
180 pub fn neg(&self) -> Self {
182 BigInt {
183 sign: -self.sign,
184 mag: self.mag.clone(),
185 }
186 }
187
188 fn normalize(&mut self) {
191 while let Some(&0) = self.mag.last() {
192 self.mag.pop();
193 }
194 if self.mag.is_empty() {
195 self.sign = 0;
196 } else if self.sign == 0 {
197 self.sign = 1;
198 }
199 }
200
201 fn cmp_mag(a: &[u32], b: &[u32]) -> Ordering {
205 if a.len() != b.len() {
206 return a.len().cmp(&b.len());
207 }
208 for i in (0..a.len()).rev() {
209 if a[i] != b[i] {
210 return a[i].cmp(&b[i]);
211 }
212 }
213 Ordering::Equal
214 }
215
216 fn add_mag(a: &[u32], b: &[u32]) -> Vec<u32> {
218 let (long, short) = if a.len() >= b.len() { (a, b) } else { (b, a) };
219 let mut out = Vec::with_capacity(long.len() + 1);
220 let mut carry: u64 = 0;
221 for i in 0..long.len() {
222 let mut sum = long[i] as u64 + carry;
223 if i < short.len() {
224 sum += short[i] as u64;
225 }
226 out.push((sum & 0xFFFF_FFFF) as u32);
227 carry = sum >> BASE_BITS;
228 }
229 if carry > 0 {
230 out.push(carry as u32);
231 }
232 out
233 }
234
235 fn sub_mag(a: &[u32], b: &[u32]) -> Vec<u32> {
237 debug_assert!(Self::cmp_mag(a, b) != Ordering::Less);
238 let mut out = Vec::with_capacity(a.len());
239 let mut borrow: i64 = 0;
240 for i in 0..a.len() {
241 let bi = if i < b.len() { b[i] as i64 } else { 0 };
242 let mut diff = a[i] as i64 - bi - borrow;
243 if diff < 0 {
244 diff += BASE as i64;
245 borrow = 1;
246 } else {
247 borrow = 0;
248 }
249 out.push(diff as u32);
250 }
251 while let Some(&0) = out.last() {
252 out.pop();
253 }
254 out
255 }
256
257 fn mul_mag(a: &[u32], b: &[u32]) -> Vec<u32> {
259 if a.is_empty() || b.is_empty() {
260 return Vec::new();
261 }
262 let mut out = vec![0u32; a.len() + b.len()];
263 for i in 0..a.len() {
264 let mut carry: u64 = 0;
265 let ai = a[i] as u64;
266 for j in 0..b.len() {
267 let idx = i + j;
268 let cur = out[idx] as u64 + ai * b[j] as u64 + carry;
269 out[idx] = (cur & 0xFFFF_FFFF) as u32;
270 carry = cur >> BASE_BITS;
271 }
272 let mut idx = i + b.len();
274 while carry > 0 {
275 let cur = out[idx] as u64 + carry;
276 out[idx] = (cur & 0xFFFF_FFFF) as u32;
277 carry = cur >> BASE_BITS;
278 idx += 1;
279 }
280 }
281 while let Some(&0) = out.last() {
282 out.pop();
283 }
284 out
285 }
286
287 pub fn add(&self, other: &BigInt) -> BigInt {
291 if self.is_zero() {
292 return other.clone();
293 }
294 if other.is_zero() {
295 return self.clone();
296 }
297 if self.sign == other.sign {
298 let mag = Self::add_mag(&self.mag, &other.mag);
299 let mut r = BigInt {
300 sign: self.sign,
301 mag,
302 };
303 r.normalize();
304 r
305 } else {
306 match Self::cmp_mag(&self.mag, &other.mag) {
308 Ordering::Equal => BigInt::zero(),
309 Ordering::Greater => {
310 let mag = Self::sub_mag(&self.mag, &other.mag);
311 let mut r = BigInt {
312 sign: self.sign,
313 mag,
314 };
315 r.normalize();
316 r
317 }
318 Ordering::Less => {
319 let mag = Self::sub_mag(&other.mag, &self.mag);
320 let mut r = BigInt {
321 sign: other.sign,
322 mag,
323 };
324 r.normalize();
325 r
326 }
327 }
328 }
329 }
330
331 pub fn sub(&self, other: &BigInt) -> BigInt {
333 self.add(&other.neg())
334 }
335
336 pub fn mul(&self, other: &BigInt) -> BigInt {
338 if self.is_zero() || other.is_zero() {
339 return BigInt::zero();
340 }
341 let mag = Self::mul_mag(&self.mag, &other.mag);
342 let mut r = BigInt {
343 sign: self.sign * other.sign,
344 mag,
345 };
346 r.normalize();
347 r
348 }
349
350 pub fn divmod(&self, divisor: &BigInt) -> Option<(BigInt, BigInt)> {
355 if divisor.is_zero() {
356 return None; }
358 if self.is_zero() {
359 return Some((BigInt::zero(), BigInt::zero()));
360 }
361 if Self::cmp_mag(&self.mag, &divisor.mag) == Ordering::Less {
363 return Some((BigInt::zero(), self.clone()));
364 }
365 let (q_mag, r_mag) = Self::divmod_mag(&self.mag, &divisor.mag);
366 let mut q = BigInt {
367 sign: self.sign * divisor.sign,
368 mag: q_mag,
369 };
370 let mut r = BigInt {
371 sign: self.sign,
372 mag: r_mag,
373 };
374 q.normalize();
375 r.normalize();
376 Some((q, r))
377 }
378
379 pub fn div(&self, divisor: &BigInt) -> Option<BigInt> {
381 self.divmod(divisor).map(|(q, _)| q)
382 }
383
384 pub fn rem(&self, divisor: &BigInt) -> Option<BigInt> {
386 self.divmod(divisor).map(|(_, r)| r)
387 }
388
389 fn divmod_mag(a: &[u32], b: &[u32]) -> (Vec<u32>, Vec<u32>) {
392 if b.len() == 1 {
394 let d = b[0] as u64;
395 let mut q = vec![0u32; a.len()];
396 let mut rem: u64 = 0;
397 for i in (0..a.len()).rev() {
398 let cur = (rem << BASE_BITS) | a[i] as u64;
399 q[i] = (cur / d) as u32;
400 rem = cur % d;
401 }
402 while let Some(&0) = q.last() {
403 q.pop();
404 }
405 let r = if rem == 0 {
406 Vec::new()
407 } else {
408 vec![rem as u32]
409 };
410 return (q, r);
411 }
412
413 let shift = b[b.len() - 1].leading_zeros();
415 let bn = Self::shl_bits(b, shift);
416 let mut an = Self::shl_bits(a, shift);
417 if an.len() == a.len() {
419 an.push(0);
420 }
421 let n = bn.len();
422 let m = an.len() - n; let mut q = vec![0u32; m];
424
425 let b_high = bn[n - 1] as u64;
426 let b_second = bn[n - 2] as u64;
427
428 for j in (0..m).rev() {
429 let top = ((an[j + n] as u64) << BASE_BITS) | an[j + n - 1] as u64;
431 let mut q_hat = top / b_high;
432 let mut r_hat = top % b_high;
433 while q_hat >= BASE || q_hat * b_second > (r_hat << BASE_BITS) | an[j + n - 2] as u64 {
435 q_hat -= 1;
436 r_hat += b_high;
437 if r_hat >= BASE {
438 break;
439 }
440 }
441
442 let mut borrow: i64 = 0;
444 let mut carry: u64 = 0;
445 for i in 0..n {
446 let p = q_hat * bn[i] as u64 + carry;
447 carry = p >> BASE_BITS;
448 let sub = an[j + i] as i64 - (p & 0xFFFF_FFFF) as i64 - borrow;
449 if sub < 0 {
450 an[j + i] = (sub + BASE as i64) as u32;
451 borrow = 1;
452 } else {
453 an[j + i] = sub as u32;
454 borrow = 0;
455 }
456 }
457 let sub = an[j + n] as i64 - carry as i64 - borrow;
458 if sub < 0 {
459 an[j + n] = (sub + BASE as i64) as u32;
461 q_hat -= 1;
462 let mut carry2: u64 = 0;
463 for i in 0..n {
464 let s = an[j + i] as u64 + bn[i] as u64 + carry2;
465 an[j + i] = (s & 0xFFFF_FFFF) as u32;
466 carry2 = s >> BASE_BITS;
467 }
468 an[j + n] = (an[j + n] as u64 + carry2) as u32;
469 } else {
470 an[j + n] = sub as u32;
471 }
472 q[j] = q_hat as u32;
473 }
474
475 while let Some(&0) = q.last() {
476 q.pop();
477 }
478 let mut rem = an[..n].to_vec();
480 while let Some(&0) = rem.last() {
481 rem.pop();
482 }
483 let rem = Self::shr_bits(&rem, shift);
484 (q, rem)
485 }
486
487 fn shl_bits(a: &[u32], bits: u32) -> Vec<u32> {
489 if bits == 0 || a.is_empty() {
490 return a.to_vec();
491 }
492 let mut out = Vec::with_capacity(a.len() + 1);
493 let mut carry: u32 = 0;
494 for &limb in a {
495 let v = ((limb as u64) << bits) | carry as u64;
496 out.push((v & 0xFFFF_FFFF) as u32);
497 carry = (v >> BASE_BITS) as u32;
498 }
499 if carry > 0 {
500 out.push(carry);
501 }
502 out
503 }
504
505 fn shr_bits(a: &[u32], bits: u32) -> Vec<u32> {
507 if bits == 0 || a.is_empty() {
508 return a.to_vec();
509 }
510 let mut out = vec![0u32; a.len()];
511 let mut carry: u32 = 0;
512 for i in (0..a.len()).rev() {
513 let v = a[i];
514 out[i] = (v >> bits) | carry;
515 carry = v << (BASE_BITS - bits);
516 }
517 while let Some(&0) = out.last() {
518 out.pop();
519 }
520 out
521 }
522
523 pub fn pow(&self, exp: u32) -> BigInt {
525 let mut result = BigInt::one();
526 let mut base = self.clone();
527 let mut e = exp;
528 while e > 0 {
529 if e & 1 == 1 {
530 result = result.mul(&base);
531 }
532 e >>= 1;
533 if e > 0 {
534 base = base.mul(&base);
535 }
536 }
537 result
538 }
539
540 pub fn gcd(&self, other: &BigInt) -> BigInt {
542 let mut a = self.abs();
543 let mut b = other.abs();
544 while !b.is_zero() {
545 let r = a.rem(&b).expect("b non-zero in gcd loop");
547 a = b;
548 b = r;
549 }
550 a
551 }
552}
553
554impl PartialOrd for BigInt {
555 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
556 Some(self.cmp(other))
557 }
558}
559
560impl Ord for BigInt {
561 fn cmp(&self, other: &Self) -> Ordering {
562 match self.sign.cmp(&other.sign) {
563 Ordering::Equal => {}
564 non_eq => return non_eq,
565 }
566 match self.sign {
568 0 => Ordering::Equal,
569 1 => Self::cmp_mag(&self.mag, &other.mag),
570 _ => Self::cmp_mag(&other.mag, &self.mag), }
572 }
573}
574
575impl fmt::Debug for BigInt {
576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577 write!(f, "BigInt({})", self.to_string())
578 }
579}
580
581impl fmt::Display for BigInt {
582 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583 f.write_str(&self.to_string())
584 }
585}
586
587#[cfg(test)]
588mod tests {
589 use super::*;
590
591 #[test]
592 fn from_and_to_i64_roundtrip() {
593 for v in [
594 0i64,
595 1,
596 -1,
597 42,
598 -42,
599 1_000_000,
600 -1_000_000,
601 i64::MAX,
602 i64::MIN,
603 ] {
604 let b = BigInt::from_i64(v);
605 assert_eq!(b.to_string(), v.to_string(), "value {v}");
606 }
607 }
608
609 #[test]
610 fn from_str_roundtrip_and_failclosed() {
611 assert_eq!(
612 BigInt::from_str("12345678901234567890")
613 .unwrap()
614 .to_string(),
615 "12345678901234567890"
616 );
617 assert_eq!(
618 BigInt::from_str("-99999999999999999999")
619 .unwrap()
620 .to_string(),
621 "-99999999999999999999"
622 );
623 assert_eq!(BigInt::from_str("+7").unwrap().to_string(), "7");
624 assert_eq!(BigInt::from_str("-0").unwrap().to_string(), "0");
625 assert!(BigInt::from_str("").is_none());
626 assert!(BigInt::from_str("12a3").is_none());
627 assert!(BigInt::from_str("--3").is_none());
628 }
629
630 #[test]
631 fn add_sub_signs() {
632 let a = BigInt::from_i64(100);
633 let b = BigInt::from_i64(-30);
634 assert_eq!(a.add(&b).to_string(), "70");
635 assert_eq!(b.add(&a).to_string(), "70");
636 assert_eq!(a.sub(&b).to_string(), "130");
637 assert_eq!(b.sub(&a).to_string(), "-130");
638 assert_eq!(a.add(&a.neg()).to_string(), "0");
639 }
640
641 #[test]
642 fn mul_and_pow_2_to_100() {
643 let two = BigInt::from_i64(2);
645 let p = two.pow(100);
646 assert_eq!(p.to_string(), "1267650600228229401496703205376");
647 }
648
649 #[test]
650 fn factorial_100_known_value() {
651 let mut acc = BigInt::one();
652 for k in 1..=100u64 {
653 acc = acc.mul(&BigInt::from_u64(k));
654 }
655 let expected = "93326215443944152681699238856266700490715968264381621468592963895217\
65759999322991560894146397615651828625369792082722375825118521091686400\
6580000000000000000000000";
659 assert_eq!(acc.to_string(), expected);
660 }
661
662 #[test]
663 fn divmod_known_values() {
664 let a = BigInt::from_i64(100);
665 let b = BigInt::from_i64(7);
666 let (q, r) = a.divmod(&b).unwrap();
667 assert_eq!(q.to_string(), "14");
668 assert_eq!(r.to_string(), "2");
669
670 assert_eq!(q.mul(&b).add(&r), a);
672
673 let (q2, r2) = BigInt::from_i64(-100).divmod(&BigInt::from_i64(7)).unwrap();
675 assert_eq!(q2.to_string(), "-14");
676 assert_eq!(r2.to_string(), "-2");
677 }
678
679 #[test]
680 fn divmod_multilimb() {
681 let num = BigInt::from_i64(2).pow(100);
683 let den = BigInt::from_i64(2).pow(50);
684 let (q, r) = num.divmod(&den).unwrap();
685 assert!(r.is_zero());
686 assert_eq!(q, BigInt::from_i64(2).pow(50));
687
688 let x = BigInt::from_str("123456789012345678901234567890").unwrap();
690 let y = BigInt::from_str("98765432109876543").unwrap();
691 let (q, r) = x.divmod(&y).unwrap();
692 assert_eq!(q.mul(&y).add(&r), x);
693 assert!(r.abs() < y.abs());
694 }
695
696 #[test]
697 fn divide_by_zero_fails_closed() {
698 assert!(BigInt::from_i64(5).divmod(&BigInt::zero()).is_none());
699 assert!(BigInt::from_i64(5).div(&BigInt::zero()).is_none());
700 assert!(BigInt::from_i64(5).rem(&BigInt::zero()).is_none());
701 }
702
703 #[test]
704 fn ordering() {
705 assert!(BigInt::from_i64(-5) < BigInt::from_i64(-3));
706 assert!(BigInt::from_i64(-3) < BigInt::from_i64(0));
707 assert!(BigInt::from_i64(0) < BigInt::from_i64(3));
708 assert!(BigInt::from_i64(3) < BigInt::from_i64(5));
709 assert!(BigInt::from_i64(2).pow(100) > BigInt::from_i64(2).pow(99));
710 assert_eq!(
711 BigInt::from_i64(7).cmp(&BigInt::from_i64(7)),
712 Ordering::Equal
713 );
714 }
715
716 #[test]
717 fn gcd_known() {
718 assert_eq!(
719 BigInt::from_i64(48).gcd(&BigInt::from_i64(36)).to_string(),
720 "12"
721 );
722 assert_eq!(
723 BigInt::from_i64(-48).gcd(&BigInt::from_i64(36)).to_string(),
724 "12"
725 );
726 assert_eq!(
727 BigInt::from_i64(17).gcd(&BigInt::from_i64(5)).to_string(),
728 "1"
729 );
730 assert_eq!(
731 BigInt::from_i64(0).gcd(&BigInt::from_i64(9)).to_string(),
732 "9"
733 );
734 }
735
736 #[test]
737 fn abs_neg() {
738 assert_eq!(BigInt::from_i64(-42).abs().to_string(), "42");
739 assert_eq!(BigInt::from_i64(42).neg().to_string(), "-42");
740 assert!(BigInt::zero().neg().is_zero());
741 }
742}