1pub(crate) mod traits;
22pub(crate) mod compute_limbs;
23
24pub use traits::BigInt;
25
26use crate::int::algos::div::div_fixed::div_rem_mag_fixed;
27use crate::int::algos::div::div_rem::div_rem;
28use crate::int::algos::support::limbs::{
29 add_assign_fixed, bit_len_fixed, cmp_cross, cmp_fixed, is_zero_fixed, max_n_limbs, shl,
30 shl_fixed, shr_fixed, sub_assign_fixed,
31};
32use crate::int::algos::mul::mul_schoolbook::{mul_low_fixed, mul_schoolbook};
33use crate::int::policy::add::dispatch as add_dispatch;
34use crate::int::policy::cmp::dispatch as cmp_dispatch;
35use crate::int::policy::cube::dispatch as cube_dispatch;
36use crate::int::policy::div_rem::dispatch as div_rem_dispatch;
37use crate::int::policy::eq::dispatch as eq_dispatch;
38use crate::int::policy::icbrt::dispatch as icbrt_dispatch;
39use crate::int::policy::hypot::dispatch as hypot_dispatch;
40use crate::int::policy::isqrt::dispatch as isqrt_dispatch;
41use crate::int::policy::mul::dispatch as mul_fast;
42use crate::int::policy::neg::dispatch as neg_dispatch;
43use crate::int::policy::sum_sq::dispatch as sum_sq_dispatch;
44use crate::int::policy::pow::dispatch as pow_dispatch;
45use crate::int::policy::rem::dispatch as rem_dispatch;
46use crate::int::policy::sqr::dispatch as sqr_dispatch;
47use crate::int::policy::sub::dispatch as sub_dispatch;
48use crate::support::int_fmt::fmt_into;
49use core::cmp::Ordering;
50use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub};
51
52#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
54pub struct Uint<const N: usize> {
55 limbs: [u64; N],
56}
57
58#[derive(Clone, Copy, Eq, Hash, Debug)]
66pub struct Int<const N: usize> {
67 limbs: [u64; N],
68}
69
70impl<const N: usize> Uint<N> {
71 pub const LIMBS: usize = N;
73 pub const BITS: u32 = (N as u32) * 64;
77
78 pub const ZERO: Self = Self { limbs: [0; N] };
80 pub const ONE: Self = {
82 let mut limbs = [0u64; N];
83 limbs[0] = 1;
84 Self { limbs }
85 };
86 pub const MAX: Self = Self {
88 limbs: [u64::MAX; N],
89 };
90
91 #[inline]
93 pub const fn from_limbs(limbs: [u64; N]) -> Self {
94 Self { limbs }
95 }
96
97 #[inline]
99 pub const fn as_limbs(&self) -> &[u64; N] {
100 &self.limbs
101 }
102
103 #[inline]
105 pub fn wrapping_add(mut self, rhs: Self) -> Self {
106 add_assign_fixed(&mut self.limbs, &rhs.limbs);
107 self
108 }
109
110 #[inline]
112 pub fn wrapping_sub(mut self, rhs: Self) -> Self {
113 sub_assign_fixed(&mut self.limbs, &rhs.limbs);
114 self
115 }
116
117 #[inline]
126 pub fn wrapping_mul(self, rhs: Self) -> Self {
127 let mut out = [0u64; N];
128 mul_low_fixed(&self.limbs, &rhs.limbs, &mut out);
129 Self { limbs: out }
130 }
131
132 #[inline]
139 pub const fn wrapping_sqr(self) -> Self {
140 sqr_dispatch(self)
141 }
142
143 #[inline]
148 pub const fn wrapping_cube(self) -> Self {
149 cube_dispatch(self)
150 }
151
152 #[inline]
154 pub fn checked_add(mut self, rhs: Self) -> Option<Self> {
155 let carry = add_assign_fixed(&mut self.limbs, &rhs.limbs);
156 if carry { None } else { Some(self) }
157 }
158
159 #[inline]
161 pub fn checked_sub(mut self, rhs: Self) -> Option<Self> {
162 let borrow = sub_assign_fixed(&mut self.limbs, &rhs.limbs);
163 if borrow { None } else { Some(self) }
164 }
165
166 #[inline]
169 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
170 let (a, b) = (&self.limbs, &rhs.limbs);
171 let mut out = [0u64; N];
172 let mut overflow = false;
173 let mut i = 0;
174 while i < N {
175 let ai = a[i];
176 if ai != 0 {
177 let mut carry: u64 = 0;
178 let mut j = 0;
179 while j < N {
180 let prod = (ai as u128) * (b[j] as u128);
181 if i + j < N {
182 let v = prod + (out[i + j] as u128) + (carry as u128);
183 out[i + j] = v as u64;
184 carry = (v >> 64) as u64;
185 } else if prod != 0 || carry != 0 {
186 overflow = true;
189 carry = 0;
190 }
191 j += 1;
192 }
193 if carry != 0 {
194 overflow = true;
196 }
197 }
198 i += 1;
199 }
200 if overflow {
201 None
202 } else {
203 Some(Self { limbs: out })
204 }
205 }
206
207 #[inline]
210 pub fn wrapping_div(self, rhs: Self) -> Self {
211 assert!(!rhs.is_zero(), "attempt to divide by zero");
212 let mut quot = [0u64; N];
213 let mut rem = [0u64; N];
214 div_rem(&self.limbs, &rhs.limbs, &mut quot, &mut rem);
215 Self { limbs: quot }
216 }
217
218 #[inline]
221 pub fn wrapping_rem(self, rhs: Self) -> Self {
222 assert!(
223 !rhs.is_zero(),
224 "attempt to calculate the remainder with a divisor of zero"
225 );
226 let mut quot = [0u64; N];
227 let mut rem = [0u64; N];
228 div_rem(&self.limbs, &rhs.limbs, &mut quot, &mut rem);
229 Self { limbs: rem }
230 }
231
232 #[allow(clippy::should_implement_trait)]
238 #[inline]
239 pub fn bitand(self, rhs: Self) -> Self {
240 let mut out = [0u64; N];
241 let mut i = 0;
242 while i < N {
243 out[i] = self.limbs[i] & rhs.limbs[i];
244 i += 1;
245 }
246 Self { limbs: out }
247 }
248
249 #[allow(clippy::should_implement_trait)]
251 #[inline]
252 pub fn bitor(self, rhs: Self) -> Self {
253 let mut out = [0u64; N];
254 let mut i = 0;
255 while i < N {
256 out[i] = self.limbs[i] | rhs.limbs[i];
257 i += 1;
258 }
259 Self { limbs: out }
260 }
261
262 #[allow(clippy::should_implement_trait)]
264 #[inline]
265 pub fn bitxor(self, rhs: Self) -> Self {
266 let mut out = [0u64; N];
267 let mut i = 0;
268 while i < N {
269 out[i] = self.limbs[i] ^ rhs.limbs[i];
270 i += 1;
271 }
272 Self { limbs: out }
273 }
274
275 #[allow(clippy::should_implement_trait)]
277 #[inline]
278 pub fn not(self) -> Self {
279 let mut out = [0u64; N];
280 let mut i = 0;
281 while i < N {
282 out[i] = !self.limbs[i];
283 i += 1;
284 }
285 Self { limbs: out }
286 }
287
288 #[allow(clippy::should_implement_trait)]
290 #[inline]
291 pub fn shl(self, shift: u32) -> Self {
292 let mut out = [0u64; N];
293 shl_fixed(&self.limbs, shift, &mut out);
294 Self { limbs: out }
295 }
296
297 #[allow(clippy::should_implement_trait)]
299 #[inline]
300 pub fn shr(self, shift: u32) -> Self {
301 let mut out = [0u64; N];
302 shr_fixed(&self.limbs, shift, &mut out);
303 Self { limbs: out }
304 }
305
306 #[inline]
308 pub fn is_zero(&self) -> bool {
309 is_zero_fixed(&self.limbs)
310 }
311
312 #[inline]
319 pub const fn bit_length(&self) -> u32 {
320 bit_len_fixed(&self.limbs)
321 }
322
323 #[inline]
327 pub const fn leading_zeros(&self) -> u32 {
328 Self::BITS - self.bit_length()
329 }
330
331 #[inline]
333 pub fn is_one(&self) -> bool {
334 if N == 0 || self.limbs[0] != 1 {
335 return false;
336 }
337 let mut i = 1;
338 while i < N {
339 if self.limbs[i] != 0 {
340 return false;
341 }
342 i += 1;
343 }
344 true
345 }
346
347 #[inline]
353 pub const fn wrapping_pow(self, exp: u32) -> Self {
354 pow_dispatch(self, exp)
355 }
356
357 #[inline]
360 pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
361 let mut acc = Self::ONE;
362 let mut base = self;
363 loop {
364 if exp & 1 == 1 {
365 acc = acc.checked_mul(base)?;
366 }
367 exp >>= 1;
368 if exp == 0 {
369 break;
370 }
371 base = base.checked_mul(base)?;
372 }
373 Some(acc)
374 }
375
376 #[inline]
380 pub fn pow(self, exp: u32) -> Self {
381 pow_dispatch(self, exp)
382 }
383
384 #[inline]
389 pub fn isqrt(self) -> Self {
390 isqrt_dispatch(self)
391 }
392
393 #[inline]
396 pub fn sqr(self) -> Self {
397 sqr_dispatch(self)
398 }
399
400 #[inline]
403 pub fn cube(self) -> Self {
404 cube_dispatch(self)
405 }
406
407 #[inline]
412 pub fn icbrt(self) -> Self {
413 icbrt_dispatch(self)
414 }
415
416 pub fn root_int(self, k: u32) -> (Self, bool) {
430 debug_assert!(k >= 1, "root_int requires k >= 1");
431 if k == 1 {
433 return (self, true);
434 }
435 if self.is_zero() {
436 return (Self::ZERO, true);
437 }
438 if self.is_one() {
439 return (Self::ONE, true);
440 }
441 if k == 2 {
442 let r = self.isqrt();
443 return (r, r.wrapping_sqr() == self);
444 }
445
446 let len = self.bit_length();
448 let seed_shift = len.div_ceil(k);
449 let mut s = Self::ONE.shl(seed_shift);
451
452 loop {
454 let pow_km1 = s.wrapping_pow(k - 1);
456 let quot = self.wrapping_div(pow_km1);
458 let mut t = Self::ZERO;
459 let mut c = 0;
460 while c < k - 1 {
461 t = t.wrapping_add(s);
462 c += 1;
463 }
464 t = t.wrapping_add(quot);
465 let u = t.wrapping_div(Self::from_u64(k as u64));
467 if u >= s {
468 break;
469 }
470 s = u;
471 }
472
473 let exact = s.checked_pow(k).is_some_and(|p| p == self);
474 (s, exact)
475 }
476
477 #[inline]
479 pub(crate) fn from_u64(value: u64) -> Self {
480 let mut limbs = [0u64; N];
481 if N > 0 {
482 limbs[0] = value;
483 }
484 Self { limbs }
485 }
486
487 #[inline]
492 pub(crate) const fn from_u128(v: u128) -> Self {
493 let mut limbs = [0u64; N];
494 if N > 0 {
495 limbs[0] = v as u64;
496 }
497 if N > 1 {
498 limbs[1] = (v >> 64) as u64;
499 }
500 Self { limbs }
501 }
502
503 #[inline]
506 pub(crate) const fn try_from_u128(v: u128) -> Option<Self> {
507 if N >= 2 || v <= u64::MAX as u128 {
508 Some(Self::from_u128(v))
509 } else {
510 None
511 }
512 }
513
514 #[inline]
516 pub const fn cast_signed(self) -> Int<N> {
517 Int::from_limbs(self.limbs)
518 }
519
520 pub fn as_f64(self) -> f64 {
523 let radix: f64 = 18_446_744_073_709_551_616.0; let mut acc = 0.0f64;
525 let mut i = N;
526 while i > 0 {
527 i -= 1;
528 acc = acc * radix + self.limbs[i] as f64;
529 }
530 acc
531 }
532
533 #[inline]
536 pub const fn count_ones(self) -> u32 {
537 let mut total = 0;
538 let mut i = 0;
539 while i < N {
540 total += self.limbs[i].count_ones();
541 i += 1;
542 }
543 total
544 }
545
546 #[inline]
548 pub const fn is_power_of_two(self) -> bool {
549 self.count_ones() == 1
550 }
551
552 pub fn next_power_of_two(self) -> Self {
555 if self.is_zero() {
556 return Self::ONE;
557 }
558 if self.is_power_of_two() {
559 return self;
560 }
561 let bits = self.bit_length();
562 let mut out = [0u64; N];
563 if (bits as usize) < N * 64 {
564 out[(bits / 64) as usize] = 1u64 << (bits % 64);
565 }
566 Self { limbs: out }
567 }
568
569 pub const fn from_str_radix(s: &str, radix: u32) -> Result<Self, ()> {
571 if radix != 10 {
572 return Err(());
573 }
574 let bytes = s.as_bytes();
575 if bytes.is_empty() {
576 return Err(());
577 }
578 let mut acc = [0u64; N];
579 let mut k = 0;
580 while k < bytes.len() {
581 let ch = bytes[k];
582 if ch < b'0' || ch > b'9' {
583 return Err(());
584 }
585 let d = (ch - b'0') as u64;
586 let mut carry: u64 = d;
587 let mut j = 0;
588 while j < N {
589 let p = (acc[j] as u128) * 10u128 + (carry as u128);
590 acc[j] = p as u64;
591 carry = (p >> 64) as u64;
592 j += 1;
593 }
594 k += 1;
595 }
596 Ok(Self { limbs: acc })
597 }
598}
599
600impl<const N: usize> Add for Uint<N> {
601 type Output = Self;
602 #[inline]
603 fn add(self, rhs: Self) -> Self {
604 self.wrapping_add(rhs)
605 }
606}
607
608impl<const N: usize> Sub for Uint<N> {
609 type Output = Self;
610 #[inline]
611 fn sub(self, rhs: Self) -> Self {
612 self.wrapping_sub(rhs)
613 }
614}
615
616impl<const N: usize> Mul for Uint<N> {
617 type Output = Self;
618 #[inline]
619 fn mul(self, rhs: Self) -> Self {
620 self.wrapping_mul(rhs)
621 }
622}
623
624impl<const N: usize> BitAnd for Uint<N> {
625 type Output = Self;
626 #[inline]
627 fn bitand(self, rhs: Self) -> Self {
628 Uint::bitand(self, rhs)
629 }
630}
631
632impl<const N: usize> BitOr for Uint<N> {
633 type Output = Self;
634 #[inline]
635 fn bitor(self, rhs: Self) -> Self {
636 Uint::bitor(self, rhs)
637 }
638}
639
640impl<const N: usize> BitXor for Uint<N> {
641 type Output = Self;
642 #[inline]
643 fn bitxor(self, rhs: Self) -> Self {
644 Uint::bitxor(self, rhs)
645 }
646}
647
648impl<const N: usize> Not for Uint<N> {
649 type Output = Self;
650 #[inline]
651 fn not(self) -> Self {
652 Uint::not(self)
653 }
654}
655
656impl<const N: usize> Shl<u32> for Uint<N> {
657 type Output = Self;
658 #[inline]
659 fn shl(self, shift: u32) -> Self {
660 Uint::shl(self, shift)
661 }
662}
663
664impl<const N: usize> Shr<u32> for Uint<N> {
665 type Output = Self;
666 #[inline]
667 fn shr(self, shift: u32) -> Self {
668 Uint::shr(self, shift)
669 }
670}
671
672impl<const N: usize> Div for Uint<N> {
677 type Output = Self;
678 #[inline]
679 fn div(self, rhs: Self) -> Self {
680 let mut q = [0u64; N];
681 let mut r = [0u64; N];
682 div_rem_dispatch(&self.limbs, &rhs.limbs, &mut q, &mut r);
683 Self { limbs: q }
684 }
685}
686
687impl<const N: usize> Rem for Uint<N> {
688 type Output = Self;
689 #[inline]
690 fn rem(self, rhs: Self) -> Self {
691 let mut q = [0u64; N];
692 let mut r = [0u64; N];
693 div_rem_dispatch(&self.limbs, &rhs.limbs, &mut q, &mut r);
694 Self { limbs: r }
695 }
696}
697
698impl<const N: usize> PartialOrd for Uint<N> {
699 #[inline]
700 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
701 Some(self.cmp(other))
702 }
703}
704
705impl<const N: usize> Ord for Uint<N> {
706 #[inline]
707 fn cmp(&self, other: &Self) -> Ordering {
708 match cmp_fixed(&self.limbs, &other.limbs) {
709 -1 => Ordering::Less,
710 1 => Ordering::Greater,
711 _ => Ordering::Equal,
712 }
713 }
714}
715
716impl<const N: usize> Int<N> {
717 pub const LIMBS: usize = N;
719 pub const BITS: u32 = (N as u32) * 64;
723
724 pub const ZERO: Self = Self { limbs: [0; N] };
726 pub const ONE: Self = {
728 let mut limbs = [0u64; N];
729 limbs[0] = 1;
730 Self { limbs }
731 };
732 pub const MAX: Self = {
734 let mut limbs = [u64::MAX; N];
735 limbs[N - 1] = i64::MAX as u64;
736 Self { limbs }
737 };
738 pub const MIN: Self = {
740 let mut limbs = [0u64; N];
741 limbs[N - 1] = 1u64 << 63;
742 Self { limbs }
743 };
744
745 #[inline]
747 pub const fn from_limbs(limbs: [u64; N]) -> Self {
748 Self { limbs }
749 }
750
751 #[inline]
753 pub const fn as_limbs(&self) -> &[u64; N] {
754 &self.limbs
755 }
756
757 #[inline]
759 pub const fn is_zero(&self) -> bool {
760 is_zero_fixed(&self.limbs)
761 }
762
763 #[inline]
765 pub const fn is_negative(&self) -> bool {
766 N > 0 && (self.limbs[N - 1] >> 63) == 1
767 }
768
769 #[inline]
772 pub const fn is_positive(&self) -> bool {
773 !self.is_negative() && !self.is_zero()
774 }
775
776 #[inline]
779 pub const fn wrapping_neg(self) -> Self {
780 neg_dispatch(self)
781 }
782
783 #[inline]
787 pub const fn wrapping_add(self, rhs: Self) -> Self {
788 add_dispatch(self, rhs)
789 }
790
791 #[inline]
793 pub const fn wrapping_sub(self, rhs: Self) -> Self {
794 sub_dispatch(self, rhs)
795 }
796
797 #[inline]
801 pub const fn wrapping_mul(self, rhs: Self) -> Self {
802 let mut out = [0u64; N];
803 mul_low_fixed(&self.limbs, &rhs.limbs, &mut out);
804 Self { limbs: out }
805 }
806
807 #[inline]
809 pub const fn abs(self) -> Self {
810 if self.is_negative() {
811 self.wrapping_neg()
812 } else {
813 self
814 }
815 }
816
817 #[inline]
820 pub fn signum(&self) -> i32 {
821 if self.is_zero() {
822 0
823 } else if self.is_negative() {
824 -1
825 } else {
826 1
827 }
828 }
829
830 #[inline]
832 pub(crate) const fn from_i64(value: i64) -> Self {
833 let fill = if value < 0 { u64::MAX } else { 0 };
836 let mut limbs = [fill; N];
837 if N > 0 {
838 limbs[0] = value as u64;
839 }
840 Self { limbs }
841 }
842
843 #[inline]
845 pub(crate) const fn from_i8(value: i8) -> Self {
846 Self::from_i64(value as i64)
847 }
848
849 #[inline]
851 pub(crate) const fn from_i16(value: i16) -> Self {
852 Self::from_i64(value as i64)
853 }
854
855 #[inline]
857 pub(crate) const fn from_i32(value: i32) -> Self {
858 Self::from_i64(value as i64)
859 }
860
861 #[inline]
863 pub(crate) const fn from_u8(value: u8) -> Self {
864 Self::from_u64_unsigned(value as u64)
865 }
866
867 #[inline]
869 pub(crate) const fn from_u16(value: u16) -> Self {
870 Self::from_u64_unsigned(value as u64)
871 }
872
873 #[inline]
875 pub(crate) const fn from_u32(value: u32) -> Self {
876 Self::from_u64_unsigned(value as u64)
877 }
878
879 #[inline]
883 const fn from_u64_unsigned(value: u64) -> Self {
884 let mut limbs = [0u64; N];
885 if N > 0 {
886 limbs[0] = value;
887 }
888 Self { limbs }
889 }
890
891 #[inline]
895 pub(crate) const fn try_from_u64(value: u64) -> Option<Self> {
896 if N >= 2 || value <= i64::MAX as u64 {
897 Some(Self::from_u64_unsigned(value))
898 } else {
899 None
900 }
901 }
902
903 #[inline]
907 pub(crate) const fn try_from_i128(v: i128) -> Option<Self> {
908 let mag = v.unsigned_abs();
909 let built = Self::from_mag_limbs(&[mag as u64, (mag >> 64) as u64], v < 0);
910 if N >= 2 || built.as_i128() == v {
911 Some(built)
912 } else {
913 None
914 }
915 }
916
917 #[inline]
921 pub(crate) const fn try_from_u128(v: u128) -> Option<Self> {
922 let built = Self::from_mag_limbs(&[v as u64, (v >> 64) as u64], false);
923 if N >= 3 {
924 Some(built)
925 } else if built.is_negative() {
926 None
928 } else if N >= 2 || built.as_i128() as u128 == v {
929 Some(built)
930 } else {
931 None
932 }
933 }
934
935 #[inline]
938 pub(crate) const fn to_i64(self) -> i64 {
939 self.as_i128() as i64
940 }
941
942 #[inline]
946 pub(crate) const fn to_i128(self) -> i128 {
947 self.as_i128()
948 }
949
950 #[inline]
952 pub(crate) fn try_to_i32(self) -> Option<i32> {
953 match self.to_i128_checked() {
954 Some(v) if v >= i32::MIN as i128 && v <= i32::MAX as i128 => Some(v as i32),
955 _ => None,
956 }
957 }
958
959 #[inline]
961 pub(crate) fn try_to_u32(self) -> Option<u32> {
962 match self.to_u128_checked() {
963 Some(v) if v <= u32::MAX as u128 => Some(v as u32),
964 _ => None,
965 }
966 }
967
968 #[inline]
970 pub(crate) fn try_to_i64(self) -> Option<i64> {
971 match self.to_i128_checked() {
972 Some(v) if v >= i64::MIN as i128 && v <= i64::MAX as i128 => Some(v as i64),
973 _ => None,
974 }
975 }
976
977 #[inline]
979 pub(crate) fn try_to_u64(self) -> Option<u64> {
980 match self.to_u128_checked() {
981 Some(v) if v <= u64::MAX as u128 => Some(v as u64),
982 _ => None,
983 }
984 }
985
986 #[inline]
989 pub(crate) fn try_to_i128(self) -> Option<i128> {
990 self.to_i128_checked()
991 }
992
993 #[inline]
996 pub(crate) fn try_to_u128(self) -> Option<u128> {
997 self.to_u128_checked()
998 }
999
1000 #[inline]
1002 pub fn is_one(&self) -> bool {
1003 if N == 0 || self.limbs[0] != 1 {
1004 return false;
1005 }
1006 let mut i = 1;
1007 while i < N {
1008 if self.limbs[i] != 0 {
1009 return false;
1010 }
1011 i += 1;
1012 }
1013 true
1014 }
1015
1016 #[inline]
1018 pub fn min_value() -> Self {
1019 let mut limbs = [0u64; N];
1020 if N > 0 {
1021 limbs[N - 1] = 1u64 << 63;
1022 }
1023 Self { limbs }
1024 }
1025
1026 #[inline]
1028 pub fn max_value() -> Self {
1029 let mut limbs = [u64::MAX; N];
1030 if N > 0 {
1031 limbs[N - 1] = u64::MAX >> 1;
1032 }
1033 Self { limbs }
1034 }
1035
1036 #[inline]
1044 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
1045 crate::int::policy::add::dispatch_checked(self, rhs)
1046 }
1047
1048 #[inline]
1053 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
1054 crate::int::policy::sub::dispatch_checked(self, rhs)
1055 }
1056
1057 #[inline]
1061 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
1062 if self.is_zero() || rhs.is_zero() {
1063 return Some(Self::ZERO);
1064 }
1065 let neg = self.is_negative() ^ rhs.is_negative();
1066 let ma = Uint::<N>::from_limbs(*self.abs().as_limbs());
1067 let mb = Uint::<N>::from_limbs(*rhs.abs().as_limbs());
1068 let prod = ma.checked_mul(mb)?;
1069 let signed = Self::from_limbs(*prod.as_limbs());
1070 if neg {
1071 let r = signed.wrapping_neg();
1072 if r.is_negative() || r.is_zero() {
1075 Some(r)
1076 } else {
1077 None
1078 }
1079 } else if signed.is_negative() {
1080 None
1082 } else {
1083 Some(signed)
1084 }
1085 }
1086
1087 #[inline]
1094 pub const fn wrapping_pow(self, exp: u32) -> Self {
1095 Self::from_limbs(*pow_dispatch(self.cast_unsigned(), exp).as_limbs())
1096 }
1097
1098 #[inline]
1100 pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
1101 let mut acc = Self::ONE;
1102 let mut base = self;
1103 loop {
1104 if exp & 1 == 1 {
1105 acc = acc.checked_mul(base)?;
1106 }
1107 exp >>= 1;
1108 if exp == 0 {
1109 break;
1110 }
1111 base = base.checked_mul(base)?;
1112 }
1113 Some(acc)
1114 }
1115
1116 #[inline]
1122 pub const fn wrapping_sqr(self) -> Self {
1123 Self::from_limbs(*sqr_dispatch(self.cast_unsigned()).as_limbs())
1124 }
1125
1126 #[inline]
1132 pub const fn wrapping_cube(self) -> Self {
1133 Self::from_limbs(*cube_dispatch(self.cast_unsigned()).as_limbs())
1134 }
1135
1136 #[inline]
1150 pub const fn bit_length(&self) -> u32 {
1151 bit_len_fixed(self.abs().as_limbs())
1152 }
1153
1154 #[inline]
1164 pub const fn leading_zeros(&self) -> u32 {
1165 if self.is_negative() {
1166 0
1167 } else {
1168 Self::BITS - self.bit_length()
1169 }
1170 }
1171
1172 pub const TEN: Self = {
1182 let mut limbs = [0u64; N];
1183 if N > 0 {
1184 limbs[0] = 10;
1185 }
1186 Self { limbs }
1187 };
1188
1189 #[inline]
1191 pub const fn unsigned_abs(self) -> Uint<N> {
1192 Uint::from_limbs(*self.abs().as_limbs())
1193 }
1194
1195 #[inline]
1197 pub fn negate(self) -> Self {
1198 self.wrapping_neg()
1199 }
1200
1201 #[inline]
1209 pub fn div_rem(self, rhs: Self) -> (Self, Self) {
1210 assert!(!rhs.is_zero(), "attempt to divide by zero");
1211 let neg_q = self.is_negative() ^ rhs.is_negative();
1212 let neg_r = self.is_negative();
1213 let mut quot = [0u64; N];
1214 let mut rem = [0u64; N];
1215 div_rem_mag_fixed::<N>(
1216 self.unsigned_abs().as_limbs(),
1217 rhs.unsigned_abs().as_limbs(),
1218 &mut quot,
1219 &mut rem,
1220 );
1221 let q = Self::from_mag_limbs(", neg_q);
1222 let r = Self::from_mag_limbs(&rem, neg_r);
1223 (q, r)
1224 }
1225
1226 #[inline]
1229 pub(crate) const fn from_mag_limbs(mag: &[u64], negative: bool) -> Self {
1230 let mut out = [0u64; N];
1231 let n = if mag.len() < N { mag.len() } else { N };
1232 let mut i = 0;
1233 while i < n {
1234 out[i] = mag[i];
1235 i += 1;
1236 }
1237 let v = Self { limbs: out };
1238 if negative && !is_zero_fixed(&v.limbs) {
1241 v.wrapping_neg()
1242 } else {
1243 v
1244 }
1245 }
1246
1247 #[inline]
1249 pub const fn bit(self, idx: u32) -> bool {
1250 let limb = (idx / 64) as usize;
1251 if limb >= N {
1252 return self.is_negative();
1253 }
1254 (self.limbs[limb] >> (idx % 64)) & 1 == 1
1255 }
1256
1257 #[inline]
1261 pub(crate) const fn from_i128(v: i128) -> Self {
1262 if N <= 2 {
1268 let mut limbs = [0u64; N];
1269 limbs[0] = v as u64;
1270 if N == 2 {
1271 limbs[1] = (v >> 64) as u64;
1272 }
1273 return Self { limbs };
1274 }
1275 let mag = v.unsigned_abs();
1276 Self::from_mag_limbs(&[mag as u64, (mag >> 64) as u64], v < 0)
1277 }
1278
1279 #[inline]
1281 pub(crate) const fn from_u128(v: u128) -> Self {
1282 Self::from_mag_limbs(&[v as u64, (v >> 64) as u64], false)
1283 }
1284
1285 #[inline]
1288 pub const fn from_limbs_le(limbs: [u64; N]) -> Self {
1289 Self { limbs }
1290 }
1291
1292 #[inline]
1295 pub const fn limbs_le(self) -> [u64; N] {
1296 self.limbs
1297 }
1298
1299 #[inline]
1304 pub fn mul_u64(self, n: u64) -> Self {
1305 let mag = *self.unsigned_abs().as_limbs();
1306 let mut prod = [0u64; N];
1307 let mut carry: u64 = 0;
1308 let mut i = 0;
1309 while i < N {
1310 let p = (mag[i] as u128) * (n as u128) + (carry as u128);
1311 prod[i] = p as u64;
1312 carry = (p >> 64) as u64;
1313 i += 1;
1314 }
1315 if carry != 0 {
1316 panic!("Int: mul overflow");
1317 }
1318 let negative = self.is_negative();
1319 let r = Self::from_mag_limbs(&prod, negative);
1320 if !r.is_zero() && r.is_negative() != negative {
1323 panic!("Int: mul overflow");
1324 }
1325 r
1326 }
1327
1328 pub fn to_i128_checked(self) -> Option<i128> {
1330 let negative = self.is_negative();
1331 let mag = *self.unsigned_abs().as_limbs();
1332 let mut i = 2;
1334 while i < N {
1335 if mag[i] != 0 {
1336 return None;
1337 }
1338 i += 1;
1339 }
1340 let lo = if N > 0 { mag[0] as u128 } else { 0 };
1341 let hi = if N > 1 { mag[1] as u128 } else { 0 };
1342 let lo_u128 = lo | (hi << 64);
1343 if negative {
1344 if lo_u128 <= (i128::MAX as u128) + 1 {
1345 Some((lo_u128 as i128).wrapping_neg())
1346 } else {
1347 None
1348 }
1349 } else if lo_u128 <= i128::MAX as u128 {
1350 Some(lo_u128 as i128)
1351 } else {
1352 None
1353 }
1354 }
1355
1356 pub fn to_u128_checked(self) -> Option<u128> {
1358 if self.is_negative() {
1359 return None;
1360 }
1361 let mut i = 2;
1362 while i < N {
1363 if self.limbs[i] != 0 {
1364 return None;
1365 }
1366 i += 1;
1367 }
1368 let lo = if N > 0 { self.limbs[0] as u128 } else { 0 };
1369 let hi = if N > 1 { self.limbs[1] as u128 } else { 0 };
1370 Some(lo | (hi << 64))
1371 }
1372
1373 pub fn to_f64(self) -> f64 {
1376 let mag = *self.unsigned_abs().as_limbs();
1377 let radix: f64 = 18_446_744_073_709_551_616.0; let mut acc = 0.0f64;
1379 let mut i = N;
1380 while i > 0 {
1381 i -= 1;
1382 acc = acc * radix + mag[i] as f64;
1383 }
1384 if self.is_negative() { -acc } else { acc }
1385 }
1386
1387 pub fn to_f32(self) -> f32 {
1391 self.to_f64() as f32
1392 }
1393
1394 pub(crate) const fn try_from_f64(v: f64) -> Option<Self> {
1401 let bits = v.to_bits();
1402 let negative = (bits >> 63) & 1 == 1;
1403 let exp = ((bits >> 52) & 0x7ff) as i32;
1404 let mant = bits & 0x000f_ffff_ffff_ffff;
1405 if exp == 0x7ff {
1406 return None;
1408 }
1409 if exp == 0 {
1410 return if mant == 0 { Some(Self::ZERO) } else { None };
1413 }
1414 let significand = (1u64 << 52) | mant; let shift = exp - 1075; Self::from_significand_shift(significand, shift, negative)
1417 }
1418
1419 pub(crate) const fn try_from_f32(v: f32) -> Option<Self> {
1425 let bits = v.to_bits();
1426 let negative = (bits >> 31) & 1 == 1;
1427 let exp = ((bits >> 23) & 0xff) as i32;
1428 let mant = (bits & 0x007f_ffff) as u64;
1429 if exp == 0xff {
1430 return None;
1432 }
1433 if exp == 0 {
1434 return if mant == 0 { Some(Self::ZERO) } else { None };
1435 }
1436 let significand = (1u64 << 23) | mant; let shift = exp - 150; Self::from_significand_shift(significand, shift, negative)
1439 }
1440
1441 const fn from_significand_shift(significand: u64, shift: i32, negative: bool) -> Option<Self> {
1447 if shift < 0 {
1448 let s = (-shift) as u32;
1449 if s >= 64 {
1450 return None;
1453 }
1454 if significand & ((1u64 << s) - 1) != 0 {
1455 return None;
1457 }
1458 let mag = significand >> s; let built = Self::from_mag_limbs(&[mag], negative);
1460 Self::accept_signed(built, negative)
1461 } else {
1462 let s = shift as u32;
1465 let limb_off = (s / 64) as usize;
1466 let bit_off = s % 64;
1467 let mut mag = [0u64; N];
1468 let lo = significand << bit_off;
1470 let hi = if bit_off == 0 {
1472 0
1473 } else {
1474 significand >> (64 - bit_off)
1475 };
1476 if limb_off < N {
1477 mag[limb_off] = lo;
1478 } else if lo != 0 {
1479 return None;
1480 }
1481 if hi != 0 {
1482 if limb_off + 1 < N {
1483 mag[limb_off + 1] = hi;
1484 } else {
1485 return None;
1486 }
1487 }
1488 let built = Self::from_mag_limbs(&mag, negative);
1489 Self::accept_signed(built, negative)
1490 }
1491 }
1492
1493 #[inline]
1499 const fn accept_signed(built: Self, negative: bool) -> Option<Self> {
1500 if is_zero_fixed(&built.limbs) {
1503 Some(built)
1504 } else if built.is_negative() != negative {
1505 None
1506 } else {
1507 Some(built)
1508 }
1509 }
1510
1511 pub fn from_f64(v: f64) -> Self {
1514 if !v.is_finite() {
1515 return Self::ZERO;
1516 }
1517 let negative = v < 0.0;
1518 let mut m = if negative { -v } else { v };
1519 let radix: f64 = 18_446_744_073_709_551_616.0; let mut limbs = [0u64; N];
1521 let mut i = 0;
1522 while m >= 1.0 && i < N {
1523 let rem = m % radix;
1524 limbs[i] = rem as u64;
1525 m = (m - rem) / radix;
1526 i += 1;
1527 }
1528 if m >= 1.0 {
1529 return if negative {
1530 Self::min_value()
1531 } else {
1532 Self::max_value()
1533 };
1534 }
1535 Self::from_mag_limbs(&limbs, negative)
1536 }
1537
1538 pub const fn from_str_radix(s: &str, radix: u32) -> Result<Self, ()> {
1542 if radix != 10 {
1543 return Err(());
1544 }
1545 let bytes = s.as_bytes();
1546 let (negative, start): (bool, usize) = if !bytes.is_empty() && bytes[0] == b'-' {
1547 (true, 1)
1548 } else {
1549 (false, 0)
1550 };
1551 if start >= bytes.len() {
1552 return Err(());
1553 }
1554 let mut acc = [0u64; N];
1559 let mut k = start;
1560 while k < bytes.len() {
1561 let ch = bytes[k];
1562 if ch < b'0' || ch > b'9' {
1563 return Err(());
1564 }
1565 let d = (ch - b'0') as u64;
1566 let mut carry: u64 = d;
1567 let mut j = 0;
1568 while j < N {
1569 let p = (acc[j] as u128) * 10u128 + (carry as u128);
1570 acc[j] = p as u64;
1571 carry = (p >> 64) as u64;
1572 j += 1;
1573 }
1574 k += 1;
1575 }
1576 Ok(Self::from_mag_limbs(&acc, negative))
1577 }
1578
1579 #[inline]
1587 pub const fn pow(self, exp: u32) -> Self {
1588 self.wrapping_pow(exp)
1589 }
1590
1591 #[inline]
1595 pub fn isqrt(self) -> Self {
1596 Self::from_limbs(*self.unsigned_abs().isqrt().as_limbs())
1597 }
1598
1599 #[inline]
1603 pub fn sqr(self) -> Self {
1604 self.wrapping_sqr()
1605 }
1606
1607 #[inline]
1611 pub fn cube(self) -> Self {
1612 self.wrapping_cube()
1613 }
1614
1615 #[inline]
1619 pub fn icbrt(self) -> Self {
1620 Self::from_limbs(*self.unsigned_abs().icbrt().as_limbs())
1621 }
1622
1623 #[inline]
1633 #[must_use]
1634 pub(crate) fn hypot(
1635 self,
1636 other: Self,
1637 mode: crate::support::rounding::RoundingMode,
1638 ) -> Option<Self>
1639 where
1640 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
1641 {
1642 hypot_dispatch::<N>(self, other, mode)
1643 }
1644
1645 #[inline]
1656 #[must_use]
1657 pub(crate) fn sum_sq(self, other: Self) -> Option<Self>
1658 where
1659 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
1660 {
1661 sum_sq_dispatch::<N>(self, other)
1662 }
1663
1664 #[inline]
1666 pub const fn cast_unsigned(self) -> Uint<N> {
1667 Uint::from_limbs(self.limbs)
1668 }
1669
1670 #[inline]
1673 pub fn as_f64(self) -> f64 {
1674 self.to_f64()
1675 }
1676
1677 #[inline]
1684 pub const fn count_ones(self) -> u32 {
1685 let mut total = 0;
1686 let mut i = 0;
1687 while i < N {
1688 total += self.limbs[i].count_ones();
1689 i += 1;
1690 }
1691 total
1692 }
1693
1694 #[inline]
1699 pub const fn count_zeros(self) -> u32 {
1700 Self::BITS - self.count_ones()
1701 }
1702
1703 #[inline]
1709 pub const fn trailing_zeros(self) -> u32 {
1710 let mut i = 0;
1711 while i < N {
1712 if self.limbs[i] != 0 {
1713 return i as u32 * 64 + self.limbs[i].trailing_zeros();
1714 }
1715 i += 1;
1716 }
1717 Self::BITS
1718 }
1719
1720 #[inline]
1723 pub const fn checked_neg(self) -> Option<Self> {
1724 if eq_dispatch(self, Self::MIN) {
1725 None
1726 } else {
1727 Some(self.wrapping_neg())
1728 }
1729 }
1730
1731 #[inline]
1733 pub const fn checked_div(self, rhs: Self) -> Option<Self> {
1734 if is_zero_fixed(&rhs.limbs) {
1735 None
1736 } else {
1737 Some(self.wrapping_div(rhs))
1738 }
1739 }
1740
1741 #[inline]
1745 pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
1746 if is_zero_fixed(&rhs.limbs) || self.is_min_neg_one(rhs) {
1747 None
1750 } else {
1751 Some(self.wrapping_rem(rhs))
1752 }
1753 }
1754
1755 #[inline]
1758 const fn is_min_neg_one(self, rhs: Self) -> bool {
1759 cmp_fixed(&self.limbs, &Self::MIN.limbs) == 0
1760 && cmp_fixed(&rhs.wrapping_neg().limbs, &Self::ONE.limbs) == 0
1761 }
1762
1763 #[inline]
1766 pub const fn div_euclid(self, rhs: Self) -> Self {
1767 let q = self.wrapping_div(rhs);
1768 let r = self.wrapping_rem(rhs);
1769 if r.is_negative() {
1770 if rhs.is_negative() {
1771 q.wrapping_add(Self::ONE)
1772 } else {
1773 q.wrapping_sub(Self::ONE)
1774 }
1775 } else {
1776 q
1777 }
1778 }
1779
1780 #[inline]
1782 pub const fn rem_euclid(self, rhs: Self) -> Self {
1783 let r = self.wrapping_rem(rhs);
1784 if r.is_negative() {
1785 r.wrapping_add(rhs.abs())
1786 } else {
1787 r
1788 }
1789 }
1790
1791 #[inline]
1793 pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
1794 let r = self.wrapping_add(rhs);
1795 let sa = self.is_negative();
1796 let sb = rhs.is_negative();
1797 let sr = r.is_negative();
1798 (r, sa == sb && sr != sa)
1799 }
1800
1801 #[inline]
1804 pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
1805 let r = self.wrapping_sub(rhs);
1806 let sa = self.is_negative();
1807 let sb = rhs.is_negative();
1808 let sr = r.is_negative();
1809 (r, sa != sb && sr != sa)
1810 }
1811
1812 #[inline]
1815 pub const fn overflowing_neg(self) -> (Self, bool) {
1816 let ov = cmp_fixed(&self.limbs, &Self::MIN.limbs) == 0;
1817 (self.wrapping_neg(), ov)
1818 }
1819
1820 #[inline]
1824 pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
1825 if self.is_min_neg_one(rhs) {
1826 (Self::ZERO, true)
1827 } else {
1828 (self.wrapping_rem(rhs), false)
1829 }
1830 }
1831
1832 #[inline]
1834 pub const fn saturating_add(self, rhs: Self) -> Self {
1835 match self.checked_add(rhs) {
1836 Some(v) => v,
1837 None => {
1838 if self.is_negative() {
1839 Self::MIN
1840 } else {
1841 Self::MAX
1842 }
1843 }
1844 }
1845 }
1846
1847 #[inline]
1849 pub const fn saturating_sub(self, rhs: Self) -> Self {
1850 match self.checked_sub(rhs) {
1851 Some(v) => v,
1852 None => {
1853 if self.is_negative() {
1854 Self::MIN
1855 } else {
1856 Self::MAX
1857 }
1858 }
1859 }
1860 }
1861
1862 #[inline]
1864 pub const fn saturating_neg(self) -> Self {
1865 match self.checked_neg() {
1866 Some(v) => v,
1867 None => Self::MAX,
1868 }
1869 }
1870
1871 #[inline]
1873 pub fn rotate_left(self, n: u32) -> Self {
1874 let bits = Self::BITS;
1875 let n = n % bits;
1876 if n == 0 {
1877 return self;
1878 }
1879 let u = self.cast_unsigned();
1880 Self::from_limbs(((u.shl(n)) | (u.shr(bits - n))).limbs)
1881 }
1882
1883 #[inline]
1885 pub fn rotate_right(self, n: u32) -> Self {
1886 self.rotate_left(Self::BITS - (n % Self::BITS))
1887 }
1888
1889 #[inline]
1894 pub(crate) const fn as_u128(self) -> u128 {
1895 let mag = *self.unsigned_abs().as_limbs();
1896 let lo = if N > 0 { mag[0] as u128 } else { 0 };
1897 let hi = if N > 1 { mag[1] as u128 } else { 0 };
1898 lo | (hi << 64)
1899 }
1900
1901 #[inline]
1906 pub(crate) const fn as_i128(self) -> i128 {
1907 if N <= 2 {
1913 if N == 1 {
1914 return (self.limbs[0] as i64) as i128;
1915 }
1916 let lo = self.limbs[0] as u128;
1917 let hi = self.limbs[1] as u128;
1918 return (lo | (hi << 64)) as i128;
1919 }
1920 let mag = *self.unsigned_abs().as_limbs();
1921 let lo = if N > 0 { mag[0] as u128 } else { 0 };
1922 let hi = if N > 1 { mag[1] as u128 } else { 0 };
1923 let combined = lo | (hi << 64);
1924 if self.is_negative() {
1925 (combined as i128).wrapping_neg()
1926 } else {
1927 combined as i128
1928 }
1929 }
1930
1931 #[inline]
1936 pub(crate) fn resize<T: crate::int::types::traits::BigInt>(self) -> T {
1937 use crate::int::types::traits::BigInt as _;
1938 self.resize_to::<T>()
1939 }
1940
1941 #[inline]
1945 pub const fn wrapping_div(self, rhs: Self) -> Self {
1946 if is_zero_fixed(&rhs.limbs) {
1947 panic!("attempt to divide by zero");
1948 }
1949 let negative = self.is_negative() ^ rhs.is_negative();
1950 let mut q = [0u64; N];
1951 let mut r = [0u64; N];
1952 div_rem(
1953 self.unsigned_abs().as_limbs(),
1954 rhs.unsigned_abs().as_limbs(),
1955 &mut q,
1956 &mut r,
1957 );
1958 Self::from_mag_limbs(&q, negative)
1959 }
1960
1961 #[inline]
1964 pub const fn wrapping_rem(self, rhs: Self) -> Self {
1965 if is_zero_fixed(&rhs.limbs) {
1966 panic!("attempt to calculate the remainder with a divisor of zero");
1967 }
1968 let mut q = [0u64; N];
1969 let mut r = [0u64; N];
1970 div_rem(
1971 self.unsigned_abs().as_limbs(),
1972 rhs.unsigned_abs().as_limbs(),
1973 &mut q,
1974 &mut r,
1975 );
1976 Self::from_mag_limbs(&r, self.is_negative())
1977 }
1978
1979 #[inline]
1984 pub(crate) fn widen_mul<W>(self, rhs: Self) -> W
1985 where
1986 W: crate::int::types::traits::BigInt,
1987 W::Scratch: crate::int::types::compute_limbs::ComputeLimbs,
1988 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
1989 {
1990 use crate::int::types::compute_limbs::{ComputeLimbs, Limbs};
1991 let negative = self.is_negative() ^ rhs.is_negative();
1992 let a = *self.unsigned_abs().as_limbs();
1993 let b = *rhs.unsigned_abs().as_limbs();
1994 let mut prod_buf = <Limbs<N> as ComputeLimbs>::double_buffered_u64();
2002 let prod = prod_buf.as_mut();
2003 mul_fast::<N>(&a, &b, &mut prod[..2 * N]);
2004 let mut u128_buf = <W::Scratch as ComputeLimbs>::single_u128();
2009 let u128_prod = u128_buf.as_mut();
2010 let mut i = 0;
2011 while i < N {
2012 u128_prod[i] = (prod[2 * i] as u128) | ((prod[2 * i + 1] as u128) << 64);
2013 i += 1;
2014 }
2015 W::from_mag_sign_u128(&u128_prod[..N], negative)
2016 }
2017}
2018
2019impl<const N: usize> Int<N> {
2020 #[inline]
2029 pub(crate) const fn cmp_cross<const M: usize>(self, other: Int<M>) -> Ordering {
2030 let sn = self.is_negative();
2031 let so = other.is_negative();
2032 if sn && !so {
2033 return Ordering::Less;
2034 }
2035 if !sn && so {
2036 return Ordering::Greater;
2037 }
2038 let a = self.unsigned_abs();
2040 let b = other.unsigned_abs();
2041 let c = cmp_cross(a.as_limbs(), b.as_limbs());
2042 let c = if sn { -c } else { c };
2044 if c < 0 {
2045 Ordering::Less
2046 } else if c > 0 {
2047 Ordering::Greater
2048 } else {
2049 Ordering::Equal
2050 }
2051 }
2052}
2053
2054impl<const N: usize> Int<N> {
2055 pub(crate) const fn cmp_cross_scaled<const M: usize>(
2083 self,
2084 other: Int<M>,
2085 scale_diff: u32,
2086 ) -> Ordering {
2087 let sn = self.is_negative();
2088 let so = other.is_negative();
2089 if sn && !so {
2090 return Ordering::Less;
2091 }
2092 if !sn && so {
2093 return Ordering::Greater;
2094 }
2095
2096 let a = self.unsigned_abs();
2099 let b = other.unsigned_abs();
2100
2101 let mag_cmp = if scale_diff == 0 {
2102 cmp_cross(a.as_limbs(), b.as_limbs())
2103 } else {
2104 let mut pow = [0u64; max_n_limbs(4)];
2109 pow[0] = 1;
2110 let mut e = 0;
2111 while e < scale_diff {
2112 let mut carry: u128 = 0;
2114 let mut i = 0;
2115 while i < pow.len() {
2116 let prod = (pow[i] as u128) * 10u128 + carry;
2117 pow[i] = prod as u64;
2118 carry = prod >> 64;
2119 i += 1;
2120 }
2121 e += 1;
2122 }
2123
2124 let mut q = [0u64; max_n_limbs(4)];
2126 let mut r = [0u64; max_n_limbs(4)];
2127 div_rem(a.as_limbs(), &pow, &mut q, &mut r);
2128
2129 let c = cmp_cross(&q, b.as_limbs());
2131 if c != 0 {
2132 c
2133 } else {
2134 let mut rk = 0;
2136 let mut nz = false;
2137 while rk < r.len() {
2138 if r[rk] != 0 {
2139 nz = true;
2140 break;
2141 }
2142 rk += 1;
2143 }
2144 if nz {
2145 1
2146 } else {
2147 0
2148 }
2149 }
2150 };
2151
2152 let c = if sn { -mag_cmp } else { mag_cmp };
2154 if c < 0 {
2155 Ordering::Less
2156 } else if c > 0 {
2157 Ordering::Greater
2158 } else {
2159 Ordering::Equal
2160 }
2161 }
2162}
2163
2164impl<const N: usize> Int<N> {
2165 pub(crate) const fn cmp_f64_exact(self, scale: u32, value: f64) -> Ordering {
2190 let bits = value.to_bits();
2191 let fsign = (bits >> 63) != 0;
2192 let exp_field = ((bits >> 52) & 0x7ff) as i32;
2193 let frac = bits & 0x000f_ffff_ffff_ffff;
2194 let (m, e): (u64, i32) = if exp_field == 0 {
2196 (frac, -1074)
2198 } else {
2199 (frac | 0x0010_0000_0000_0000, exp_field - 1075)
2200 };
2201
2202 let sn = self.is_negative();
2203 let fzero = m == 0;
2204 if fzero {
2206 let self_limbs = self.as_limbs();
2208 let mut nz = false;
2209 let mut k = 0;
2210 while k < self_limbs.len() {
2211 if self_limbs[k] != 0 {
2212 nz = true;
2213 break;
2214 }
2215 k += 1;
2216 }
2217 if !nz {
2218 return Ordering::Equal;
2219 }
2220 return if sn { Ordering::Less } else { Ordering::Greater };
2221 }
2222 if sn && !fsign {
2223 return Ordering::Less;
2224 }
2225 if !sn && fsign {
2226 return Ordering::Greater;
2227 }
2228
2229 let a = self.unsigned_abs();
2235 let a_limbs = a.as_limbs();
2236
2237 let mut pow10 = [0u64; 288];
2239 pow10[0] = 1;
2240 let mut pe = 0;
2241 while pe < scale {
2242 let mut carry: u128 = 0;
2243 let mut i = 0;
2244 while i < pow10.len() {
2245 let prod = (pow10[i] as u128) * 10u128 + carry;
2246 pow10[i] = prod as u64;
2247 carry = prod >> 64;
2248 i += 1;
2249 }
2250 pe += 1;
2251 }
2252
2253 let m_limbs = [m];
2254
2255 let mut lhs = [0u64; 288];
2256 let mut rhs = [0u64; 288];
2257
2258 if e >= 0 {
2259 let mut i = 0;
2261 while i < a_limbs.len() {
2262 lhs[i] = a_limbs[i];
2263 i += 1;
2264 }
2265 let mut tmp = [0u64; 288];
2267 mul_schoolbook(&m_limbs, &pow10, &mut tmp);
2268 shl(&tmp, e as u32, &mut rhs);
2270 } else {
2271 shl(a_limbs, (-e) as u32, &mut lhs);
2273 mul_schoolbook(&m_limbs, &pow10, &mut rhs);
2274 }
2275
2276 let mag_cmp = cmp_cross(&lhs, &rhs);
2277 let c = if sn { -mag_cmp } else { mag_cmp };
2279 if c < 0 {
2280 Ordering::Less
2281 } else if c > 0 {
2282 Ordering::Greater
2283 } else {
2284 Ordering::Equal
2285 }
2286 }
2287}
2288
2289impl<const N: usize, const M: usize> PartialEq<Int<M>> for Int<N> {
2295 #[inline]
2296 fn eq(&self, other: &Int<M>) -> bool {
2297 self.cmp_cross(*other) == Ordering::Equal
2298 }
2299}
2300
2301impl<const N: usize, const M: usize> PartialOrd<Int<M>> for Int<N> {
2302 #[inline]
2303 fn partial_cmp(&self, other: &Int<M>) -> Option<Ordering> {
2304 Some(self.cmp_cross(*other))
2305 }
2306}
2307
2308impl From<Int<2>> for i128 {
2317 #[inline]
2318 fn from(v: Int<2>) -> i128 {
2319 v.as_i128()
2320 }
2321}
2322
2323impl PartialEq<i128> for Int<2> {
2324 #[inline]
2325 fn eq(&self, other: &i128) -> bool {
2326 self.as_i128() == *other
2327 }
2328}
2329impl PartialEq<Int<2>> for i128 {
2330 #[inline]
2331 fn eq(&self, other: &Int<2>) -> bool {
2332 *self == other.as_i128()
2333 }
2334}
2335impl PartialOrd<i128> for Int<2> {
2336 #[inline]
2337 fn partial_cmp(&self, other: &i128) -> Option<Ordering> {
2338 self.as_i128().partial_cmp(other)
2339 }
2340}
2341impl PartialOrd<Int<2>> for i128 {
2342 #[inline]
2343 fn partial_cmp(&self, other: &Int<2>) -> Option<Ordering> {
2344 self.partial_cmp(&other.as_i128())
2345 }
2346}
2347
2348impl From<Int<1>> for i64 {
2353 #[inline]
2354 fn from(v: Int<1>) -> i64 {
2355 v.as_i128() as i64
2356 }
2357}
2358impl From<Int<1>> for i128 {
2360 #[inline]
2361 fn from(v: Int<1>) -> i128 {
2362 v.as_i128()
2363 }
2364}
2365impl PartialEq<i64> for Int<1> {
2366 #[inline]
2367 fn eq(&self, other: &i64) -> bool {
2368 self.as_i128() == *other as i128
2369 }
2370}
2371impl PartialEq<Int<1>> for i64 {
2372 #[inline]
2373 fn eq(&self, other: &Int<1>) -> bool {
2374 *self as i128 == other.as_i128()
2375 }
2376}
2377impl PartialOrd<i64> for Int<1> {
2378 #[inline]
2379 fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
2380 self.as_i128().partial_cmp(&(i128::from(*other)))
2381 }
2382}
2383impl PartialOrd<Int<1>> for i64 {
2384 #[inline]
2385 fn partial_cmp(&self, other: &Int<1>) -> Option<Ordering> {
2386 i128::from(*self).partial_cmp(&other.as_i128())
2387 }
2388}
2389
2390impl<const N: usize> Ord for Int<N> {
2391 #[inline]
2392 fn cmp(&self, other: &Self) -> Ordering {
2393 cmp_dispatch(*self, *other)
2397 }
2398}
2399
2400impl<const N: usize> Add for Int<N> {
2401 type Output = Self;
2402 #[inline]
2403 fn add(self, rhs: Self) -> Self {
2404 add_dispatch(self, rhs)
2405 }
2406}
2407
2408impl<const N: usize> Sub for Int<N> {
2409 type Output = Self;
2410 #[inline]
2411 fn sub(self, rhs: Self) -> Self {
2412 self.wrapping_sub(rhs)
2413 }
2414}
2415
2416impl<const N: usize> Mul for Int<N> {
2417 type Output = Self;
2418 #[inline]
2419 fn mul(self, rhs: Self) -> Self {
2420 self.wrapping_mul(rhs)
2421 }
2422}
2423
2424impl<const N: usize> BitAnd for Int<N> {
2425 type Output = Self;
2426 #[inline]
2427 fn bitand(self, rhs: Self) -> Self {
2428 let mut out = [0u64; N];
2429 let mut i = 0;
2430 while i < N {
2431 out[i] = self.limbs[i] & rhs.limbs[i];
2432 i += 1;
2433 }
2434 Self { limbs: out }
2435 }
2436}
2437
2438impl<const N: usize> BitOr for Int<N> {
2439 type Output = Self;
2440 #[inline]
2441 fn bitor(self, rhs: Self) -> Self {
2442 let mut out = [0u64; N];
2443 let mut i = 0;
2444 while i < N {
2445 out[i] = self.limbs[i] | rhs.limbs[i];
2446 i += 1;
2447 }
2448 Self { limbs: out }
2449 }
2450}
2451
2452impl<const N: usize> BitXor for Int<N> {
2453 type Output = Self;
2454 #[inline]
2455 fn bitxor(self, rhs: Self) -> Self {
2456 let mut out = [0u64; N];
2457 let mut i = 0;
2458 while i < N {
2459 out[i] = self.limbs[i] ^ rhs.limbs[i];
2460 i += 1;
2461 }
2462 Self { limbs: out }
2463 }
2464}
2465
2466impl<const N: usize> Not for Int<N> {
2467 type Output = Self;
2468 #[inline]
2469 fn not(self) -> Self {
2470 let mut out = [0u64; N];
2471 let mut i = 0;
2472 while i < N {
2473 out[i] = !self.limbs[i];
2474 i += 1;
2475 }
2476 Self { limbs: out }
2477 }
2478}
2479
2480impl<const N: usize> Shl<u32> for Int<N> {
2481 type Output = Self;
2482 #[inline]
2483 fn shl(self, shift: u32) -> Self {
2484 let mut out = [0u64; N];
2485 shl_fixed(&self.limbs, shift, &mut out);
2486 Self { limbs: out }
2487 }
2488}
2489
2490impl<const N: usize> Shr<u32> for Int<N> {
2491 type Output = Self;
2492 #[inline]
2493 fn shr(self, shift: u32) -> Self {
2494 let neg = self.is_negative();
2498 let src = if neg { !self } else { self };
2499 let mut out = [0u64; N];
2500 shr_fixed(&src.limbs, shift, &mut out);
2501 let shifted = Self { limbs: out };
2502 if neg { !shifted } else { shifted }
2503 }
2504}
2505
2506impl<const N: usize> Neg for Int<N> {
2507 type Output = Self;
2508 #[inline]
2509 fn neg(self) -> Self {
2510 self.wrapping_neg()
2511 }
2512}
2513
2514impl<const N: usize> Div for Int<N> {
2522 type Output = Self;
2523 #[inline]
2524 fn div(self, rhs: Self) -> Self {
2525 self.div_rem(rhs).0
2526 }
2527}
2528
2529impl<const N: usize> Rem for Int<N> {
2530 type Output = Self;
2531 #[inline]
2532 fn rem(self, rhs: Self) -> Self {
2533 rem_dispatch(self, rhs)
2534 }
2535}
2536
2537impl<const N: usize> core::fmt::Display for Uint<N>
2543where
2544 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2545{
2546 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2547 let mut buf =
2551 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2552 let s = fmt_into::<N>(&self.limbs, 10, true, buf.as_mut());
2553 f.pad_integral(true, "", s)
2554 }
2555}
2556
2557impl<const N: usize> core::fmt::Display for Int<N>
2558where
2559 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2560{
2561 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2562 let mag = *self.unsigned_abs().as_limbs();
2563 let mut buf =
2568 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2569 let s = fmt_into::<N>(&mag, 10, true, buf.as_mut());
2570 f.pad_integral(!self.is_negative() || self.is_zero(), "", s)
2571 }
2572}
2573
2574impl<const N: usize> core::str::FromStr for Int<N> {
2575 type Err = ();
2576 #[inline]
2577 fn from_str(s: &str) -> Result<Self, ()> {
2578 Self::from_str_radix(s, 10)
2579 }
2580}
2581
2582impl<const N: usize> core::fmt::LowerHex for Int<N>
2592where
2593 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2594{
2595 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2596 let mut buf =
2597 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2598 let s = fmt_into::<N>(&self.limbs, 16, true, buf.as_mut());
2599 f.pad_integral(true, "0x", s)
2600 }
2601}
2602
2603impl<const N: usize> core::fmt::UpperHex for Int<N>
2604where
2605 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2606{
2607 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2608 let mut buf =
2609 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2610 let s = fmt_into::<N>(&self.limbs, 16, false, buf.as_mut());
2611 f.pad_integral(true, "0x", s)
2612 }
2613}
2614
2615impl<const N: usize> core::fmt::Octal for Int<N>
2616where
2617 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2618{
2619 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2620 let mut buf =
2621 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::bit_formatting_limbs_u8();
2622 let s = fmt_into::<N>(&self.limbs, 8, true, buf.as_mut());
2623 f.pad_integral(true, "0o", s)
2624 }
2625}
2626
2627impl<const N: usize> core::fmt::Binary for Int<N>
2628where
2629 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2630{
2631 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2632 let mut buf =
2633 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::bit_formatting_limbs_u8();
2634 let s = fmt_into::<N>(&self.limbs, 2, true, buf.as_mut());
2635 f.pad_integral(true, "0b", s)
2636 }
2637}
2638
2639impl<const N: usize> Uint<N> {
2652 #[inline]
2659 pub const fn resize_n<const M: usize>(self) -> Uint<M> {
2660 let mut out = [0u64; M];
2661 let mut i = 0;
2662 while i < M {
2663 if i < N {
2664 out[i] = self.limbs[i];
2665 }
2666 i += 1;
2667 }
2668 Uint::from_limbs(out)
2669 }
2670
2671 #[inline]
2674 pub fn widen<const M: usize>(self) -> Uint<M> {
2675 debug_assert!(M >= N, "widen requires M >= N");
2676 self.resize_n::<M>()
2677 }
2678
2679 #[inline]
2682 pub fn narrow<const M: usize>(self) -> Option<Uint<M>> {
2683 debug_assert!(M <= N, "narrow requires M <= N");
2684 let keep = if M < N { M } else { N };
2685 let mut i = keep;
2686 while i < N {
2687 if self.limbs[i] != 0 {
2688 return None;
2689 }
2690 i += 1;
2691 }
2692 Some(self.resize_n::<M>())
2693 }
2694}
2695
2696impl<const N: usize> Int<N> {
2697 #[inline]
2713 pub(crate) const fn resize_n<const M: usize>(self) -> Int<M> {
2714 let fill = if self.is_negative() { u64::MAX } else { 0 };
2715 let mut out = [0u64; M];
2716 let mut i = 0;
2717 while i < M {
2718 out[i] = if i < N { self.limbs[i] } else { fill };
2719 i += 1;
2720 }
2721 Int::from_limbs(out)
2722 }
2723
2724 #[inline]
2730 pub(crate) const fn try_narrow<const M: usize>(self) -> Option<Int<M>> {
2731 debug_assert!(M >= 1 && M <= N, "try_narrow requires 1 <= M <= N");
2732 let sign_fill = if (self.limbs[M - 1] >> 63) == 1 {
2733 u64::MAX
2734 } else {
2735 0
2736 };
2737 let mut i = M;
2738 while i < N {
2739 if self.limbs[i] != sign_fill {
2740 return None;
2741 }
2742 i += 1;
2743 }
2744 Some(self.resize_n::<M>())
2745 }
2746
2747 #[inline]
2749 pub fn widen<const M: usize>(self) -> Int<M> {
2750 debug_assert!(M >= N, "widen requires M >= N");
2751 self.resize_n::<M>()
2752 }
2753
2754 #[inline]
2759 pub fn narrow<const M: usize>(self) -> Option<Int<M>> {
2760 self.try_narrow::<M>()
2761 }
2762}
2763
2764
2765
2766macro_rules! int_from_signed {
2775 ($($prim:ty => $base:ident),+) => {$(
2776 impl<const N: usize> From<$prim> for Int<N> {
2777 #[inline]
2778 fn from(v: $prim) -> Self { Self::$base(v) }
2779 }
2780 )+};
2781}
2782int_from_signed!(i8 => from_i8, i16 => from_i16, i32 => from_i32, i64 => from_i64);
2783
2784macro_rules! int_from_unsigned {
2785 ($($prim:ty => $base:ident),+) => {$(
2786 impl<const N: usize> From<$prim> for Int<N> {
2787 #[inline]
2788 fn from(v: $prim) -> Self { Self::$base(v) }
2789 }
2790 )+};
2791}
2792int_from_unsigned!(u8 => from_u8, u16 => from_u16, u32 => from_u32);
2793
2794macro_rules! uint_from_unsigned {
2795 ($($prim:ty),+) => {$(
2796 impl<const N: usize> From<$prim> for Uint<N> {
2797 #[inline]
2798 fn from(v: $prim) -> Self { Self::from_u64(v as u64) }
2799 }
2800 )+};
2801}
2802uint_from_unsigned!(u8, u16, u32, u64);
2803
2804impl<const N: usize> TryFrom<u64> for Int<N> {
2807 type Error = crate::support::error::ConvertError;
2808 #[inline]
2809 fn try_from(v: u64) -> Result<Self, Self::Error> {
2810 Self::try_from_u64(v).ok_or(crate::support::error::ConvertError::Overflow)
2811 }
2812}
2813
2814impl<const N: usize> TryFrom<i128> for Int<N> {
2815 type Error = crate::support::error::ConvertError;
2816 #[inline]
2817 fn try_from(v: i128) -> Result<Self, Self::Error> {
2818 Self::try_from_i128(v).ok_or(crate::support::error::ConvertError::Overflow)
2819 }
2820}
2821
2822impl<const N: usize> TryFrom<u128> for Int<N> {
2823 type Error = crate::support::error::ConvertError;
2824 #[inline]
2825 fn try_from(v: u128) -> Result<Self, Self::Error> {
2826 Self::try_from_u128(v).ok_or(crate::support::error::ConvertError::Overflow)
2827 }
2828}
2829
2830impl<const N: usize> TryFrom<Int<N>> for i32 {
2839 type Error = crate::support::error::ConvertError;
2840 #[inline]
2841 fn try_from(v: Int<N>) -> Result<Self, Self::Error> {
2842 v.try_to_i32().ok_or(crate::support::error::ConvertError::Overflow)
2843 }
2844}
2845
2846impl<const N: usize> TryFrom<Int<N>> for u32 {
2847 type Error = crate::support::error::ConvertError;
2848 #[inline]
2849 fn try_from(v: Int<N>) -> Result<Self, Self::Error> {
2850 v.try_to_u32().ok_or(crate::support::error::ConvertError::Overflow)
2851 }
2852}
2853
2854impl<const N: usize> TryFrom<Int<N>> for u64 {
2855 type Error = crate::support::error::ConvertError;
2856 #[inline]
2857 fn try_from(v: Int<N>) -> Result<Self, Self::Error> {
2858 v.try_to_u64().ok_or(crate::support::error::ConvertError::Overflow)
2859 }
2860}
2861
2862impl<const N: usize> TryFrom<Int<N>> for u128 {
2863 type Error = crate::support::error::ConvertError;
2864 #[inline]
2865 fn try_from(v: Int<N>) -> Result<Self, Self::Error> {
2866 v.try_to_u128().ok_or(crate::support::error::ConvertError::Overflow)
2867 }
2868}
2869
2870impl<const N: usize> TryFrom<u128> for Uint<N> {
2871 type Error = crate::support::error::ConvertError;
2872 #[inline]
2873 fn try_from(v: u128) -> Result<Self, Self::Error> {
2874 Self::try_from_u128(v).ok_or(crate::support::error::ConvertError::Overflow)
2875 }
2876}
2877
2878impl<const N: usize> TryFrom<f64> for Int<N> {
2884 type Error = crate::support::error::ConvertError;
2885 #[inline]
2886 fn try_from(v: f64) -> Result<Self, Self::Error> {
2887 Self::try_from_f64(v).ok_or(crate::support::error::ConvertError::Overflow)
2888 }
2889}
2890
2891impl<const N: usize> TryFrom<f32> for Int<N> {
2892 type Error = crate::support::error::ConvertError;
2893 #[inline]
2894 fn try_from(v: f32) -> Result<Self, Self::Error> {
2895 Self::try_from_f32(v).ok_or(crate::support::error::ConvertError::Overflow)
2896 }
2897}
2898
2899#[cfg(test)]
2900mod tests {
2901 use super::*;
2902 use crate::int::algos::mul::mul_schoolbook::{mul_low_fixed, mul_schoolbook_fixed};
2903
2904 #[test]
2905 fn try_from_i128_detects_narrow_overflow() {
2906 assert_eq!(Int::<2>::try_from_i128(i128::MAX), Some(Int::<2>::from_i128(i128::MAX)));
2908 assert_eq!(Int::<2>::try_from_i128(i128::MIN), Some(Int::<2>::from_i128(i128::MIN)));
2909 assert_eq!(Int::<1>::try_from_i128(i64::MAX as i128 + 1), None);
2911 assert_eq!(Int::<1>::try_from_i128(i64::MIN as i128 - 1), None);
2912 assert_eq!(
2913 Int::<1>::try_from_i128(i64::MAX as i128),
2914 Some(Int::<1>::from_i64(i64::MAX))
2915 );
2916 assert!(<Int<1> as TryFrom<i128>>::try_from(i64::MAX as i128 + 1).is_err());
2918 assert_eq!(<Int<2> as TryFrom<i128>>::try_from(-5_i128), Ok(Int::<2>::from_i64(-5)));
2919 }
2920
2921 #[test]
2922 fn try_from_u128_detects_narrow_overflow() {
2923 assert_eq!(Uint::<2>::try_from_u128(u128::MAX), Some(Uint::<2>::from_u128(u128::MAX)));
2925 assert_eq!(Uint::<1>::try_from_u128(u64::MAX as u128 + 1), None);
2926 assert_eq!(Uint::<1>::try_from_u128(u64::MAX as u128), Some(Uint::<1>::from_u64(u64::MAX)));
2927 assert!(<Uint<1> as TryFrom<u128>>::try_from(u64::MAX as u128 + 1).is_err());
2928 assert_eq!(Int::<1>::try_from_u128(u64::MAX as u128), None);
2930 assert_eq!(Int::<2>::try_from_u128(u128::MAX), None);
2931 assert_eq!(Int::<3>::try_from_u128(u128::MAX), Some(Int::<3>::from_u128(u128::MAX)));
2932 assert!(<Int<2> as TryFrom<u128>>::try_from(u128::MAX).is_err());
2933 }
2934
2935 #[test]
2936 fn try_from_u64_and_out_conversions_at_edges() {
2937 assert!(<Int<1> as TryFrom<u64>>::try_from(u64::MAX).is_err());
2939 assert_eq!(<Int<2> as TryFrom<u64>>::try_from(u64::MAX), Ok(Int::<2>::from_u128(u64::MAX as u128)));
2940 assert_eq!(i128::from(Int::<2>::MAX), i128::MAX);
2942 assert_eq!(i128::from(Int::<2>::MIN), i128::MIN);
2943 assert_eq!(i64::from(Int::<1>::from_i64(-123)), -123_i64);
2944 let big = Int::<3>::from_u128(u128::MAX);
2947 assert_eq!(big.try_to_i128(), None);
2948 assert_eq!(<i32 as TryFrom<Int<4>>>::try_from(Int::<4>::from_i64(-7)), Ok(-7_i32));
2949 assert!(<u32 as TryFrom<Int<4>>>::try_from(Int::<4>::from_i64(-1)).is_err());
2950 }
2951
2952 #[test]
2953 fn float_conversions_reject_and_round_trip() {
2954 assert_eq!(Int::<2>::try_from_f64(f64::NAN), None);
2956 assert_eq!(Int::<2>::try_from_f64(f64::INFINITY), None);
2957 assert_eq!(Int::<2>::try_from_f64(f64::NEG_INFINITY), None);
2958 assert_eq!(Int::<2>::try_from_f64(0.5), None);
2959 assert_eq!(Int::<2>::try_from_f64(3.5), None);
2960 assert_eq!(Int::<2>::try_from_f32(f32::NAN), None);
2961 assert_eq!(Int::<2>::try_from_f32(f32::INFINITY), None);
2962 assert_eq!(Int::<2>::try_from_f32(0.5), None);
2963 assert_eq!(Int::<2>::try_from_f32(3.5), None);
2964 assert_eq!(Int::<1>::try_from_f64(1e30), None); assert_eq!(Int::<2>::try_from_f64(0.0), Some(Int::<2>::ZERO));
2967 assert_eq!(Int::<2>::try_from_f64(-0.0), Some(Int::<2>::ZERO));
2968 assert_eq!(Int::<2>::try_from_f32(0.0), Some(Int::<2>::ZERO));
2969 assert_eq!(Int::<2>::try_from_f32(-0.0), Some(Int::<2>::ZERO));
2970 assert_eq!(Int::<4>::try_from_f64(42.0), Some(Int::<4>::from_i64(42)));
2972 assert_eq!(Int::<4>::try_from_f64(-42.0), Some(Int::<4>::from_i64(-42)));
2973 assert_eq!(Int::<4>::try_from_f32(7.0), Some(Int::<4>::from_i64(7)));
2974 assert_eq!(Int::<4>::try_from_f32(-7.0), Some(Int::<4>::from_i64(-7)));
2975 assert!(<Int<2> as TryFrom<f64>>::try_from(f64::NAN).is_err());
2977 assert_eq!(<Int<2> as TryFrom<f64>>::try_from(-9.0), Ok(Int::<2>::from_i64(-9)));
2978 assert_eq!(<Int<2> as TryFrom<f32>>::try_from(-9.0), Ok(Int::<2>::from_i64(-9)));
2979 assert_eq!(Int::<4>::from_i64(123).to_f64(), 123.0);
2981 assert_eq!(Int::<4>::from_i64(-123).to_f64(), -123.0);
2982 assert_eq!(Int::<4>::from_i64(123).to_f32(), 123.0_f32);
2983 }
2984
2985 #[test]
2986 fn float_conversions_wide_and_boundaries() {
2987 let big = 2f64.powi(64); assert_eq!(Int::<1>::try_from_f64(big), None);
2991 assert_eq!(
2992 Int::<2>::try_from_f64(big),
2993 Some(Int::<2>::from_u128(1u128 << 64))
2994 );
2995
2996 let two_63 = 2f64.powi(63);
2999 assert_eq!(Int::<1>::try_from_f64(two_63), None);
3000 let near_max = (i64::MAX - 1023) as f64; assert_eq!(near_max as i64, i64::MAX - 1023);
3004 assert_eq!(
3005 Int::<1>::try_from_f64(near_max),
3006 Some(Int::<1>::from_i64(i64::MAX - 1023))
3007 );
3008
3009 let min_edge = -(2f64.powi(63));
3011 assert_eq!(
3012 Int::<1>::try_from_f64(min_edge),
3013 Some(Int::<1>::from_i64(i64::MIN))
3014 );
3015 assert_eq!(Int::<1>::try_from_f64(-(2f64.powi(64))), None);
3017
3018 let two_24 = 2f32.powi(24);
3020 assert_eq!(
3021 Int::<1>::try_from_f32(two_24),
3022 Some(Int::<1>::from_i64(1 << 24))
3023 );
3024 }
3025
3026 #[test]
3027 fn float_conversions_are_const() {
3028 const X: Option<Int<2>> = Int::<2>::try_from_f64(42.0);
3030 const Y: Option<Int<2>> = Int::<2>::try_from_f32(42.0);
3031 assert_eq!(X, Some(Int::<2>::from_i64(42)));
3032 assert_eq!(Y, Some(Int::<2>::from_i64(42)));
3033 }
3034
3035 #[test]
3036 fn from_traits_are_infallible_for_fitting_prims() {
3037 assert_eq!(Int::<1>::from(-7_i32), Int::<1>::from_i64(-7));
3038 assert_eq!(Int::<4>::from(42_i64), Int::<4>::from_i64(42));
3039 assert_eq!(Uint::<1>::from(7_u32), Uint::<1>::from_u64(7));
3040 assert_eq!(Uint::<4>::from(u64::MAX), Uint::<4>::from_u64(u64::MAX));
3041 }
3042
3043 #[test]
3047 fn fixed_int_trait_surface() {
3048 fn exercises<T: BigInt>(seven: T, three: T) {
3049 assert_eq!(T::LIMBS as u32 * 64, T::BITS);
3050 assert!(T::ZERO.is_zero());
3051 assert!(T::ONE.is_one());
3052 assert!(!T::ZERO.is_one());
3053
3054 let ten = seven + three;
3056 assert_eq!(ten - three, seven);
3057 assert_eq!(ten, seven.wrapping_add(three));
3058 assert_eq!(seven.wrapping_sub(three) + three, seven);
3059
3060 let _ = (seven & three) | (seven ^ three);
3062 let _ = !T::ZERO;
3063 assert_eq!((T::ONE << 4) >> 4, T::ONE);
3064
3065 assert_eq!(seven.checked_add(three), Some(ten));
3067 assert!(seven.checked_mul(three).is_some());
3068
3069 assert_eq!(three.sqr(), three * three);
3071 assert_eq!(three.cube(), three * three * three);
3072 assert_eq!(three.pow(2), three.sqr());
3073 assert_eq!(three.wrapping_pow(3), three.cube());
3074 assert_eq!(three.checked_pow(2), Some(three.sqr()));
3075
3076 assert_eq!(T::ONE.bit_length(), 1);
3078 assert_eq!(T::ZERO.bit_length(), 0);
3079 assert_eq!(T::ONE.leading_zeros(), T::BITS - 1);
3080
3081 let items = [T::ONE, T::ONE, T::ONE];
3083 assert_eq!(T::sum(items), three);
3084 assert_eq!(T::product([three, T::ONE]), three);
3085 assert_eq!(T::from_limbs(seven.to_limbs()), seven);
3086 }
3087
3088 exercises(Int::<4>::from_i64(7), Int::<4>::from_i64(3));
3089 exercises(Int::<6>::from_i64(7), Int::<6>::from_i64(3));
3090 }
3091
3092 #[test]
3095 fn limbs_mul_low_matches_full_product_low_half() {
3096 fn check<const N: usize, const D: usize>(a: [u64; N], b: [u64; N]) {
3097 debug_assert!(D == 2 * N);
3098 let mut full = [0u64; D];
3099 mul_schoolbook_fixed::<N, D>(&a, &b, &mut full);
3100 let mut low = [0u64; N];
3101 mul_low_fixed::<N>(&a, &b, &mut low);
3102 let mut expected = [0u64; N];
3103 expected.copy_from_slice(&full[..N]);
3104 assert_eq!(low, expected, "low-half mismatch for {a:?} * {b:?}");
3105 }
3106
3107 check::<4, 8>([0, 0, 0, 0], [0, 0, 0, 0]);
3109 check::<4, 8>([1, 0, 0, 0], [u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
3110 check::<4, 8>([u64::MAX; 4], [u64::MAX; 4]);
3111 check::<4, 8>([0, 1, 0, 0], [0, 1, 0, 0]); check::<4, 8>(
3113 [0xDEAD_BEEF, 0xCAFE_F00D, 0x1234, 0x5678_9ABC],
3114 [0xFEED_FACE, 0x0BAD_C0DE, 0x9999, 0x0000_0001],
3115 );
3116 check::<2, 4>([u64::MAX, u64::MAX], [3, 0]);
3118 check::<6, 12>([7, 8, 9, 10, 11, 12], [1, 2, 3, 4, 5, 6]);
3119 }
3120
3121 #[test]
3124 fn dedicated_sqr_matches_general_mul() {
3125 fn check<const N: usize>(x: [u64; N]) {
3126 let a = Uint::<N>::from_limbs(x);
3127 assert_eq!(
3128 a.wrapping_sqr(),
3129 a.wrapping_mul(a),
3130 "sqr != mul(self,self) for {x:?}"
3131 );
3132 }
3133
3134 check::<4>([0, 0, 0, 0]);
3136 check::<4>([1, 0, 0, 0]);
3137 check::<4>([u64::MAX; 4]);
3138 check::<4>([0x1234_5678, 0, 0, 0]);
3139 check::<4>([u64::MAX, u64::MAX, 0, 0]);
3140 check::<4>([0xDEAD_BEEF_CAFE_F00D, 0x0123_4567_89AB_CDEF, 0xFEDC, 0x99]);
3141 check::<4>([u64::MAX, u64::MAX, u64::MAX, 0]);
3143 check::<1>([u64::MAX]);
3145 check::<2>([u64::MAX, u64::MAX]);
3146 check::<6>([7, 8, 9, 10, 11, 12]);
3147 check::<8>([u64::MAX, 1, u64::MAX, 2, u64::MAX, 3, u64::MAX, 4]);
3148 let mut state = 0x9E37_79B9_7F4A_7C15u64;
3150 let mut next = || {
3151 state ^= state << 13;
3152 state ^= state >> 7;
3153 state ^= state << 17;
3154 state
3155 };
3156 for _ in 0..64 {
3157 check::<5>([next(), next(), next(), next(), next()]);
3158 }
3159 }
3160
3161 #[test]
3162 fn uint_sqr_cube_match_naive() {
3163 let x = Uint::<4>::from_limbs([123_456_789, 0, 0, 0]);
3164 assert_eq!(x.wrapping_sqr(), x.wrapping_mul(x));
3165 assert_eq!(x.wrapping_cube(), x.wrapping_mul(x).wrapping_mul(x));
3166
3167 let y = Uint::<4>::from_limbs([0xDEAD_BEEF_CAFE, 0x1234_5678, 0, 0]);
3169 assert_eq!(y.wrapping_sqr(), y.wrapping_mul(y));
3170 assert_eq!(y.wrapping_cube(), y.wrapping_mul(y).wrapping_mul(y));
3171 }
3172
3173 #[cfg(feature = "_wide-support")]
3181 #[test]
3182 fn root_int_floor_and_exactness() {
3183 fn brute(m: u128, k: u32) -> (u128, bool) {
3185 if m == 0 {
3186 return (0, true);
3187 }
3188 let mut r: u128 = 0;
3189 while {
3191 let next = r + 1;
3192 next.checked_pow(k).is_some_and(|p| p <= m)
3193 } {
3194 r += 1;
3195 }
3196 (r, r.pow(k) == m)
3197 }
3198
3199 fn check<const N: usize>(m: u128, k: u32) {
3200 let lo = (m & 0xFFFF_FFFF_FFFF_FFFF) as u64;
3201 let hi = (m >> 64) as u64;
3202 let mut limbs = [0u64; N];
3203 limbs[0] = lo;
3204 if N > 1 {
3205 limbs[1] = hi;
3206 }
3207 let n = Uint::<N>::from_limbs(limbs);
3208 let (root, exact) = n.root_int(k);
3209 let (eroot, eexact) = brute(m, k);
3210 let root_lo = root.as_limbs()[0] as u128
3211 | ((if N > 1 { root.as_limbs()[1] as u128 } else { 0 }) << 64);
3212 assert_eq!(root_lo, eroot, "root mismatch for m={m}, k={k}");
3213 assert_eq!(exact, eexact, "exact flag mismatch for m={m}, k={k}");
3214
3215 let rk = root.pow(k);
3217 assert!(rk <= n, "root^k > m for m={m}, k={k}");
3218 let next = root.wrapping_add(Uint::<N>::ONE);
3219 if let Some(p) = next.checked_pow(k) { assert!(p > n, "(root+1)^k <= m for m={m}, k={k}") }
3221 }
3222
3223 let samples: [u128; 14] = [
3224 0,
3225 1,
3226 2,
3227 7,
3228 8,
3229 9,
3230 26,
3231 27,
3232 28,
3233 1000,
3234 1023,
3235 1024,
3236 1_000_000,
3237 u64::MAX as u128,
3238 ];
3239 for &m in &samples {
3240 for k in [2u32, 3, 5] {
3241 check::<4>(m, k);
3242 check::<2>(m, k);
3243 check::<8>(m, k);
3244 }
3245 }
3246
3247 let big = Uint::<4>::from_limbs([0xFFFF_FFFF_FFFF_FFFF, 0x1234_5678, 0, 0]);
3249 assert_eq!(big.root_int(2).0, big.isqrt());
3250
3251 let base = Uint::<4>::ONE.shl(40);
3253 let cube = base.wrapping_cube();
3254 let (r, exact) = cube.root_int(3);
3255 assert_eq!(r, base);
3256 assert!(exact);
3257 let (r2, exact2) = cube.wrapping_sub(Uint::<4>::ONE).root_int(3);
3259 assert_eq!(r2, base.wrapping_sub(Uint::<4>::ONE));
3260 assert!(!exact2);
3261 }
3262
3263 #[test]
3264 fn uint_widen_zero_extends() {
3265 let a = Uint::<2>::from_limbs([7, 8]);
3266 let w = a.widen::<4>();
3267 assert_eq!(*w.as_limbs(), [7, 8, 0, 0]);
3268 assert_eq!(a.resize_n::<4>(), w);
3269 }
3270
3271 #[test]
3272 fn uint_narrow_checks_dropped_limbs() {
3273 let fits = Uint::<4>::from_limbs([7, 8, 0, 0]);
3274 assert_eq!(*fits.narrow::<2>().unwrap().as_limbs(), [7, 8]);
3275
3276 let too_big = Uint::<4>::from_limbs([7, 8, 1, 0]);
3277 assert!(too_big.narrow::<2>().is_none());
3278
3279 let a = Uint::<2>::from_limbs([3, 4]);
3281 assert_eq!(a.widen::<4>().narrow::<2>().unwrap(), a);
3282 }
3283
3284 #[test]
3285 fn int_widen_sign_extends() {
3286 let neg = Int::<2>::from_i64(-1);
3288 assert_eq!(*neg.widen::<4>().as_limbs(), [u64::MAX; 4]);
3289 assert_eq!(neg.widen::<4>(), Int::<4>::from_i64(-1));
3290 let pos = Int::<2>::from_i64(5);
3292 assert_eq!(*pos.widen::<4>().as_limbs(), [5, 0, 0, 0]);
3293 }
3294
3295 #[test]
3296 fn int_narrow_requires_sign_consistency() {
3297 let neg = Int::<4>::from_i64(-1);
3299 assert_eq!(neg.narrow::<2>().unwrap(), Int::<2>::from_i64(-1));
3300 let big = Int::<4>::from_limbs([0, 0, 1, 0]);
3302 assert!(big.narrow::<2>().is_none());
3303 let weird = Int::<4>::from_limbs([1, 0, 0, u64::MAX]);
3305 assert!(weird.narrow::<2>().is_none());
3306 let p = Int::<2>::from_i64(42);
3308 assert_eq!(p.widen::<4>().narrow::<2>().unwrap(), p);
3309 }
3310
3311 #[test]
3312 fn int_resize_const_two_complement() {
3313 let pos = Int::<2>::from_i64(123);
3315 let wide: Int<4> = pos.resize_n::<4>();
3316 assert_eq!(*wide.as_limbs(), [123, 0, 0, 0]);
3317 assert_eq!(wide.resize_n::<2>(), pos);
3318
3319 let neg = Int::<2>::from_i64(-7);
3321 let wneg: Int<4> = neg.resize_n::<4>();
3322 assert_eq!(*wneg.as_limbs(), [(-7i64) as u64, u64::MAX, u64::MAX, u64::MAX]);
3323 assert_eq!(wneg, Int::<4>::from_i64(-7));
3324
3325 let v = Int::<4>::from_limbs([1, 2, 3, 4]);
3327 assert_eq!(*v.resize_n::<2>().as_limbs(), [1, 2]);
3328
3329 assert_eq!(Int::<4>::from_i64(-1).try_narrow::<2>().unwrap(), Int::<2>::from_i64(-1));
3332 assert!(Int::<4>::from_limbs([0, 0, 1, 0]).try_narrow::<2>().is_none());
3334 let too_big = Int::<2>::from_limbs([0x8000_0000_0000_0000, 0]);
3338 assert!(too_big.try_narrow::<1>().is_none());
3339 let min2 = Int::<2>::from_i64(i64::MIN);
3341 assert_eq!(min2.try_narrow::<1>().unwrap(), Int::<1>::from_i64(i64::MIN));
3342 assert_eq!(min2.resize_n::<4>().try_narrow::<2>().unwrap(), min2);
3344
3345 const W: Int<4> = Int::<2>::from_i64(-7).resize_n::<4>();
3347 assert_eq!(W, Int::<4>::from_i64(-7));
3348 }
3349
3350 #[test]
3351 fn bit_count_is_const() {
3352 const Z: u32 = Int::<2>::leading_zeros(&Int::<2>::MAX);
3358 const BL: u32 = Int::<2>::bit_length(&Int::<2>::MAX);
3359 const UZ: u32 = Uint::<2>::leading_zeros(&Uint::<2>::MAX);
3360 const UBL: u32 = Uint::<2>::bit_length(&Uint::<2>::MAX);
3361 assert_eq!(Z, 1);
3364 assert_eq!(BL, 127);
3365 assert_eq!(UZ, 0);
3367 assert_eq!(UBL, 128);
3368 }
3369
3370 #[test]
3371 fn int_cross_width_comparison() {
3372 let a = Int::<1>::from_i64(5);
3374 let b = Int::<2>::from_i64(5);
3375 assert!(a == b);
3376 assert!(b == a);
3377 assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal));
3378
3379 let small = Int::<1>::from_i64(3);
3381 let big = Int::<2>::from_i64(100);
3382 assert!(small < big);
3383 assert!(big > small);
3384
3385 let huge = Int::<2>::from_limbs([0, 64]); assert!(huge > Int::<1>::MAX);
3390 assert!(Int::<1>::from_i64(-1) < huge);
3391
3392 assert!(Int::<1>::from_i64(-1) < Int::<2>::from_i64(1));
3394 assert!(Int::<1>::from_i64(-100) < Int::<2>::from_i64(-3));
3396 assert!(Int::<2>::from_i64(-3) > Int::<1>::from_i64(-100));
3397 assert!(Int::<1>::from_i64(-7) == Int::<2>::from_i64(-7));
3399
3400 let mut v = vec![
3402 Int::<2>::from_i64(3),
3403 Int::<2>::from_i64(-10),
3404 Int::<2>::from_i64(0),
3405 Int::<2>::from_i64(7),
3406 ];
3407 v.sort();
3408 assert_eq!(
3409 v,
3410 vec![
3411 Int::<2>::from_i64(-10),
3412 Int::<2>::from_i64(0),
3413 Int::<2>::from_i64(3),
3414 Int::<2>::from_i64(7),
3415 ]
3416 );
3417 }
3418
3419 #[test]
3420 fn consts_and_round_trip() {
3421 assert_eq!(Uint::<4>::LIMBS, 4);
3422 assert_eq!(Uint::<4>::BITS, 256);
3423 assert_eq!(*Uint::<4>::ZERO.as_limbs(), [0, 0, 0, 0]);
3424 assert_eq!(*Uint::<4>::ONE.as_limbs(), [1, 0, 0, 0]);
3425 assert_eq!(*Uint::<4>::MAX.as_limbs(), [u64::MAX; 4]);
3426
3427 let v = Uint::<4>::from_limbs([7, 8, 9, 10]);
3428 assert_eq!(*v.as_limbs(), [7, 8, 9, 10]);
3429 }
3430
3431 #[test]
3432 fn widths_have_expected_bits() {
3433 assert_eq!(Int::<4>::BITS, 256);
3434 assert_eq!(Int::<64>::BITS, 4096);
3435 assert_eq!(Uint::<16>::LIMBS, 16);
3436 }
3437
3438 #[test]
3439 fn wrapping_sub_borrows_across_limbs() {
3440 let a = Uint::<4>::from_limbs([0, 1, 0, 0]);
3442 let d = a.wrapping_sub(Uint::<4>::ONE);
3443 assert_eq!(*d.as_limbs(), [u64::MAX, 0, 0, 0]);
3444
3445 let wrap = Uint::<4>::ZERO.wrapping_sub(Uint::<4>::ONE);
3447 assert_eq!(*wrap.as_limbs(), [u64::MAX; 4]);
3448 }
3449
3450 #[test]
3451 fn unsigned_ordering() {
3452 let small = Uint::<4>::from_limbs([5, 0, 0, 0]);
3453 let big = Uint::<4>::from_limbs([0, 1, 0, 0]); assert!(small < big);
3455 assert!(big > small);
3456 assert_eq!(small, small);
3457 assert!(Uint::<4>::ZERO < Uint::<4>::MAX);
3458 assert_eq!(small.max(big), big);
3460 }
3461
3462 #[test]
3463 fn wrapping_add_carries_across_limbs() {
3464 let a = Uint::<4>::from_limbs([u64::MAX, 0, 0, 0]);
3466 let sum = a.wrapping_add(Uint::<4>::ONE);
3467 assert_eq!(*sum.as_limbs(), [0, 1, 0, 0]);
3468
3469 let wrap = Uint::<4>::MAX.wrapping_add(Uint::<4>::ONE);
3471 assert_eq!(*wrap.as_limbs(), [0, 0, 0, 0]);
3472 }
3473
3474 #[test]
3475 fn uint_wrapping_mul_cross_limb_product() {
3476 let a = Uint::<4>::from_limbs([0, 1, 0, 0]);
3478 let p = a.wrapping_mul(a);
3479 assert_eq!(*p.as_limbs(), [0, 0, 1, 0]);
3480
3481 let m = Uint::<4>::from_limbs([u64::MAX, 0, 0, 0]);
3483 let three = Uint::<4>::from_limbs([3, 0, 0, 0]);
3484 let q = m.wrapping_mul(three);
3485 assert_eq!(*q.as_limbs(), [u64::MAX - 2, 2, 0, 0]);
3486
3487 let v = Uint::<4>::from_limbs([7, 8, 9, 10]);
3489 assert_eq!(v.wrapping_mul(Uint::<4>::ONE), v);
3490 }
3491
3492 #[test]
3493 fn uint_wrapping_mul_truncates_modulo_width() {
3494 let hi = Uint::<4>::from_limbs([0, 0, 0, 1]);
3496 assert_eq!(hi.wrapping_mul(hi), Uint::<4>::ZERO);
3497
3498 let r = Uint::<4>::MAX.wrapping_mul(Uint::<4>::MAX);
3502 assert_eq!(*r.as_limbs(), [1, 0, 0, 0]);
3503 }
3504
3505 #[test]
3506 fn uint_checked_add_sub_overflow() {
3507 assert_eq!(
3508 Uint::<4>::ONE.checked_add(Uint::<4>::ONE),
3509 Some(Uint::<4>::from_limbs([2, 0, 0, 0]))
3510 );
3511 assert_eq!(Uint::<4>::MAX.checked_add(Uint::<4>::ONE), None);
3513
3514 assert_eq!(
3515 Uint::<4>::from_limbs([5, 0, 0, 0]).checked_sub(Uint::<4>::from_limbs([3, 0, 0, 0])),
3516 Some(Uint::<4>::from_limbs([2, 0, 0, 0]))
3517 );
3518 assert_eq!(Uint::<4>::ZERO.checked_sub(Uint::<4>::ONE), None);
3520 }
3521
3522 #[test]
3523 fn uint_checked_mul_overflow() {
3524 let a = Uint::<4>::from_limbs([0, 1, 0, 0]);
3526 assert_eq!(a.checked_mul(a), Some(Uint::<4>::from_limbs([0, 0, 1, 0])));
3527 let hi = Uint::<4>::from_limbs([0, 0, 0, 1]);
3529 assert_eq!(hi.checked_mul(hi), None);
3530 assert_eq!(
3532 Uint::<4>::MAX.checked_mul(Uint::<4>::from_limbs([2, 0, 0, 0])),
3533 None
3534 );
3535 }
3536
3537 #[test]
3538 fn uint_div_rem_with_remainder() {
3539 let n = Uint::<4>::from_limbs([1000, 0, 0, 0]);
3541 let d = Uint::<4>::from_limbs([7, 0, 0, 0]);
3542 assert_eq!(*n.wrapping_div(d).as_limbs(), [142, 0, 0, 0]);
3543 assert_eq!(*n.wrapping_rem(d).as_limbs(), [6, 0, 0, 0]);
3544
3545 let big = Uint::<4>::from_limbs([0, 0, 1, 0]);
3547 let by = Uint::<4>::from_limbs([0, 1, 0, 0]);
3548 assert_eq!(*big.wrapping_div(by).as_limbs(), [0, 1, 0, 0]);
3549 assert!(big.wrapping_rem(by).is_zero());
3550 }
3551
3552 #[test]
3553 #[should_panic(expected = "divide by zero")]
3554 fn uint_div_by_zero_panics() {
3555 let _ = Uint::<4>::ONE.wrapping_div(Uint::<4>::ZERO);
3556 }
3557
3558 #[test]
3559 fn uint_bitwise_ops() {
3560 let a = Uint::<4>::from_limbs([0b1100, 0xFF, 0, 0]);
3561 let b = Uint::<4>::from_limbs([0b1010, 0x0F, 0, 0]);
3562 assert_eq!(*(a & b).as_limbs(), [0b1000, 0x0F, 0, 0]);
3563 assert_eq!(*(a | b).as_limbs(), [0b1110, 0xFF, 0, 0]);
3564 assert_eq!(*(a ^ b).as_limbs(), [0b0110, 0xF0, 0, 0]);
3565 assert_eq!(*(!Uint::<4>::ZERO).as_limbs(), [u64::MAX; 4]);
3566 }
3567
3568 #[test]
3569 fn uint_shifts() {
3570 let one = Uint::<4>::ONE;
3571 assert_eq!(*(one << 64).as_limbs(), [0, 1, 0, 0]);
3573 assert_eq!(*(one << 130).as_limbs(), [0, 0, 0b100, 0]);
3575 let v = Uint::<4>::from_limbs([0, 0, 0b100, 0]);
3577 assert_eq!(*(v >> 130).as_limbs(), [1, 0, 0, 0]);
3578 assert_eq!(one << 256, Uint::<4>::ZERO);
3580 }
3581
3582 #[test]
3583 fn uint_is_zero_bitlen_leading_zeros() {
3584 assert!(Uint::<4>::ZERO.is_zero());
3585 assert!(!Uint::<4>::ONE.is_zero());
3586 assert_eq!(Uint::<4>::ZERO.bit_length(), 0);
3587 assert_eq!(Uint::<4>::ONE.bit_length(), 1);
3588 let b = Uint::<4>::from_limbs([0, 1, 0, 0]);
3590 assert_eq!(b.bit_length(), 65);
3591 assert_eq!(b.leading_zeros(), 256 - 65);
3592 assert_eq!(Uint::<4>::ZERO.leading_zeros(), 256);
3593 assert_eq!(Uint::<4>::MAX.leading_zeros(), 0);
3594 }
3595
3596 #[test]
3597 fn uint_operator_traits_delegate() {
3598 let a = Uint::<4>::from_limbs([10, 0, 0, 0]);
3599 let b = Uint::<4>::from_limbs([3, 0, 0, 0]);
3600 assert_eq!(*(a + b).as_limbs(), [13, 0, 0, 0]);
3601 assert_eq!(*(a - b).as_limbs(), [7, 0, 0, 0]);
3602 assert_eq!(*(a * b).as_limbs(), [30, 0, 0, 0]);
3603 }
3604
3605 #[test]
3606 fn int_from_i64_sign_extends() {
3607 assert_eq!(*Int::<4>::from_i64(5).as_limbs(), [5, 0, 0, 0]);
3609 assert_eq!(*Int::<4>::from_i64(-1).as_limbs(), [u64::MAX; 4]);
3611 assert_eq!(
3613 *Int::<4>::from_i64(-2).as_limbs(),
3614 [u64::MAX - 1, u64::MAX, u64::MAX, u64::MAX]
3615 );
3616 assert!(Int::<4>::from_i64(-1).is_negative());
3617 assert!(Int::<4>::from_i64(1).is_positive());
3618 assert!(Int::<4>::from_i64(0).is_zero());
3619 }
3620
3621 #[test]
3622 fn int_wrapping_neg_two_complement() {
3623 let five = Int::<4>::from_i64(5);
3624 let neg_five = five.wrapping_neg();
3625 assert_eq!(neg_five, Int::<4>::from_i64(-5));
3626 assert_eq!(neg_five.wrapping_neg(), five);
3628 assert_eq!(Int::<4>::from_i64(-1).wrapping_neg(), Int::<4>::ONE);
3630 assert_eq!(-five, neg_five);
3632 }
3633
3634 #[test]
3635 fn int_add_sub_mul_with_signs() {
3636 let a = Int::<4>::from_i64(7);
3637 let b = Int::<4>::from_i64(-3);
3638 assert_eq!(a.wrapping_add(b), Int::<4>::from_i64(4));
3640 assert_eq!(a.wrapping_sub(b), Int::<4>::from_i64(10));
3642 assert_eq!(a.wrapping_mul(b), Int::<4>::from_i64(-21));
3644 assert_eq!(b.wrapping_mul(b), Int::<4>::from_i64(9));
3646 assert_eq!(a + b, Int::<4>::from_i64(4));
3648 assert_eq!(a - b, Int::<4>::from_i64(10));
3649 assert_eq!(a * b, Int::<4>::from_i64(-21));
3650 }
3651
3652 #[test]
3653 fn int_mul_crosses_limbs_with_sign() {
3654 let big = Int::<4>::from_i64(0).wrapping_add(Int::<4>::from_limbs([0, 1, 0, 0]));
3656 let neg = big.wrapping_mul(Int::<4>::from_i64(-1));
3657 assert_eq!(neg, big.wrapping_neg());
3658 assert_eq!(*neg.as_limbs(), [0, u64::MAX, u64::MAX, u64::MAX]);
3660 }
3661
3662 #[test]
3663 fn int_abs_signum() {
3664 assert_eq!(Int::<4>::from_i64(-9).abs(), Int::<4>::from_i64(9));
3665 assert_eq!(Int::<4>::from_i64(9).abs(), Int::<4>::from_i64(9));
3666 assert_eq!(Int::<4>::from_i64(-9).signum(), -1);
3667 assert_eq!(Int::<4>::from_i64(9).signum(), 1);
3668 assert_eq!(Int::<4>::from_i64(0).signum(), 0);
3669 }
3670
3671 #[test]
3672 fn int_from_i128_round_trips() {
3673 for v in [
3674 0i128,
3675 1,
3676 -1,
3677 42,
3678 -42,
3679 i64::MAX as i128,
3680 i64::MIN as i128,
3681 i128::MAX,
3682 i128::MIN,
3683 123_456_789_012_345_678,
3684 ] {
3685 let a = Int::<4>::from_i128(v);
3686 assert_eq!(a.to_i128_checked(), Some(v), "round-trip i128 {v}");
3687 let b = Int::<8>::from_i128(v);
3688 assert_eq!(b.to_i128_checked(), Some(v), "round-trip i128 {v} (N=8)");
3689 }
3690 let big = Int::<4>::from_u128(u128::MAX);
3692 assert_eq!(big.to_i128_checked(), None);
3693 assert_eq!(big.to_u128_checked(), Some(u128::MAX));
3694 assert_eq!(Int::<4>::from_i128(-1).to_u128_checked(), None);
3696 }
3697
3698 #[test]
3699 fn int_from_str_radix_and_display_round_trip() {
3700 let cases = [
3701 "0",
3702 "1",
3703 "-1",
3704 "42",
3705 "-42",
3706 "1000000000000000000000",
3707 "-340282366920938463463374607431768211455",
3708 ];
3709 for s in cases {
3710 let v = Int::<4>::from_str_radix(s, 10).unwrap();
3711 assert_eq!(format!("{v}"), s, "display round-trip {s}");
3712 let v2: Int<4> = s.parse().unwrap();
3714 assert_eq!(v, v2);
3715 }
3716 assert!(Int::<4>::from_str_radix("10", 16).is_err());
3718 assert!(Int::<4>::from_str_radix("12x", 10).is_err());
3719 assert!(Int::<4>::from_str_radix("", 10).is_err());
3720 assert!(Int::<4>::from_str_radix("-", 10).is_err());
3721 }
3722
3723 #[test]
3724 fn int_div_rem_signs_match_truncating() {
3725 let cases: [(i128, i128); 6] = [
3728 (1000, 7),
3729 (-1000, 7),
3730 (1000, -7),
3731 (-1000, -7),
3732 (7, 1000),
3733 (-7, 1000),
3734 ];
3735 for (a, b) in cases {
3736 let (q, r) = Int::<4>::from_i128(a).div_rem(Int::<4>::from_i128(b));
3737 assert_eq!(q.to_i128_checked(), Some(a / b), "quot {a}/{b}");
3738 assert_eq!(r.to_i128_checked(), Some(a % b), "rem {a}%{b}");
3739 }
3740 }
3741
3742 #[test]
3743 #[should_panic(expected = "divide by zero")]
3744 fn int_div_rem_by_zero_panics() {
3745 let _ = Int::<4>::ONE.div_rem(Int::<4>::ZERO);
3746 }
3747
3748 #[test]
3749 fn int_bit_reads_twos_complement() {
3750 let v = Int::<4>::from_i128(0b1010);
3751 assert!(!v.bit(0));
3752 assert!(v.bit(1));
3753 assert!(!v.bit(2));
3754 assert!(v.bit(3));
3755 assert!(!v.bit(200));
3757 let neg = Int::<4>::from_i128(-1);
3759 assert!(neg.bit(0));
3760 assert!(neg.bit(255));
3761 assert!(neg.bit(1000)); }
3763
3764 #[test]
3765 fn int_mul_u64_matches_wide_mul() {
3766 let v = Int::<4>::from_i128(123_456_789);
3767 assert_eq!(
3768 v.mul_u64(1000),
3769 Int::<4>::from_i128(123_456_789_000)
3770 );
3771 let n = Int::<4>::from_i128(-123_456_789);
3773 assert_eq!(
3774 n.mul_u64(1000),
3775 Int::<4>::from_i128(-123_456_789_000)
3776 );
3777 assert_eq!(v.mul_u64(0), Int::<4>::ZERO);
3779 assert_eq!(v.mul_u64(1), v);
3780 }
3781
3782 #[test]
3783 #[should_panic(expected = "mul overflow")]
3784 fn int_mul_u64_overflow_panics() {
3785 let _ = Int::<4>::max_value().mul_u64(2);
3787 }
3788
3789 #[test]
3790 fn int_div_rem_operators_match_div_rem() {
3791 let a = Int::<4>::from_i128(-1000);
3794 let b = Int::<4>::from_i128(7);
3795 assert_eq!(a / b, Int::<4>::from_i128(-1000 / 7));
3796 assert_eq!(a % b, Int::<4>::from_i128(-1000 % 7));
3797 let (q, r) = a.div_rem(b);
3798 assert_eq!(a / b, q);
3799 assert_eq!(a % b, r);
3800 }
3801
3802 #[cfg(feature = "_wide-support")]
3804 #[test]
3805 fn int_wide_storage_surface() {
3806 use crate::int::types::traits::BigInt;
3807 fn exercises<T: BigInt>() {
3808 assert!(<T as BigInt>::ZERO == <T as BigInt>::from_i128(0));
3809 assert!(<T as BigInt>::ONE == <T as BigInt>::from_i128(1));
3810 assert!(<T as BigInt>::TEN == <T as BigInt>::from_i128(10));
3811
3812 let twelve = <T as BigInt>::from_i128(12);
3813 let three = <T as BigInt>::from_i128(3);
3814 assert!(three.pow(3) == <T as BigInt>::from_i128(27));
3816 assert!(<T as BigInt>::from_i128(144).isqrt() == <T as BigInt>::from_i128(12));
3817 let (q, r) = twelve.div_rem(<T as BigInt>::from_i128(5));
3819 assert!(q == <T as BigInt>::from_i128(2));
3820 assert!(r == <T as BigInt>::from_i128(2));
3821 assert!(twelve.bit(2) && twelve.bit(3) && !twelve.bit(0));
3823 assert!(<T as BigInt>::ONE.leading_zeros() == <T as BigInt>::BITS - 1);
3824 assert!(twelve.mul_u64(10) == <T as BigInt>::from_i128(120));
3826 assert!(twelve.to_f64() == 12.0);
3827 assert!(<T as BigInt>::from_f64_val(7.9) == <T as BigInt>::from_i128(7));
3828 }
3829 exercises::<Int<4>>();
3830 exercises::<Int<8>>();
3831
3832 let v = Int::<4>::from_i128(-123_456_789);
3834 let w: Int<8> = BigInt::resize_to(v);
3835 assert_eq!(w.to_i128_checked(), Some(-123_456_789));
3836 let back: Int<4> = BigInt::resize_to(w);
3837 assert_eq!(back, v);
3838 }
3839
3840 #[cfg(feature = "_wide-support")]
3842 #[test]
3843 fn int_isqrt_matches_uint_magnitude() {
3844 use crate::int::types::traits::BigInt;
3845 let n = Int::<4>::from_i128(1_000_000_000_000);
3847 let r = BigInt::isqrt(n);
3848 assert_eq!(r, Int::<4>::from_i128(1_000_000));
3849 let big = Int::<8>::from_i128(987_654_321);
3851 let sq = big.checked_mul(big).unwrap();
3852 assert_eq!(BigInt::isqrt(sq), big);
3853 }
3854
3855 #[test]
3858 fn uint_sqr_policy_matches_wrapping_sqr() {
3859 fn check<const N: usize>(limbs: [u64; N]) {
3860 let x = Uint::<N>::from_limbs(limbs);
3861 assert_eq!(x.sqr(), x.wrapping_sqr(), "sqr mismatch at {limbs:?}");
3862 assert_eq!(x.sqr(), x.wrapping_mul(x), "sqr != x*x at {limbs:?}");
3863 }
3864 check::<1>([0]);
3866 check::<1>([1]);
3867 check::<1>([u64::MAX]);
3868 check::<1>([12345]);
3869 check::<2>([0, 0]);
3871 check::<2>([1, 0]);
3872 check::<2>([u64::MAX, u64::MAX]);
3873 check::<2>([0xDEAD_BEEF, 0x1234]);
3874 check::<4>([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
3876 check::<4>([0x1234_5678_9ABC_DEF0, 0xFEDC_BA98, 0, 0]);
3877 check::<6>([7, 8, 9, 10, 11, 12]);
3879 }
3880
3881 #[test]
3883 fn uint_cube_policy_matches_wrapping_cube() {
3884 fn check<const N: usize>(limbs: [u64; N]) {
3885 let x = Uint::<N>::from_limbs(limbs);
3886 assert_eq!(x.cube(), x.wrapping_cube(), "cube mismatch at {limbs:?}");
3887 assert_eq!(
3888 x.cube(),
3889 x.wrapping_mul(x).wrapping_mul(x),
3890 "cube != x*x*x at {limbs:?}"
3891 );
3892 }
3893 check::<1>([0]);
3894 check::<1>([1]);
3895 check::<1>([3]);
3896 check::<1>([u64::MAX]);
3897 check::<2>([0, 0]);
3898 check::<2>([1, 0]);
3899 check::<2>([100, 0]);
3900 check::<2>([u64::MAX, u64::MAX]);
3901 check::<4>([5, 0, 0, 0]);
3902 check::<4>([0x1234, 0x5678, 0, 0]);
3903 }
3904
3905 #[test]
3907 fn int_sqr_cube_match_wrapping() {
3908 fn check<const N: usize>(v: i128) {
3909 let x = Int::<N>::from_i128(v);
3910 assert_eq!(x.sqr(), x.wrapping_sqr(), "int sqr mismatch v={v}");
3911 assert_eq!(x.cube(), x.wrapping_cube(), "int cube mismatch v={v}");
3912 }
3913 for v in [0i128, 1, -1, 12, -12, 100, -100, 1_000_000, -1_000_000] {
3914 check::<4>(v);
3915 check::<8>(v);
3916 }
3917 }
3918
3919 #[test]
3922 fn uint_icbrt_floor_correctness() {
3923 fn brute_cbrt(n: u64) -> u64 {
3925 if n == 0 {
3926 return 0;
3927 }
3928 let mut r: u64 = 0;
3929 while (r + 1).checked_mul((r + 1) * (r + 1) + r + 1)
3930 .is_some_and(|p| p <= n)
3931 || (r + 1).checked_pow(3).is_some_and(|p| p <= n)
3932 {
3933 r += 1;
3934 }
3935 r
3936 }
3937
3938 fn check<const N: usize>(n: u64) {
3939 let x = Uint::<N>::from_u64(n);
3940 let root = x.icbrt();
3941 let root_u64 = root.as_limbs()[0];
3942 let expected = brute_cbrt(n);
3943 assert_eq!(root_u64, expected, "icbrt({n}) = {root_u64}, expected {expected}");
3944 for i in 1..N {
3946 assert_eq!(root.as_limbs()[i], 0, "icbrt({n}) high limb {i} nonzero");
3947 }
3948 }
3949
3950 for n in [0u64, 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000,
3952 1_000_000_000u64, 8_000_000_000u64] {
3953 check::<1>(n);
3954 check::<2>(n);
3955 check::<4>(n);
3956 }
3957
3958 for n in [2u64, 3, 4, 5, 6, 7, 9, 10, 26, 28, 63, 65, 999,
3960 1_000_000_001u64] {
3961 check::<1>(n);
3962 check::<2>(n);
3963 check::<4>(n);
3964 }
3965
3966 check::<1>(0);
3968 check::<1>(1);
3969 check::<4>(0);
3970 check::<4>(1);
3971
3972 for n in [u64::MAX, u64::MAX - 1, u64::MAX - 100, 1 << 60, 1 << 48] {
3974 check::<2>(n);
3975 check::<4>(n);
3976 }
3977 }
3978
3979 #[test]
3983 fn uint_icbrt_wide_floor_identity() {
3984 fn check_wide<const N: usize>(limbs: [u64; N]) {
3985 let x = Uint::<N>::from_limbs(limbs);
3986 let r = x.icbrt();
3987 let r3 = r.wrapping_pow(3);
3989 assert!(
3990 r3 <= x,
3991 "icbrt violated: r³ > x for {limbs:?}"
3992 );
3993 let r1 = r.wrapping_add(Uint::<N>::ONE);
3995 let r1_3 = r1.wrapping_pow(3);
3996 assert!(
3999 r1_3 > x || r1 == Uint::<N>::ZERO,
4000 "icbrt not floor: (r+1)³ <= x for {limbs:?}"
4001 );
4002 }
4003
4004 let m = 1_000_000u64;
4008 let m3 = m * m * m; check_wide::<4>([m3, 0, 0, 0]);
4010 check_wide::<4>([m3 + 1, 0, 0, 0]);
4011 check_wide::<4>([m3 - 1, 0, 0, 0]);
4012
4013 let hi = 1u64;
4015 let lo = 0u64;
4016 check_wide::<4>([lo, hi, 0, 0]); check_wide::<4>([u64::MAX, u64::MAX, 0, 0]); check_wide::<6>([m3, 0, 0, 0, 0, 0]);
4022 check_wide::<6>([u64::MAX, u64::MAX, u64::MAX, 0, 0, 0]); }
4024
4025 #[test]
4027 fn int_icbrt_magnitude() {
4028 for v in [0i128, 1, -1, 8, -8, 27, -27, 1000, -1000] {
4029 let x = Int::<4>::from_i128(v);
4030 let expected = Int::<4>::from_i128((v.unsigned_abs() as f64).cbrt() as i128);
4031 let got = x.icbrt();
4032 assert_eq!(got, expected, "int icbrt({v}) mismatch");
4033 }
4034 }
4035
4036 #[test]
4037 fn int_wideint_mag_sign_round_trips() {
4038 use crate::int::types::traits::BigInt;
4039 for v in [0i128, 1, -1, 123_456_789_012_345_678, -987_654_321] {
4042 let a = Int::<4>::from_i128(v);
4043 let mut mag = [0u128; 2];
4044 let neg = a.mag_into_u128(&mut mag);
4045 assert_eq!(neg, a.is_negative());
4046 assert_eq!(Int::<4>::from_mag_sign_u128(&mag, neg), a, "mag/sign {v}");
4047 }
4048 assert_eq!(<Int<4> as BigInt>::U128_LIMBS, 2);
4050 assert_eq!(<Int<3> as BigInt>::U128_LIMBS, 2);
4051 assert_eq!(<Int<8> as BigInt>::U128_LIMBS, 4);
4052
4053 let v3 = Int::<3>::from_i128(-170_141_183_460_469_231_731);
4056 let mut buf = [0u128; 2];
4057 let neg = v3.mag_into_u128(&mut buf);
4058 assert_eq!(Int::<3>::from_mag_sign_u128(&buf, neg), v3);
4059
4060 let v4 = Int::<4>::from_i128(i128::MIN);
4061 let mut buf4 = [0u128; 2];
4062 let neg4 = v4.mag_into_u128(&mut buf4);
4063 assert_eq!(Int::<4>::from_mag_sign_u128(&buf4, neg4), v4);
4064 }
4065
4066 #[test]
4067 fn int_to_from_f64_and_negate_ten() {
4068 assert_eq!(Int::<4>::from_i64(5).to_f64(), 5.0);
4069 assert_eq!(Int::<4>::from_i64(-5).to_f64(), -5.0);
4070 assert_eq!(Int::<4>::from_f64(42.9), Int::<4>::from_i64(42));
4071 assert_eq!(Int::<4>::from_f64(-42.9), Int::<4>::from_i64(-42));
4072 assert_eq!(Int::<4>::from_f64(f64::NAN), Int::<4>::ZERO);
4074 assert_eq!(Int::<4>::from_i64(5).negate(), Int::<4>::from_i64(-5));
4076 assert_eq!(Int::<4>::TEN, Int::<4>::from_i64(10));
4077 let v = Int::<4>::from_i128(-9_876_543_210);
4079 assert_eq!(Int::<4>::from_limbs_le(v.limbs_le()), v);
4080 }
4081
4082 #[test]
4083 fn int_signed_ordering() {
4084 let neg = Int::<4>::from_i64(-5);
4085 let zero = Int::<4>::ZERO;
4086 let pos = Int::<4>::from_i64(5);
4087 assert!(neg < zero);
4090 assert!(zero < pos);
4091 assert!(neg < pos);
4092 assert!(Int::<4>::from_i64(-10) < Int::<4>::from_i64(-1));
4094 assert_eq!(neg.max(pos), pos);
4095 assert_eq!(neg.min(pos), neg);
4096 assert_eq!(pos.cmp(&pos), Ordering::Equal);
4097 }
4098}
4099
4100#[cfg(all(test, feature = "wide"))]
4109mod unified_mg_feasibility {
4110 use super::Int;
4111 use crate::algos::support::mg_divide::div_wide_pow10;
4112 use crate::int::types::compute_limbs::{ComputeLimbs, Limbs};
4113 use crate::int::types::traits::BigInt;
4114 use crate::support::rounding::RoundingMode;
4115
4116 fn scaled<const N: usize, const M: usize>(a: Int<N>, b: Int<N>, scale: u32) -> Int<M>
4124 where
4125 Limbs<N>: ComputeLimbs,
4126 Int<M>: BigInt,
4127 Limbs<M>: ComputeLimbs,
4128 <Int<M> as BigInt>::Scratch: ComputeLimbs,
4129 {
4130 let prod: Int<M> = a.widen_mul::<Int<M>>(b);
4131 div_wide_pow10::<Int<M>>(prod, scale, RoundingMode::HalfToEven)
4132 }
4133
4134 #[test]
4136 fn n2_widen4_scale5() {
4137 let a = Int::<2>::from_i64(123456789);
4138 let b = Int::<2>::from_i64(987654321);
4139 let got = scaled::<2, 4>(a, b, 5);
4140 assert_eq!(got, Int::<4>::from_i64(1219326311126));
4141 }
4142
4143 #[test]
4145 fn n1_widen2_scale3() {
4146 let a = Int::<1>::from_i64(123456);
4147 let b = Int::<1>::from_i64(654321);
4148 let got = scaled::<1, 2>(a, b, 3);
4149 assert_eq!(got, Int::<2>::from_i64(80779853));
4150 }
4151
4152 #[test]
4156 fn round_trip_mul_then_div() {
4157 let x1 = 4242i64;
4159 let ten_pow_4 = Int::<1>::from_i64(10_000);
4160 let rt1 = scaled::<1, 2>(Int::<1>::from_i64(x1), ten_pow_4, 4);
4161 assert_eq!(rt1, Int::<2>::from_i64(x1));
4162
4163 let x2 = 9_876_543_210i64;
4165 let ten_pow_7 = Int::<2>::from_i64(10_000_000);
4166 let rt2 = scaled::<2, 4>(Int::<2>::from_i64(x2), ten_pow_7, 7);
4167 assert_eq!(rt2, Int::<4>::from_i64(x2));
4168 }
4169
4170 #[test]
4175 fn scale_zero_is_widen_mul_identity() {
4176 let a1 = Int::<1>::from_i64(123456);
4178 let b1 = Int::<1>::from_i64(654321);
4179 let prod1: Int<2> = a1.widen_mul::<Int<2>>(b1);
4180 assert_eq!(prod1, Int::<2>::from_i64(123456 * 654321));
4181
4182 let a2 = Int::<2>::from_i64(123456789);
4184 let b2 = Int::<2>::from_i64(987654321);
4185 let prod2: Int<4> = a2.widen_mul::<Int<4>>(b2);
4186 assert_eq!(prod2, Int::<4>::from_i64(123456789i64 * 987654321i64));
4187 }
4188
4189 #[test]
4192 fn max_operand_each_width() {
4193 let a1 = Int::<1>::from_i64(i64::MAX);
4197 let b1 = Int::<1>::from_i64(i64::MAX);
4198 let got1 = scaled::<1, 2>(a1, b1, 9);
4199 let exact1 = (i64::MAX as i128) * (i64::MAX as i128);
4200 let pow9 = 1_000_000_000i128;
4201 let q1 = exact1 / pow9;
4202 let r1 = exact1 % pow9;
4203 let half = pow9 / 2;
4205 let expect1 = if r1 > half || (r1 == half && (q1 & 1) == 1) {
4206 q1 + 1
4207 } else {
4208 q1
4209 };
4210 assert_eq!(got1, Int::<2>::from_i128(expect1));
4211
4212 let big = Int::<2>::MAX; let got2 = scaled::<2, 4>(big, big, 20);
4217 let prod2: Int<4> = big.widen_mul::<Int<4>>(big);
4218 let pow20 = Int::<4>::TEN.pow(20);
4221 let (q2, r2) = prod2.div_rem(pow20);
4222 let half20 = pow20.div_rem(Int::<4>::from_i64(2)).0;
4223 let expect2 = match r2.cmp(&half20) {
4224 core::cmp::Ordering::Greater => q2.wrapping_add(Int::<4>::ONE),
4225 core::cmp::Ordering::Equal => {
4226 if (q2.as_limbs()[0] & 1) == 1 {
4227 q2.wrapping_add(Int::<4>::ONE)
4228 } else {
4229 q2
4230 }
4231 }
4232 core::cmp::Ordering::Less => q2,
4233 };
4234 assert_eq!(got2, expect2);
4235 }
4236}
4237
4238#[cfg(test)]
4239mod bit_count_contract_tests {
4240 use super::{Int, Uint};
4241
4242 #[test]
4247 fn int_bit_counts_match_signed_contract_at_edges() {
4248 for v in [0_i64, 1, -1, i64::MAX, i64::MIN, 42, -42, 1 << 40, -(1 << 40)] {
4250 let x = Int::<1>::from_i64(v);
4251 assert_eq!(x.leading_zeros(), v.leading_zeros(), "i64 lz {v}");
4252 assert_eq!(x.trailing_zeros(), v.trailing_zeros(), "i64 tz {v}");
4253 assert_eq!(x.count_ones(), v.count_ones(), "i64 popcount {v}");
4254 assert_eq!(x.count_zeros(), v.count_zeros(), "i64 cz {v}");
4255 let mag_bits = 64 - v.unsigned_abs().leading_zeros();
4257 assert_eq!(x.bit_length(), mag_bits, "i64 bit_length {v}");
4258 }
4259
4260 for v in [
4262 0_i128,
4263 1,
4264 -1,
4265 i128::MAX,
4266 i128::MIN,
4267 (1_i128 << 64), (1_i128 << 64) - 1, -(1_i128 << 64),
4270 i64::MAX as i128,
4271 i64::MIN as i128,
4272 ] {
4273 let x = Int::<2>::from_i128(v);
4274 assert_eq!(x.leading_zeros(), v.leading_zeros(), "i128 lz {v}");
4275 assert_eq!(x.trailing_zeros(), v.trailing_zeros(), "i128 tz {v}");
4276 assert_eq!(x.count_ones(), v.count_ones(), "i128 popcount {v}");
4277 assert_eq!(x.count_zeros(), v.count_zeros(), "i128 cz {v}");
4278 let mag_bits = 128 - v.unsigned_abs().leading_zeros();
4279 assert_eq!(x.bit_length(), mag_bits, "i128 bit_length {v}");
4280 }
4281
4282 const B: u32 = Int::<4>::BITS; let z = Int::<4>::ZERO;
4289 assert_eq!(z.leading_zeros(), B);
4290 assert_eq!(z.trailing_zeros(), B);
4291 assert_eq!(z.count_ones(), 0);
4292 assert_eq!(z.count_zeros(), B);
4293 assert_eq!(z.bit_length(), 0);
4294
4295 let one = Int::<4>::ONE;
4297 assert_eq!(one.leading_zeros(), B - 1);
4298 assert_eq!(one.trailing_zeros(), 0);
4299 assert_eq!(one.count_ones(), 1);
4300 assert_eq!(one.count_zeros(), B - 1);
4301 assert_eq!(one.bit_length(), 1);
4302
4303 let neg_one = Int::<4>::from_i64(-1);
4307 assert_eq!(*neg_one.as_limbs(), [u64::MAX; 4]);
4308 assert_eq!(neg_one.leading_zeros(), 0);
4309 assert_eq!(neg_one.trailing_zeros(), 0);
4310 assert_eq!(neg_one.count_ones(), B);
4311 assert_eq!(neg_one.count_zeros(), 0);
4312 assert_eq!(neg_one.bit_length(), 1);
4313
4314 let max = Int::<4>::MAX;
4316 assert_eq!(max.leading_zeros(), 1);
4317 assert_eq!(max.trailing_zeros(), 0);
4318 assert_eq!(max.count_ones(), B - 1);
4319 assert_eq!(max.count_zeros(), 1);
4320 assert_eq!(max.bit_length(), B - 1); let min = Int::<4>::MIN;
4326 assert_eq!(min.leading_zeros(), 0);
4327 assert_eq!(min.trailing_zeros(), B - 1);
4328 assert_eq!(min.count_ones(), 1);
4329 assert_eq!(min.count_zeros(), B - 1);
4330 assert_eq!(min.bit_length(), B); let two_64 = Int::<4>::from_u128(1u128 << 64);
4334 assert_eq!(two_64.trailing_zeros(), 64);
4335 assert_eq!(two_64.count_ones(), 1);
4336 assert_eq!(two_64.leading_zeros(), B - 65);
4337 assert_eq!(two_64.bit_length(), 65);
4338
4339 let two_64_m1 = Int::<4>::from_u128((1u128 << 64) - 1);
4340 assert_eq!(two_64_m1.trailing_zeros(), 0);
4341 assert_eq!(two_64_m1.count_ones(), 64);
4342 assert_eq!(two_64_m1.leading_zeros(), B - 64);
4343 assert_eq!(two_64_m1.bit_length(), 64);
4344 }
4345
4346 #[test]
4349 fn uint_bit_counts_match_unsigned_contract_at_edges() {
4350 for v in [0_u64, 1, u64::MAX, 42, 1 << 40] {
4352 let x = Uint::<1>::from_u64(v);
4353 assert_eq!(x.leading_zeros(), v.leading_zeros(), "u64 lz {v}");
4354 assert_eq!(x.count_ones(), v.count_ones(), "u64 popcount {v}");
4355 assert_eq!(x.bit_length(), 64 - v.leading_zeros(), "u64 bit_length {v}");
4357 }
4358
4359 for v in [0_u128, 1, u128::MAX, 1u128 << 64, (1u128 << 64) - 1] {
4362 let x = Uint::<2>::from_u128(v);
4363 assert_eq!(x.leading_zeros(), v.leading_zeros(), "u128 lz {v}");
4364 assert_eq!(x.count_ones(), v.count_ones(), "u128 popcount {v}");
4365 assert_eq!(x.bit_length(), 128 - v.leading_zeros(), "u128 bit_length {v}");
4366 }
4367
4368 const B: u32 = Uint::<4>::BITS; let zero = Uint::<4>::ZERO;
4371 assert_eq!(zero.leading_zeros(), B);
4372 assert_eq!(zero.count_ones(), 0);
4373 assert_eq!(zero.bit_length(), 0);
4374
4375 let umax = Uint::<4>::from_limbs([u64::MAX; 4]);
4377 assert_eq!(umax.leading_zeros(), 0);
4378 assert_eq!(umax.count_ones(), B);
4379 assert_eq!(umax.bit_length(), B);
4380
4381 let two_64 = Uint::<4>::from_u128(1u128 << 64);
4383 assert_eq!(two_64.count_ones(), 1);
4384 assert_eq!(two_64.leading_zeros(), B - 65);
4385 assert_eq!(two_64.bit_length(), 65);
4386 }
4387}
4388
4389#[cfg(test)]
4394mod hint_tests {
4395 use super::{Int, Uint};
4396
4397 #[test]
4398 fn signed_add_sub_neg() {
4399 let a = Int::<4>::from_i128(5);
4400 let b = Int::<4>::from_i128(3);
4401 assert_eq!(a.wrapping_add(b), Int::<4>::from_i128(8));
4402 assert_eq!(a.wrapping_sub(b), Int::<4>::from_i128(2));
4403 assert_eq!(b.wrapping_sub(a), Int::<4>::from_i128(-2));
4404 assert_eq!(a.negate(), Int::<4>::from_i128(-5));
4405 assert_eq!(Int::<4>::ZERO.negate(), Int::<4>::ZERO);
4406 }
4407
4408 #[test]
4409 fn signed_mul_div_rem() {
4410 let six = Int::<8>::from_i128(6);
4411 let two = Int::<8>::from_i128(2);
4412 let three = Int::<8>::from_i128(3);
4413 assert_eq!(six.wrapping_mul(three), Int::<8>::from_i128(18));
4414 assert_eq!(six.wrapping_div(two), three);
4415 assert_eq!(
4416 Int::<8>::from_i128(7).wrapping_rem(three),
4417 Int::<8>::from_i128(1)
4418 );
4419 assert_eq!(
4420 Int::<8>::from_i128(-7).wrapping_rem(three),
4421 Int::<8>::from_i128(-1)
4422 );
4423 assert_eq!(six.negate().wrapping_mul(three), Int::<8>::from_i128(-18));
4424 }
4425
4426 #[test]
4427 fn checked_overflow() {
4428 assert_eq!(Int::<4>::MAX.checked_add(Int::<4>::ONE), None);
4429 assert_eq!(Int::<4>::MIN.checked_sub(Int::<4>::ONE), None);
4430 assert_eq!(Int::<4>::MIN.checked_neg(), None);
4431 assert_eq!(
4432 Int::<4>::from_i128(2).checked_add(Int::<4>::from_i128(3)),
4433 Some(Int::<4>::from_i128(5))
4434 );
4435 }
4436
4437 #[test]
4438 fn from_str_and_pow() {
4439 let ten = Int::<16>::from_str_radix("10", 10).unwrap();
4440 assert_eq!(ten, Int::<16>::from_i128(10));
4441 assert_eq!(ten.pow(3), Int::<16>::from_i128(1000));
4442 let big = Int::<16>::from_str_radix("10", 10).unwrap().pow(40);
4443 let from_str =
4444 Int::<16>::from_str_radix("10000000000000000000000000000000000000000", 10).unwrap();
4445 assert_eq!(big, from_str);
4446 assert_eq!(
4447 Int::<4>::from_str_radix("-42", 10).unwrap(),
4448 Int::<4>::from_i128(-42)
4449 );
4450 }
4451
4452 #[test]
4453 fn ordering_and_resize() {
4454 assert!(Int::<4>::from_i128(-1) < Int::<4>::ZERO);
4455 assert!(Int::<4>::MIN < Int::<4>::MAX);
4456 let v = Int::<4>::from_i128(-123_456_789);
4457 let wide: Int<16> = v.resize();
4458 let back: Int<4> = wide.resize();
4459 assert_eq!(back, v);
4460 assert_eq!(wide, Int::<16>::from_i128(-123_456_789));
4461 }
4462
4463 #[cfg(feature = "_wide-support")]
4465 #[test]
4466 fn isqrt_and_f64() {
4467 assert_eq!(Int::<8>::from_i128(144).isqrt(), Int::<8>::from_i128(12));
4468 assert_eq!(Int::<4>::from_i128(1_000_000).as_f64(), 1_000_000.0);
4469 assert_eq!(Int::<4>::from_f64(-2_500.0), Int::<4>::from_i128(-2500));
4470 }
4471
4472 #[test]
4475 fn uint256_is_zero_and_bit_helpers() {
4476 let zero = Uint::<4>::ZERO;
4477 let one = Uint::<4>::from_str_radix("1", 10).unwrap();
4478 let two = Uint::<4>::from_str_radix("2", 10).unwrap();
4479 assert!(zero.is_zero());
4480 assert!(!one.is_zero());
4481 assert!(one.is_power_of_two());
4482 assert!(two.is_power_of_two());
4483 let three = Uint::<4>::from_str_radix("3", 10).unwrap();
4484 assert!(!three.is_power_of_two());
4485 assert_eq!(zero.next_power_of_two(), one);
4486 assert_eq!(one.next_power_of_two(), one);
4487 let four = Uint::<4>::from_str_radix("4", 10).unwrap();
4488 assert_eq!(three.next_power_of_two(), four);
4489 assert_eq!(zero.count_ones(), 0);
4490 assert_eq!(one.count_ones(), 1);
4491 assert_eq!(zero.leading_zeros(), Uint::<4>::BITS);
4492 assert_eq!(one.leading_zeros(), Uint::<4>::BITS - 1);
4493 }
4494
4495 #[test]
4496 fn uint256_parse_arithmetic_and_pow() {
4497 assert!(Uint::<4>::from_str_radix("10", 2).is_err());
4498 assert!(Uint::<4>::from_str_radix("1a", 10).is_err());
4499 let two = Uint::<4>::from_str_radix("2", 10).unwrap();
4500 let three = Uint::<4>::from_str_radix("3", 10).unwrap();
4501 let six = Uint::<4>::from_str_radix("6", 10).unwrap();
4502 let seven = Uint::<4>::from_str_radix("7", 10).unwrap();
4503 assert_eq!(three - two, Uint::<4>::from_str_radix("1", 10).unwrap());
4504 assert_eq!(six / two, three);
4505 assert_eq!(seven % three, Uint::<4>::from_str_radix("1", 10).unwrap());
4506 let five = Uint::<4>::from_str_radix("5", 10).unwrap();
4507 let four = Uint::<4>::from_str_radix("4", 10).unwrap();
4508 let one = Uint::<4>::from_str_radix("1", 10).unwrap();
4509 assert_eq!(five & four, four);
4510 assert_eq!(five | one, five);
4511 assert_eq!(five ^ four, one);
4512 let p10 = two.pow(10);
4513 assert_eq!(p10, Uint::<4>::from_str_radix("1024", 10).unwrap());
4514 let signed = three.cast_signed();
4515 assert_eq!(signed, Int::<4>::from_i128(3));
4516 }
4517
4518 #[test]
4520 fn signed_bit_and_trailing_zeros() {
4521 let v = Int::<4>::from_i128(0b1100);
4522 assert!(v.bit(2));
4523 assert!(v.bit(3));
4524 assert!(!v.bit(0));
4525 assert!(!v.bit(1));
4526 assert!(!v.bit(1000));
4527 let n = Int::<4>::from_i128(-1);
4528 assert!(n.bit(1000));
4529 assert_eq!(Int::<4>::from_i128(8).trailing_zeros(), 3);
4530 assert_eq!(Int::<4>::ZERO.trailing_zeros(), Int::<4>::BITS);
4531 }
4532
4533 #[test]
4535 fn as_u128_returns_low_magnitude_bits() {
4536 let src = Int::<4>::from_i128(123_456_789);
4537 let dst: u128 = src.as_u128();
4538 assert_eq!(dst, 123_456_789);
4539 let dst: u128 = Int::<4>::ZERO.as_u128();
4540 assert_eq!(dst, 0);
4541 }
4542}