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 (lhs_limbs, rhs_limbs) = (&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 lhs_limb = lhs_limbs[i];
176 if lhs_limb != 0 {
177 let mut carry: u64 = 0;
178 let mut j = 0;
179 while j < N {
180 let prod = (lhs_limb as u128) * (rhs_limbs[j] as u128);
181 if i + j < N {
182 let column = prod + (out[i + j] as u128) + (carry as u128);
183 out[i + j] = column as u64;
184 carry = (column >> 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 root = self.isqrt();
443 return (root, root.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(|power| power == 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(value: u128) -> Self {
493 let mut limbs = [0u64; N];
494 if N > 0 {
495 limbs[0] = value as u64;
496 }
497 if N > 1 {
498 limbs[1] = (value >> 64) as u64;
499 }
500 Self { limbs }
501 }
502
503 #[inline]
506 pub(crate) const fn try_from_u128(value: u128) -> Option<Self> {
507 if N >= 2 || value <= u64::MAX as u128 {
508 Some(Self::from_u128(value))
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(text: &str, radix: u32) -> Result<Self, ()> {
571 if radix != 10 {
572 return Err(());
573 }
574 let bytes = text.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 digit = (ch - b'0') as u64;
586 let mut carry: u64 = digit;
587 let mut j = 0;
588 while j < N {
589 let product = (acc[j] as u128) * 10u128 + (carry as u128);
590 acc[j] = product as u64;
591 carry = (product >> 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 quotient = [0u64; N];
681 let mut remainder = [0u64; N];
682 div_rem_dispatch(&self.limbs, &rhs.limbs, &mut quotient, &mut remainder);
683 Self { limbs: quotient }
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 quotient = [0u64; N];
692 let mut remainder = [0u64; N];
693 div_rem_dispatch(&self.limbs, &rhs.limbs, &mut quotient, &mut remainder);
694 Self { limbs: remainder }
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(value: i128) -> Option<Self> {
908 let mag = value.unsigned_abs();
909 let built = Self::from_mag_limbs(&[mag as u64, (mag >> 64) as u64], value < 0);
910 if N >= 2 || built.as_i128() == value {
911 Some(built)
912 } else {
913 None
914 }
915 }
916
917 #[inline]
921 pub(crate) const fn try_from_u128(value: u128) -> Option<Self> {
922 let built = Self::from_mag_limbs(&[value as u64, (value >> 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 == value {
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(wide) if wide >= i32::MIN as i128 && wide <= i32::MAX as i128 =>
955 Some(wide as i32),
956 _ => None,
957 }
958 }
959
960 #[inline]
962 pub(crate) fn try_to_u32(self) -> Option<u32> {
963 match self.to_u128_checked() {
964 Some(wide) if wide <= u32::MAX as u128 => Some(wide as u32),
965 _ => None,
966 }
967 }
968
969 #[inline]
971 pub(crate) fn try_to_i64(self) -> Option<i64> {
972 match self.to_i128_checked() {
973 Some(wide) if wide >= i64::MIN as i128 && wide <= i64::MAX as i128 =>
974 Some(wide as i64),
975 _ => None,
976 }
977 }
978
979 #[inline]
981 pub(crate) fn try_to_u64(self) -> Option<u64> {
982 match self.to_u128_checked() {
983 Some(wide) if wide <= u64::MAX as u128 => Some(wide as u64),
984 _ => None,
985 }
986 }
987
988 #[inline]
991 pub(crate) fn try_to_i128(self) -> Option<i128> {
992 self.to_i128_checked()
993 }
994
995 #[inline]
998 pub(crate) fn try_to_u128(self) -> Option<u128> {
999 self.to_u128_checked()
1000 }
1001
1002 #[inline]
1004 pub fn is_one(&self) -> bool {
1005 if N == 0 || self.limbs[0] != 1 {
1006 return false;
1007 }
1008 let mut i = 1;
1009 while i < N {
1010 if self.limbs[i] != 0 {
1011 return false;
1012 }
1013 i += 1;
1014 }
1015 true
1016 }
1017
1018 #[inline]
1020 pub fn min_value() -> Self {
1021 let mut limbs = [0u64; N];
1022 if N > 0 {
1023 limbs[N - 1] = 1u64 << 63;
1024 }
1025 Self { limbs }
1026 }
1027
1028 #[inline]
1030 pub fn max_value() -> Self {
1031 let mut limbs = [u64::MAX; N];
1032 if N > 0 {
1033 limbs[N - 1] = u64::MAX >> 1;
1034 }
1035 Self { limbs }
1036 }
1037
1038 #[inline]
1046 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
1047 crate::int::policy::add::dispatch_checked(self, rhs)
1048 }
1049
1050 #[inline]
1055 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
1056 crate::int::policy::sub::dispatch_checked(self, rhs)
1057 }
1058
1059 #[inline]
1063 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
1064 if self.is_zero() || rhs.is_zero() {
1065 return Some(Self::ZERO);
1066 }
1067 let negative = self.is_negative() ^ rhs.is_negative();
1068 let lhs_mag = Uint::<N>::from_limbs(*self.abs().as_limbs());
1069 let rhs_mag = Uint::<N>::from_limbs(*rhs.abs().as_limbs());
1070 let prod = lhs_mag.checked_mul(rhs_mag)?;
1071 let signed = Self::from_limbs(*prod.as_limbs());
1072 if negative {
1073 let negated = signed.wrapping_neg();
1074 if negated.is_negative() || negated.is_zero() {
1077 Some(negated)
1078 } else {
1079 None
1080 }
1081 } else if signed.is_negative() {
1082 None
1084 } else {
1085 Some(signed)
1086 }
1087 }
1088
1089 #[inline]
1096 pub const fn wrapping_pow(self, exp: u32) -> Self {
1097 Self::from_limbs(*pow_dispatch(self.cast_unsigned(), exp).as_limbs())
1098 }
1099
1100 #[inline]
1102 pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
1103 let mut acc = Self::ONE;
1104 let mut base = self;
1105 loop {
1106 if exp & 1 == 1 {
1107 acc = acc.checked_mul(base)?;
1108 }
1109 exp >>= 1;
1110 if exp == 0 {
1111 break;
1112 }
1113 base = base.checked_mul(base)?;
1114 }
1115 Some(acc)
1116 }
1117
1118 #[inline]
1124 pub const fn wrapping_sqr(self) -> Self {
1125 Self::from_limbs(*sqr_dispatch(self.cast_unsigned()).as_limbs())
1126 }
1127
1128 #[inline]
1134 pub const fn wrapping_cube(self) -> Self {
1135 Self::from_limbs(*cube_dispatch(self.cast_unsigned()).as_limbs())
1136 }
1137
1138 #[inline]
1152 pub const fn bit_length(&self) -> u32 {
1153 bit_len_fixed(self.abs().as_limbs())
1154 }
1155
1156 #[inline]
1166 pub const fn leading_zeros(&self) -> u32 {
1167 if self.is_negative() {
1168 0
1169 } else {
1170 Self::BITS - self.bit_length()
1171 }
1172 }
1173
1174 pub const TEN: Self = {
1184 let mut limbs = [0u64; N];
1185 if N > 0 {
1186 limbs[0] = 10;
1187 }
1188 Self { limbs }
1189 };
1190
1191 #[inline]
1193 pub const fn unsigned_abs(self) -> Uint<N> {
1194 Uint::from_limbs(*self.abs().as_limbs())
1195 }
1196
1197 #[inline]
1199 pub fn negate(self) -> Self {
1200 self.wrapping_neg()
1201 }
1202
1203 #[inline]
1211 pub fn div_rem(self, rhs: Self) -> (Self, Self) {
1212 assert!(!rhs.is_zero(), "attempt to divide by zero");
1213 let neg_q = self.is_negative() ^ rhs.is_negative();
1214 let neg_r = self.is_negative();
1215 let mut quot = [0u64; N];
1216 let mut rem = [0u64; N];
1217 div_rem_mag_fixed::<N>(
1218 self.unsigned_abs().as_limbs(),
1219 rhs.unsigned_abs().as_limbs(),
1220 &mut quot,
1221 &mut rem,
1222 );
1223 let quotient = Self::from_mag_limbs(", neg_q);
1224 let remainder = Self::from_mag_limbs(&rem, neg_r);
1225 (quotient, remainder)
1226 }
1227
1228 #[inline]
1231 pub(crate) const fn from_mag_limbs(mag: &[u64], negative: bool) -> Self {
1232 let mut out = [0u64; N];
1233 let copy_len = if mag.len() < N { mag.len() } else { N };
1234 let mut i = 0;
1235 while i < copy_len {
1236 out[i] = mag[i];
1237 i += 1;
1238 }
1239 let built = Self { limbs: out };
1240 if negative && !is_zero_fixed(&built.limbs) {
1243 built.wrapping_neg()
1244 } else {
1245 built
1246 }
1247 }
1248
1249 #[inline]
1251 pub const fn bit(self, idx: u32) -> bool {
1252 let limb = (idx / 64) as usize;
1253 if limb >= N {
1254 return self.is_negative();
1255 }
1256 (self.limbs[limb] >> (idx % 64)) & 1 == 1
1257 }
1258
1259 #[inline]
1263 pub(crate) const fn from_i128(value: i128) -> Self {
1264 if N <= 2 {
1270 let mut limbs = [0u64; N];
1271 limbs[0] = value as u64;
1272 if N == 2 {
1273 limbs[1] = (value >> 64) as u64;
1274 }
1275 return Self { limbs };
1276 }
1277 let mag = value.unsigned_abs();
1278 Self::from_mag_limbs(&[mag as u64, (mag >> 64) as u64], value < 0)
1279 }
1280
1281 #[inline]
1283 pub(crate) const fn from_u128(value: u128) -> Self {
1284 Self::from_mag_limbs(&[value as u64, (value >> 64) as u64], false)
1285 }
1286
1287 #[inline]
1290 pub const fn from_limbs_le(limbs: [u64; N]) -> Self {
1291 Self { limbs }
1292 }
1293
1294 #[inline]
1297 pub const fn limbs_le(self) -> [u64; N] {
1298 self.limbs
1299 }
1300
1301 #[inline]
1306 pub fn mul_u64(self, multiplier: u64) -> Self {
1307 let mag = *self.unsigned_abs().as_limbs();
1308 let mut prod = [0u64; N];
1309 let mut carry: u64 = 0;
1310 let mut i = 0;
1311 while i < N {
1312 let product = (mag[i] as u128) * (multiplier as u128) + (carry as u128);
1313 prod[i] = product as u64;
1314 carry = (product >> 64) as u64;
1315 i += 1;
1316 }
1317 if carry != 0 {
1318 panic!("Int: mul overflow");
1319 }
1320 let negative = self.is_negative();
1321 let scaled = Self::from_mag_limbs(&prod, negative);
1322 if !scaled.is_zero() && scaled.is_negative() != negative {
1325 panic!("Int: mul overflow");
1326 }
1327 scaled
1328 }
1329
1330 pub fn to_i128_checked(self) -> Option<i128> {
1332 let negative = self.is_negative();
1333 let mag = *self.unsigned_abs().as_limbs();
1334 let mut i = 2;
1336 while i < N {
1337 if mag[i] != 0 {
1338 return None;
1339 }
1340 i += 1;
1341 }
1342 let lo = if N > 0 { mag[0] as u128 } else { 0 };
1343 let hi = if N > 1 { mag[1] as u128 } else { 0 };
1344 let lo_u128 = lo | (hi << 64);
1345 if negative {
1346 if lo_u128 <= (i128::MAX as u128) + 1 {
1347 Some((lo_u128 as i128).wrapping_neg())
1348 } else {
1349 None
1350 }
1351 } else if lo_u128 <= i128::MAX as u128 {
1352 Some(lo_u128 as i128)
1353 } else {
1354 None
1355 }
1356 }
1357
1358 pub fn to_u128_checked(self) -> Option<u128> {
1360 if self.is_negative() {
1361 return None;
1362 }
1363 let mut i = 2;
1364 while i < N {
1365 if self.limbs[i] != 0 {
1366 return None;
1367 }
1368 i += 1;
1369 }
1370 let lo = if N > 0 { self.limbs[0] as u128 } else { 0 };
1371 let hi = if N > 1 { self.limbs[1] as u128 } else { 0 };
1372 Some(lo | (hi << 64))
1373 }
1374
1375 pub fn to_f64(self) -> f64 {
1378 let mag = *self.unsigned_abs().as_limbs();
1379 let radix: f64 = 18_446_744_073_709_551_616.0; let mut acc = 0.0f64;
1381 let mut i = N;
1382 while i > 0 {
1383 i -= 1;
1384 acc = acc * radix + mag[i] as f64;
1385 }
1386 if self.is_negative() { -acc } else { acc }
1387 }
1388
1389 pub fn to_f32(self) -> f32 {
1393 self.to_f64() as f32
1394 }
1395
1396 pub(crate) const fn try_from_f64(value: f64) -> Option<Self> {
1403 let bits = value.to_bits();
1404 let negative = (bits >> 63) & 1 == 1;
1405 let exp = ((bits >> 52) & 0x7ff) as i32;
1406 let mant = bits & 0x000f_ffff_ffff_ffff;
1407 if exp == 0x7ff {
1408 return None;
1410 }
1411 if exp == 0 {
1412 return if mant == 0 { Some(Self::ZERO) } else { None };
1415 }
1416 let significand = (1u64 << 52) | mant; let shift = exp - 1075; Self::from_significand_shift(significand, shift, negative)
1419 }
1420
1421 pub(crate) const fn try_from_f32(value: f32) -> Option<Self> {
1427 let bits = value.to_bits();
1428 let negative = (bits >> 31) & 1 == 1;
1429 let exp = ((bits >> 23) & 0xff) as i32;
1430 let mant = (bits & 0x007f_ffff) as u64;
1431 if exp == 0xff {
1432 return None;
1434 }
1435 if exp == 0 {
1436 return if mant == 0 { Some(Self::ZERO) } else { None };
1437 }
1438 let significand = (1u64 << 23) | mant; let shift = exp - 150; Self::from_significand_shift(significand, shift, negative)
1441 }
1442
1443 const fn from_significand_shift(significand: u64, shift: i32, negative: bool) -> Option<Self> {
1449 if shift < 0 {
1450 let right_shift = (-shift) as u32;
1451 if right_shift >= 64 {
1452 return None;
1455 }
1456 if significand & ((1u64 << right_shift) - 1) != 0 {
1457 return None;
1459 }
1460 let mag = significand >> right_shift; let built = Self::from_mag_limbs(&[mag], negative);
1462 Self::accept_signed(built, negative)
1463 } else {
1464 let left_shift = shift as u32;
1467 let limb_off = (left_shift / 64) as usize;
1468 let bit_off = left_shift % 64;
1469 let mut mag = [0u64; N];
1470 let lo = significand << bit_off;
1472 let hi = if bit_off == 0 {
1474 0
1475 } else {
1476 significand >> (64 - bit_off)
1477 };
1478 if limb_off < N {
1479 mag[limb_off] = lo;
1480 } else if lo != 0 {
1481 return None;
1482 }
1483 if hi != 0 {
1484 if limb_off + 1 < N {
1485 mag[limb_off + 1] = hi;
1486 } else {
1487 return None;
1488 }
1489 }
1490 let built = Self::from_mag_limbs(&mag, negative);
1491 Self::accept_signed(built, negative)
1492 }
1493 }
1494
1495 #[inline]
1501 const fn accept_signed(built: Self, negative: bool) -> Option<Self> {
1502 if is_zero_fixed(&built.limbs) {
1505 Some(built)
1506 } else if built.is_negative() != negative {
1507 None
1508 } else {
1509 Some(built)
1510 }
1511 }
1512
1513 pub fn from_f64(value: f64) -> Self {
1516 if !value.is_finite() {
1517 return Self::ZERO;
1518 }
1519 let negative = value < 0.0;
1520 let mut magnitude = if negative { -value } else { value };
1521 let radix: f64 = 18_446_744_073_709_551_616.0; let mut limbs = [0u64; N];
1523 let mut i = 0;
1524 while magnitude >= 1.0 && i < N {
1525 let rem = magnitude % radix;
1526 limbs[i] = rem as u64;
1527 magnitude = (magnitude - rem) / radix;
1528 i += 1;
1529 }
1530 if magnitude >= 1.0 {
1531 return if negative {
1532 Self::min_value()
1533 } else {
1534 Self::max_value()
1535 };
1536 }
1537 Self::from_mag_limbs(&limbs, negative)
1538 }
1539
1540 pub const fn from_str_radix(text: &str, radix: u32) -> Result<Self, ()> {
1544 if radix != 10 {
1545 return Err(());
1546 }
1547 let bytes = text.as_bytes();
1548 let (negative, start): (bool, usize) = if !bytes.is_empty() && bytes[0] == b'-' {
1549 (true, 1)
1550 } else {
1551 (false, 0)
1552 };
1553 if start >= bytes.len() {
1554 return Err(());
1555 }
1556 let mut acc = [0u64; N];
1561 let mut k = start;
1562 while k < bytes.len() {
1563 let ch = bytes[k];
1564 if ch < b'0' || ch > b'9' {
1565 return Err(());
1566 }
1567 let digit = (ch - b'0') as u64;
1568 let mut carry: u64 = digit;
1569 let mut j = 0;
1570 while j < N {
1571 let product = (acc[j] as u128) * 10u128 + (carry as u128);
1572 acc[j] = product as u64;
1573 carry = (product >> 64) as u64;
1574 j += 1;
1575 }
1576 k += 1;
1577 }
1578 Ok(Self::from_mag_limbs(&acc, negative))
1579 }
1580
1581 #[inline]
1589 pub const fn pow(self, exp: u32) -> Self {
1590 self.wrapping_pow(exp)
1591 }
1592
1593 #[inline]
1597 pub fn isqrt(self) -> Self {
1598 Self::from_limbs(*self.unsigned_abs().isqrt().as_limbs())
1599 }
1600
1601 #[inline]
1605 pub fn sqr(self) -> Self {
1606 self.wrapping_sqr()
1607 }
1608
1609 #[inline]
1613 pub fn cube(self) -> Self {
1614 self.wrapping_cube()
1615 }
1616
1617 #[inline]
1621 pub fn icbrt(self) -> Self {
1622 Self::from_limbs(*self.unsigned_abs().icbrt().as_limbs())
1623 }
1624
1625 #[inline]
1635 #[must_use]
1636 pub(crate) fn hypot(
1637 self,
1638 other: Self,
1639 mode: crate::support::rounding::RoundingMode,
1640 ) -> Option<Self>
1641 where
1642 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
1643 {
1644 hypot_dispatch::<N>(self, other, mode)
1645 }
1646
1647 #[inline]
1658 #[must_use]
1659 pub(crate) fn sum_sq(self, other: Self) -> Option<Self>
1660 where
1661 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
1662 {
1663 sum_sq_dispatch::<N>(self, other)
1664 }
1665
1666 #[inline]
1668 pub const fn cast_unsigned(self) -> Uint<N> {
1669 Uint::from_limbs(self.limbs)
1670 }
1671
1672 #[inline]
1675 pub fn as_f64(self) -> f64 {
1676 self.to_f64()
1677 }
1678
1679 #[inline]
1686 pub const fn count_ones(self) -> u32 {
1687 let mut total = 0;
1688 let mut i = 0;
1689 while i < N {
1690 total += self.limbs[i].count_ones();
1691 i += 1;
1692 }
1693 total
1694 }
1695
1696 #[inline]
1701 pub const fn count_zeros(self) -> u32 {
1702 Self::BITS - self.count_ones()
1703 }
1704
1705 #[inline]
1711 pub const fn trailing_zeros(self) -> u32 {
1712 let mut i = 0;
1713 while i < N {
1714 if self.limbs[i] != 0 {
1715 return i as u32 * 64 + self.limbs[i].trailing_zeros();
1716 }
1717 i += 1;
1718 }
1719 Self::BITS
1720 }
1721
1722 #[inline]
1725 pub const fn checked_neg(self) -> Option<Self> {
1726 if eq_dispatch(self, Self::MIN) {
1727 None
1728 } else {
1729 Some(self.wrapping_neg())
1730 }
1731 }
1732
1733 #[inline]
1735 pub const fn checked_div(self, rhs: Self) -> Option<Self> {
1736 if is_zero_fixed(&rhs.limbs) {
1737 None
1738 } else {
1739 Some(self.wrapping_div(rhs))
1740 }
1741 }
1742
1743 #[inline]
1747 pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
1748 if is_zero_fixed(&rhs.limbs) || self.is_min_neg_one(rhs) {
1749 None
1752 } else {
1753 Some(self.wrapping_rem(rhs))
1754 }
1755 }
1756
1757 #[inline]
1760 const fn is_min_neg_one(self, rhs: Self) -> bool {
1761 cmp_fixed(&self.limbs, &Self::MIN.limbs) == 0
1762 && cmp_fixed(&rhs.wrapping_neg().limbs, &Self::ONE.limbs) == 0
1763 }
1764
1765 #[inline]
1768 pub const fn div_euclid(self, rhs: Self) -> Self {
1769 let quotient = self.wrapping_div(rhs);
1770 let remainder = self.wrapping_rem(rhs);
1771 if remainder.is_negative() {
1772 if rhs.is_negative() {
1773 quotient.wrapping_add(Self::ONE)
1774 } else {
1775 quotient.wrapping_sub(Self::ONE)
1776 }
1777 } else {
1778 quotient
1779 }
1780 }
1781
1782 #[inline]
1784 pub const fn rem_euclid(self, rhs: Self) -> Self {
1785 let remainder = self.wrapping_rem(rhs);
1786 if remainder.is_negative() {
1787 remainder.wrapping_add(rhs.abs())
1788 } else {
1789 remainder
1790 }
1791 }
1792
1793 #[inline]
1795 pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
1796 let sum = self.wrapping_add(rhs);
1797 let lhs_negative = self.is_negative();
1798 let rhs_negative = rhs.is_negative();
1799 let sum_negative = sum.is_negative();
1800 (sum, lhs_negative == rhs_negative && sum_negative != lhs_negative)
1801 }
1802
1803 #[inline]
1806 pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
1807 let difference = self.wrapping_sub(rhs);
1808 let lhs_negative = self.is_negative();
1809 let rhs_negative = rhs.is_negative();
1810 let difference_negative = difference.is_negative();
1811 (difference, lhs_negative != rhs_negative && difference_negative != lhs_negative)
1812 }
1813
1814 #[inline]
1817 pub const fn overflowing_neg(self) -> (Self, bool) {
1818 let overflow = cmp_fixed(&self.limbs, &Self::MIN.limbs) == 0;
1819 (self.wrapping_neg(), overflow)
1820 }
1821
1822 #[inline]
1826 pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
1827 if self.is_min_neg_one(rhs) {
1828 (Self::ZERO, true)
1829 } else {
1830 (self.wrapping_rem(rhs), false)
1831 }
1832 }
1833
1834 #[inline]
1836 pub const fn saturating_add(self, rhs: Self) -> Self {
1837 match self.checked_add(rhs) {
1838 Some(exact) => exact,
1839 None => {
1840 if self.is_negative() {
1841 Self::MIN
1842 } else {
1843 Self::MAX
1844 }
1845 }
1846 }
1847 }
1848
1849 #[inline]
1851 pub const fn saturating_sub(self, rhs: Self) -> Self {
1852 match self.checked_sub(rhs) {
1853 Some(exact) => exact,
1854 None => {
1855 if self.is_negative() {
1856 Self::MIN
1857 } else {
1858 Self::MAX
1859 }
1860 }
1861 }
1862 }
1863
1864 #[inline]
1866 pub const fn saturating_neg(self) -> Self {
1867 match self.checked_neg() {
1868 Some(exact) => exact,
1869 None => Self::MAX,
1870 }
1871 }
1872
1873 #[inline]
1875 pub fn rotate_left(self, rotation: u32) -> Self {
1876 let bits = Self::BITS;
1877 let rotation = rotation % bits;
1878 if rotation == 0 {
1879 return self;
1880 }
1881 let unsigned = self.cast_unsigned();
1882 Self::from_limbs(((unsigned.shl(rotation)) | (unsigned.shr(bits - rotation))).limbs)
1883 }
1884
1885 #[inline]
1887 pub fn rotate_right(self, rotation: u32) -> Self {
1888 self.rotate_left(Self::BITS - (rotation % Self::BITS))
1889 }
1890
1891 #[inline]
1896 pub(crate) const fn as_u128(self) -> u128 {
1897 let mag = *self.unsigned_abs().as_limbs();
1898 let lo = if N > 0 { mag[0] as u128 } else { 0 };
1899 let hi = if N > 1 { mag[1] as u128 } else { 0 };
1900 lo | (hi << 64)
1901 }
1902
1903 #[inline]
1908 pub(crate) const fn as_i128(self) -> i128 {
1909 if N <= 2 {
1915 if N == 1 {
1916 return (self.limbs[0] as i64) as i128;
1917 }
1918 let lo = self.limbs[0] as u128;
1919 let hi = self.limbs[1] as u128;
1920 return (lo | (hi << 64)) as i128;
1921 }
1922 let mag = *self.unsigned_abs().as_limbs();
1923 let lo = if N > 0 { mag[0] as u128 } else { 0 };
1924 let hi = if N > 1 { mag[1] as u128 } else { 0 };
1925 let combined = lo | (hi << 64);
1926 if self.is_negative() {
1927 (combined as i128).wrapping_neg()
1928 } else {
1929 combined as i128
1930 }
1931 }
1932
1933 #[inline]
1938 pub(crate) fn resize<T: crate::int::types::traits::BigInt>(self) -> T {
1939 use crate::int::types::traits::BigInt as _;
1940 self.resize_to::<T>()
1941 }
1942
1943 #[inline]
1947 pub const fn wrapping_div(self, rhs: Self) -> Self {
1948 if is_zero_fixed(&rhs.limbs) {
1949 panic!("attempt to divide by zero");
1950 }
1951 let negative = self.is_negative() ^ rhs.is_negative();
1952 let mut quotient = [0u64; N];
1953 let mut remainder = [0u64; N];
1954 div_rem(
1955 self.unsigned_abs().as_limbs(),
1956 rhs.unsigned_abs().as_limbs(),
1957 &mut quotient,
1958 &mut remainder,
1959 );
1960 Self::from_mag_limbs("ient, negative)
1961 }
1962
1963 #[inline]
1966 pub const fn wrapping_rem(self, rhs: Self) -> Self {
1967 if is_zero_fixed(&rhs.limbs) {
1968 panic!("attempt to calculate the remainder with a divisor of zero");
1969 }
1970 let mut quotient = [0u64; N];
1971 let mut remainder = [0u64; N];
1972 div_rem(
1973 self.unsigned_abs().as_limbs(),
1974 rhs.unsigned_abs().as_limbs(),
1975 &mut quotient,
1976 &mut remainder,
1977 );
1978 Self::from_mag_limbs(&remainder, self.is_negative())
1979 }
1980
1981 #[inline]
1986 pub(crate) fn widen_mul<W>(self, rhs: Self) -> W
1987 where
1988 W: crate::int::types::traits::BigInt,
1989 W::Scratch: crate::int::types::compute_limbs::ComputeLimbs,
1990 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
1991 {
1992 use crate::int::types::compute_limbs::{ComputeLimbs, Limbs};
1993 let negative = self.is_negative() ^ rhs.is_negative();
1994 let lhs_mag = *self.unsigned_abs().as_limbs();
1995 let rhs_mag = *rhs.unsigned_abs().as_limbs();
1996 let mut prod_buf = <Limbs<N> as ComputeLimbs>::double_buffered_u64();
2004 let prod = prod_buf.as_mut();
2005 mul_fast::<N>(&lhs_mag, &rhs_mag, &mut prod[..2 * N]);
2006 let mut u128_buf = <W::Scratch as ComputeLimbs>::single_u128();
2011 let u128_prod = u128_buf.as_mut();
2012 let mut i = 0;
2013 while i < N {
2014 u128_prod[i] = (prod[2 * i] as u128) | ((prod[2 * i + 1] as u128) << 64);
2015 i += 1;
2016 }
2017 W::from_mag_sign_u128(&u128_prod[..N], negative)
2018 }
2019}
2020
2021impl<const N: usize> Int<N> {
2022 #[inline]
2031 pub(crate) const fn cmp_cross<const M: usize>(self, other: Int<M>) -> Ordering {
2032 let self_negative = self.is_negative();
2033 let other_negative = other.is_negative();
2034 if self_negative && !other_negative {
2035 return Ordering::Less;
2036 }
2037 if !self_negative && other_negative {
2038 return Ordering::Greater;
2039 }
2040 let self_mag = self.unsigned_abs();
2042 let other_mag = other.unsigned_abs();
2043 let mag_cmp = cmp_cross(self_mag.as_limbs(), other_mag.as_limbs());
2044 let mag_cmp = if self_negative { -mag_cmp } else { mag_cmp };
2046 if mag_cmp < 0 {
2047 Ordering::Less
2048 } else if mag_cmp > 0 {
2049 Ordering::Greater
2050 } else {
2051 Ordering::Equal
2052 }
2053 }
2054}
2055
2056impl<const N: usize> Int<N> {
2057 pub(crate) const fn cmp_cross_scaled<const M: usize>(
2085 self,
2086 other: Int<M>,
2087 scale_diff: u32,
2088 ) -> Ordering {
2089 let self_negative = self.is_negative();
2090 let other_negative = other.is_negative();
2091 if self_negative && !other_negative {
2092 return Ordering::Less;
2093 }
2094 if !self_negative && other_negative {
2095 return Ordering::Greater;
2096 }
2097
2098 let self_mag = self.unsigned_abs();
2101 let other_mag = other.unsigned_abs();
2102
2103 let mag_cmp = if scale_diff == 0 {
2104 cmp_cross(self_mag.as_limbs(), other_mag.as_limbs())
2105 } else {
2106 let mut pow = [0u64; max_n_limbs(4)];
2111 pow[0] = 1;
2112 let mut step = 0;
2113 while step < scale_diff {
2114 let mut carry: u128 = 0;
2116 let mut i = 0;
2117 while i < pow.len() {
2118 let prod = (pow[i] as u128) * 10u128 + carry;
2119 pow[i] = prod as u64;
2120 carry = prod >> 64;
2121 i += 1;
2122 }
2123 step += 1;
2124 }
2125
2126 let mut quotient = [0u64; max_n_limbs(4)];
2128 let mut remainder = [0u64; max_n_limbs(4)];
2129 div_rem(self_mag.as_limbs(), &pow, &mut quotient, &mut remainder);
2130
2131 let quotient_cmp = cmp_cross("ient, other_mag.as_limbs());
2133 if quotient_cmp != 0 {
2134 quotient_cmp
2135 } else {
2136 let mut limb_index = 0;
2138 let mut remainder_nonzero = false;
2139 while limb_index < remainder.len() {
2140 if remainder[limb_index] != 0 {
2141 remainder_nonzero = true;
2142 break;
2143 }
2144 limb_index += 1;
2145 }
2146 if remainder_nonzero {
2147 1
2148 } else {
2149 0
2150 }
2151 }
2152 };
2153
2154 let signed_cmp = if self_negative { -mag_cmp } else { mag_cmp };
2156 if signed_cmp < 0 {
2157 Ordering::Less
2158 } else if signed_cmp > 0 {
2159 Ordering::Greater
2160 } else {
2161 Ordering::Equal
2162 }
2163 }
2164}
2165
2166impl<const N: usize> Int<N> {
2167 pub(crate) const fn cmp_f64_exact(self, scale: u32, value: f64) -> Ordering {
2192 let bits = value.to_bits();
2193 let float_negative = (bits >> 63) != 0;
2194 let exp_field = ((bits >> 52) & 0x7ff) as i32;
2195 let frac = bits & 0x000f_ffff_ffff_ffff;
2196 let (mantissa, exponent): (u64, i32) = if exp_field == 0 {
2198 (frac, -1074)
2200 } else {
2201 (frac | 0x0010_0000_0000_0000, exp_field - 1075)
2202 };
2203
2204 let self_negative = self.is_negative();
2205 let float_is_zero = mantissa == 0;
2206 if float_is_zero {
2208 let self_limbs = self.as_limbs();
2210 let mut self_nonzero = false;
2211 let mut k = 0;
2212 while k < self_limbs.len() {
2213 if self_limbs[k] != 0 {
2214 self_nonzero = true;
2215 break;
2216 }
2217 k += 1;
2218 }
2219 if !self_nonzero {
2220 return Ordering::Equal;
2221 }
2222 return if self_negative { Ordering::Less } else { Ordering::Greater };
2223 }
2224 if self_negative && !float_negative {
2225 return Ordering::Less;
2226 }
2227 if !self_negative && float_negative {
2228 return Ordering::Greater;
2229 }
2230
2231 let self_mag = self.unsigned_abs();
2237 let self_mag_limbs = self_mag.as_limbs();
2238
2239 let mut pow10 = [0u64; 288];
2241 pow10[0] = 1;
2242 let mut step = 0;
2243 while step < scale {
2244 let mut carry: u128 = 0;
2245 let mut i = 0;
2246 while i < pow10.len() {
2247 let prod = (pow10[i] as u128) * 10u128 + carry;
2248 pow10[i] = prod as u64;
2249 carry = prod >> 64;
2250 i += 1;
2251 }
2252 step += 1;
2253 }
2254
2255 let mantissa_limbs = [mantissa];
2256
2257 let mut lhs = [0u64; 288];
2258 let mut rhs = [0u64; 288];
2259
2260 if exponent >= 0 {
2261 let mut i = 0;
2263 while i < self_mag_limbs.len() {
2264 lhs[i] = self_mag_limbs[i];
2265 i += 1;
2266 }
2267 let mut scaled_mantissa = [0u64; 288];
2269 mul_schoolbook(&mantissa_limbs, &pow10, &mut scaled_mantissa);
2270 shl(&scaled_mantissa, exponent as u32, &mut rhs);
2272 } else {
2273 shl(self_mag_limbs, (-exponent) as u32, &mut lhs);
2275 mul_schoolbook(&mantissa_limbs, &pow10, &mut rhs);
2276 }
2277
2278 let mag_cmp = cmp_cross(&lhs, &rhs);
2279 let signed_cmp = if self_negative { -mag_cmp } else { mag_cmp };
2281 if signed_cmp < 0 {
2282 Ordering::Less
2283 } else if signed_cmp > 0 {
2284 Ordering::Greater
2285 } else {
2286 Ordering::Equal
2287 }
2288 }
2289}
2290
2291impl<const N: usize, const M: usize> PartialEq<Int<M>> for Int<N> {
2297 #[inline]
2298 fn eq(&self, other: &Int<M>) -> bool {
2299 self.cmp_cross(*other) == Ordering::Equal
2300 }
2301}
2302
2303impl<const N: usize, const M: usize> PartialOrd<Int<M>> for Int<N> {
2304 #[inline]
2305 fn partial_cmp(&self, other: &Int<M>) -> Option<Ordering> {
2306 Some(self.cmp_cross(*other))
2307 }
2308}
2309
2310impl From<Int<2>> for i128 {
2319 #[inline]
2320 fn from(value: Int<2>) -> i128 {
2321 value.as_i128()
2322 }
2323}
2324
2325impl PartialEq<i128> for Int<2> {
2326 #[inline]
2327 fn eq(&self, other: &i128) -> bool {
2328 self.as_i128() == *other
2329 }
2330}
2331impl PartialEq<Int<2>> for i128 {
2332 #[inline]
2333 fn eq(&self, other: &Int<2>) -> bool {
2334 *self == other.as_i128()
2335 }
2336}
2337impl PartialOrd<i128> for Int<2> {
2338 #[inline]
2339 fn partial_cmp(&self, other: &i128) -> Option<Ordering> {
2340 self.as_i128().partial_cmp(other)
2341 }
2342}
2343impl PartialOrd<Int<2>> for i128 {
2344 #[inline]
2345 fn partial_cmp(&self, other: &Int<2>) -> Option<Ordering> {
2346 self.partial_cmp(&other.as_i128())
2347 }
2348}
2349
2350impl From<Int<1>> for i64 {
2355 #[inline]
2356 fn from(value: Int<1>) -> i64 {
2357 value.as_i128() as i64
2358 }
2359}
2360impl From<Int<1>> for i128 {
2362 #[inline]
2363 fn from(value: Int<1>) -> i128 {
2364 value.as_i128()
2365 }
2366}
2367impl PartialEq<i64> for Int<1> {
2368 #[inline]
2369 fn eq(&self, other: &i64) -> bool {
2370 self.as_i128() == *other as i128
2371 }
2372}
2373impl PartialEq<Int<1>> for i64 {
2374 #[inline]
2375 fn eq(&self, other: &Int<1>) -> bool {
2376 *self as i128 == other.as_i128()
2377 }
2378}
2379impl PartialOrd<i64> for Int<1> {
2380 #[inline]
2381 fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
2382 self.as_i128().partial_cmp(&(i128::from(*other)))
2383 }
2384}
2385impl PartialOrd<Int<1>> for i64 {
2386 #[inline]
2387 fn partial_cmp(&self, other: &Int<1>) -> Option<Ordering> {
2388 i128::from(*self).partial_cmp(&other.as_i128())
2389 }
2390}
2391
2392impl<const N: usize> Ord for Int<N> {
2393 #[inline]
2394 fn cmp(&self, other: &Self) -> Ordering {
2395 cmp_dispatch(*self, *other)
2399 }
2400}
2401
2402impl<const N: usize> Add for Int<N> {
2403 type Output = Self;
2404 #[inline]
2405 fn add(self, rhs: Self) -> Self {
2406 add_dispatch(self, rhs)
2407 }
2408}
2409
2410impl<const N: usize> Sub for Int<N> {
2411 type Output = Self;
2412 #[inline]
2413 fn sub(self, rhs: Self) -> Self {
2414 self.wrapping_sub(rhs)
2415 }
2416}
2417
2418impl<const N: usize> Mul for Int<N> {
2419 type Output = Self;
2420 #[inline]
2421 fn mul(self, rhs: Self) -> Self {
2422 self.wrapping_mul(rhs)
2423 }
2424}
2425
2426impl<const N: usize> BitAnd for Int<N> {
2427 type Output = Self;
2428 #[inline]
2429 fn bitand(self, rhs: Self) -> Self {
2430 let mut out = [0u64; N];
2431 let mut i = 0;
2432 while i < N {
2433 out[i] = self.limbs[i] & rhs.limbs[i];
2434 i += 1;
2435 }
2436 Self { limbs: out }
2437 }
2438}
2439
2440impl<const N: usize> BitOr for Int<N> {
2441 type Output = Self;
2442 #[inline]
2443 fn bitor(self, rhs: Self) -> Self {
2444 let mut out = [0u64; N];
2445 let mut i = 0;
2446 while i < N {
2447 out[i] = self.limbs[i] | rhs.limbs[i];
2448 i += 1;
2449 }
2450 Self { limbs: out }
2451 }
2452}
2453
2454impl<const N: usize> BitXor for Int<N> {
2455 type Output = Self;
2456 #[inline]
2457 fn bitxor(self, rhs: Self) -> Self {
2458 let mut out = [0u64; N];
2459 let mut i = 0;
2460 while i < N {
2461 out[i] = self.limbs[i] ^ rhs.limbs[i];
2462 i += 1;
2463 }
2464 Self { limbs: out }
2465 }
2466}
2467
2468impl<const N: usize> Not for Int<N> {
2469 type Output = Self;
2470 #[inline]
2471 fn not(self) -> Self {
2472 let mut out = [0u64; N];
2473 let mut i = 0;
2474 while i < N {
2475 out[i] = !self.limbs[i];
2476 i += 1;
2477 }
2478 Self { limbs: out }
2479 }
2480}
2481
2482impl<const N: usize> Shl<u32> for Int<N> {
2483 type Output = Self;
2484 #[inline]
2485 fn shl(self, shift: u32) -> Self {
2486 let mut out = [0u64; N];
2487 shl_fixed(&self.limbs, shift, &mut out);
2488 Self { limbs: out }
2489 }
2490}
2491
2492impl<const N: usize> Shr<u32> for Int<N> {
2493 type Output = Self;
2494 #[inline]
2495 fn shr(self, shift: u32) -> Self {
2496 let neg = self.is_negative();
2500 let src = if neg { !self } else { self };
2501 let mut out = [0u64; N];
2502 shr_fixed(&src.limbs, shift, &mut out);
2503 let shifted = Self { limbs: out };
2504 if neg { !shifted } else { shifted }
2505 }
2506}
2507
2508impl<const N: usize> Neg for Int<N> {
2509 type Output = Self;
2510 #[inline]
2511 fn neg(self) -> Self {
2512 self.wrapping_neg()
2513 }
2514}
2515
2516impl<const N: usize> Div for Int<N> {
2524 type Output = Self;
2525 #[inline]
2526 fn div(self, rhs: Self) -> Self {
2527 self.div_rem(rhs).0
2528 }
2529}
2530
2531impl<const N: usize> Rem for Int<N> {
2532 type Output = Self;
2533 #[inline]
2534 fn rem(self, rhs: Self) -> Self {
2535 rem_dispatch(self, rhs)
2536 }
2537}
2538
2539impl<const N: usize> core::fmt::Display for Uint<N>
2545where
2546 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2547{
2548 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2549 let mut buf =
2553 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2554 let rendered = fmt_into::<N>(&self.limbs, 10, true, buf.as_mut());
2555 formatter.pad_integral(true, "", rendered)
2556 }
2557}
2558
2559impl<const N: usize> core::fmt::Display for Int<N>
2560where
2561 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2562{
2563 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2564 let mag = *self.unsigned_abs().as_limbs();
2565 let mut buf =
2570 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2571 let rendered = fmt_into::<N>(&mag, 10, true, buf.as_mut());
2572 formatter.pad_integral(!self.is_negative() || self.is_zero(), "", rendered)
2573 }
2574}
2575
2576impl<const N: usize> core::str::FromStr for Int<N> {
2577 type Err = ();
2578 #[inline]
2579 fn from_str(text: &str) -> Result<Self, ()> {
2580 Self::from_str_radix(text, 10)
2581 }
2582}
2583
2584impl<const N: usize> core::fmt::LowerHex for Int<N>
2594where
2595 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2596{
2597 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2598 let mut buf =
2599 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2600 let rendered = fmt_into::<N>(&self.limbs, 16, true, buf.as_mut());
2601 formatter.pad_integral(true, "0x", rendered)
2602 }
2603}
2604
2605impl<const N: usize> core::fmt::UpperHex for Int<N>
2606where
2607 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2608{
2609 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2610 let mut buf =
2611 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::digit_formatting_limbs_u8();
2612 let rendered = fmt_into::<N>(&self.limbs, 16, false, buf.as_mut());
2613 formatter.pad_integral(true, "0x", rendered)
2614 }
2615}
2616
2617impl<const N: usize> core::fmt::Octal for Int<N>
2618where
2619 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2620{
2621 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2622 let mut buf =
2623 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::bit_formatting_limbs_u8();
2624 let rendered = fmt_into::<N>(&self.limbs, 8, true, buf.as_mut());
2625 formatter.pad_integral(true, "0o", rendered)
2626 }
2627}
2628
2629impl<const N: usize> core::fmt::Binary for Int<N>
2630where
2631 crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
2632{
2633 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2634 let mut buf =
2635 <crate::int::types::compute_limbs::Limbs<N> as crate::int::types::compute_limbs::ComputeLimbs>::bit_formatting_limbs_u8();
2636 let rendered = fmt_into::<N>(&self.limbs, 2, true, buf.as_mut());
2637 formatter.pad_integral(true, "0b", rendered)
2638 }
2639}
2640
2641impl<const N: usize> Uint<N> {
2654 #[inline]
2661 pub const fn resize_n<const M: usize>(self) -> Uint<M> {
2662 let mut out = [0u64; M];
2663 let mut i = 0;
2664 while i < M {
2665 if i < N {
2666 out[i] = self.limbs[i];
2667 }
2668 i += 1;
2669 }
2670 Uint::from_limbs(out)
2671 }
2672
2673 #[inline]
2676 pub fn widen<const M: usize>(self) -> Uint<M> {
2677 debug_assert!(M >= N, "widen requires M >= N");
2678 self.resize_n::<M>()
2679 }
2680
2681 #[inline]
2684 pub fn narrow<const M: usize>(self) -> Option<Uint<M>> {
2685 debug_assert!(M <= N, "narrow requires M <= N");
2686 let keep = if M < N { M } else { N };
2687 let mut i = keep;
2688 while i < N {
2689 if self.limbs[i] != 0 {
2690 return None;
2691 }
2692 i += 1;
2693 }
2694 Some(self.resize_n::<M>())
2695 }
2696}
2697
2698impl<const N: usize> Int<N> {
2699 #[inline]
2715 pub(crate) const fn resize_n<const M: usize>(self) -> Int<M> {
2716 let fill = if self.is_negative() { u64::MAX } else { 0 };
2717 let mut out = [0u64; M];
2718 let mut i = 0;
2719 while i < M {
2720 out[i] = if i < N { self.limbs[i] } else { fill };
2721 i += 1;
2722 }
2723 Int::from_limbs(out)
2724 }
2725
2726 #[inline]
2732 pub(crate) const fn try_narrow<const M: usize>(self) -> Option<Int<M>> {
2733 debug_assert!(M >= 1 && M <= N, "try_narrow requires 1 <= M <= N");
2734 let sign_fill = if (self.limbs[M - 1] >> 63) == 1 {
2735 u64::MAX
2736 } else {
2737 0
2738 };
2739 let mut i = M;
2740 while i < N {
2741 if self.limbs[i] != sign_fill {
2742 return None;
2743 }
2744 i += 1;
2745 }
2746 Some(self.resize_n::<M>())
2747 }
2748
2749 #[inline]
2751 pub fn widen<const M: usize>(self) -> Int<M> {
2752 debug_assert!(M >= N, "widen requires M >= N");
2753 self.resize_n::<M>()
2754 }
2755
2756 #[inline]
2761 pub fn narrow<const M: usize>(self) -> Option<Int<M>> {
2762 self.try_narrow::<M>()
2763 }
2764}
2765
2766
2767
2768macro_rules! int_from_signed {
2777 ($($prim:ty => $base:ident),+) => {$(
2778 impl<const N: usize> From<$prim> for Int<N> {
2779 #[inline]
2780 fn from(value: $prim) -> Self { Self::$base(value) }
2781 }
2782 )+};
2783}
2784int_from_signed!(i8 => from_i8, i16 => from_i16, i32 => from_i32, i64 => from_i64);
2785
2786macro_rules! int_from_unsigned {
2787 ($($prim:ty => $base:ident),+) => {$(
2788 impl<const N: usize> From<$prim> for Int<N> {
2789 #[inline]
2790 fn from(value: $prim) -> Self { Self::$base(value) }
2791 }
2792 )+};
2793}
2794int_from_unsigned!(u8 => from_u8, u16 => from_u16, u32 => from_u32);
2795
2796macro_rules! uint_from_unsigned {
2797 ($($prim:ty),+) => {$(
2798 impl<const N: usize> From<$prim> for Uint<N> {
2799 #[inline]
2800 fn from(value: $prim) -> Self { Self::from_u64(value as u64) }
2801 }
2802 )+};
2803}
2804uint_from_unsigned!(u8, u16, u32, u64);
2805
2806impl<const N: usize> TryFrom<u64> for Int<N> {
2809 type Error = crate::support::error::ConvertError;
2810 #[inline]
2811 fn try_from(value: u64) -> Result<Self, Self::Error> {
2812 Self::try_from_u64(value).ok_or(crate::support::error::ConvertError::Overflow)
2813 }
2814}
2815
2816impl<const N: usize> TryFrom<i128> for Int<N> {
2817 type Error = crate::support::error::ConvertError;
2818 #[inline]
2819 fn try_from(value: i128) -> Result<Self, Self::Error> {
2820 Self::try_from_i128(value).ok_or(crate::support::error::ConvertError::Overflow)
2821 }
2822}
2823
2824impl<const N: usize> TryFrom<u128> for Int<N> {
2825 type Error = crate::support::error::ConvertError;
2826 #[inline]
2827 fn try_from(value: u128) -> Result<Self, Self::Error> {
2828 Self::try_from_u128(value).ok_or(crate::support::error::ConvertError::Overflow)
2829 }
2830}
2831
2832impl<const N: usize> TryFrom<Int<N>> for i32 {
2841 type Error = crate::support::error::ConvertError;
2842 #[inline]
2843 fn try_from(value: Int<N>) -> Result<Self, Self::Error> {
2844 value.try_to_i32().ok_or(crate::support::error::ConvertError::Overflow)
2845 }
2846}
2847
2848impl<const N: usize> TryFrom<Int<N>> for u32 {
2849 type Error = crate::support::error::ConvertError;
2850 #[inline]
2851 fn try_from(value: Int<N>) -> Result<Self, Self::Error> {
2852 value.try_to_u32().ok_or(crate::support::error::ConvertError::Overflow)
2853 }
2854}
2855
2856impl<const N: usize> TryFrom<Int<N>> for u64 {
2857 type Error = crate::support::error::ConvertError;
2858 #[inline]
2859 fn try_from(value: Int<N>) -> Result<Self, Self::Error> {
2860 value.try_to_u64().ok_or(crate::support::error::ConvertError::Overflow)
2861 }
2862}
2863
2864impl<const N: usize> TryFrom<Int<N>> for u128 {
2865 type Error = crate::support::error::ConvertError;
2866 #[inline]
2867 fn try_from(value: Int<N>) -> Result<Self, Self::Error> {
2868 value.try_to_u128().ok_or(crate::support::error::ConvertError::Overflow)
2869 }
2870}
2871
2872impl<const N: usize> TryFrom<u128> for Uint<N> {
2873 type Error = crate::support::error::ConvertError;
2874 #[inline]
2875 fn try_from(value: u128) -> Result<Self, Self::Error> {
2876 Self::try_from_u128(value).ok_or(crate::support::error::ConvertError::Overflow)
2877 }
2878}
2879
2880impl<const N: usize> TryFrom<f64> for Int<N> {
2886 type Error = crate::support::error::ConvertError;
2887 #[inline]
2888 fn try_from(value: f64) -> Result<Self, Self::Error> {
2889 Self::try_from_f64(value).ok_or(crate::support::error::ConvertError::Overflow)
2890 }
2891}
2892
2893impl<const N: usize> TryFrom<f32> for Int<N> {
2894 type Error = crate::support::error::ConvertError;
2895 #[inline]
2896 fn try_from(value: f32) -> Result<Self, Self::Error> {
2897 Self::try_from_f32(value).ok_or(crate::support::error::ConvertError::Overflow)
2898 }
2899}
2900
2901#[cfg(test)]
2902mod tests {
2903 use super::*;
2904 use crate::int::algos::mul::mul_schoolbook::{mul_low_fixed, mul_schoolbook_fixed};
2905
2906 #[test]
2907 fn try_from_i128_detects_narrow_overflow() {
2908 assert_eq!(Int::<2>::try_from_i128(i128::MAX), Some(Int::<2>::from_i128(i128::MAX)));
2910 assert_eq!(Int::<2>::try_from_i128(i128::MIN), Some(Int::<2>::from_i128(i128::MIN)));
2911 assert_eq!(Int::<1>::try_from_i128(i64::MAX as i128 + 1), None);
2913 assert_eq!(Int::<1>::try_from_i128(i64::MIN as i128 - 1), None);
2914 assert_eq!(
2915 Int::<1>::try_from_i128(i64::MAX as i128),
2916 Some(Int::<1>::from_i64(i64::MAX))
2917 );
2918 assert!(<Int<1> as TryFrom<i128>>::try_from(i64::MAX as i128 + 1).is_err());
2920 assert_eq!(<Int<2> as TryFrom<i128>>::try_from(-5_i128), Ok(Int::<2>::from_i64(-5)));
2921 }
2922
2923 #[test]
2924 fn try_from_u128_detects_narrow_overflow() {
2925 assert_eq!(Uint::<2>::try_from_u128(u128::MAX), Some(Uint::<2>::from_u128(u128::MAX)));
2927 assert_eq!(Uint::<1>::try_from_u128(u64::MAX as u128 + 1), None);
2928 assert_eq!(Uint::<1>::try_from_u128(u64::MAX as u128), Some(Uint::<1>::from_u64(u64::MAX)));
2929 assert!(<Uint<1> as TryFrom<u128>>::try_from(u64::MAX as u128 + 1).is_err());
2930 assert_eq!(Int::<1>::try_from_u128(u64::MAX as u128), None);
2932 assert_eq!(Int::<2>::try_from_u128(u128::MAX), None);
2933 assert_eq!(Int::<3>::try_from_u128(u128::MAX), Some(Int::<3>::from_u128(u128::MAX)));
2934 assert!(<Int<2> as TryFrom<u128>>::try_from(u128::MAX).is_err());
2935 }
2936
2937 #[test]
2938 fn try_from_u64_and_out_conversions_at_edges() {
2939 assert!(<Int<1> as TryFrom<u64>>::try_from(u64::MAX).is_err());
2941 assert_eq!(<Int<2> as TryFrom<u64>>::try_from(u64::MAX), Ok(Int::<2>::from_u128(u64::MAX as u128)));
2942 assert_eq!(i128::from(Int::<2>::MAX), i128::MAX);
2944 assert_eq!(i128::from(Int::<2>::MIN), i128::MIN);
2945 assert_eq!(i64::from(Int::<1>::from_i64(-123)), -123_i64);
2946 let big = Int::<3>::from_u128(u128::MAX);
2949 assert_eq!(big.try_to_i128(), None);
2950 assert_eq!(<i32 as TryFrom<Int<4>>>::try_from(Int::<4>::from_i64(-7)), Ok(-7_i32));
2951 assert!(<u32 as TryFrom<Int<4>>>::try_from(Int::<4>::from_i64(-1)).is_err());
2952 }
2953
2954 #[test]
2955 fn float_conversions_reject_and_round_trip() {
2956 assert_eq!(Int::<2>::try_from_f64(f64::NAN), None);
2958 assert_eq!(Int::<2>::try_from_f64(f64::INFINITY), None);
2959 assert_eq!(Int::<2>::try_from_f64(f64::NEG_INFINITY), None);
2960 assert_eq!(Int::<2>::try_from_f64(0.5), None);
2961 assert_eq!(Int::<2>::try_from_f64(3.5), None);
2962 assert_eq!(Int::<2>::try_from_f32(f32::NAN), None);
2963 assert_eq!(Int::<2>::try_from_f32(f32::INFINITY), None);
2964 assert_eq!(Int::<2>::try_from_f32(0.5), None);
2965 assert_eq!(Int::<2>::try_from_f32(3.5), None);
2966 assert_eq!(Int::<1>::try_from_f64(1e30), None); assert_eq!(Int::<2>::try_from_f64(0.0), Some(Int::<2>::ZERO));
2969 assert_eq!(Int::<2>::try_from_f64(-0.0), Some(Int::<2>::ZERO));
2970 assert_eq!(Int::<2>::try_from_f32(0.0), Some(Int::<2>::ZERO));
2971 assert_eq!(Int::<2>::try_from_f32(-0.0), Some(Int::<2>::ZERO));
2972 assert_eq!(Int::<4>::try_from_f64(42.0), Some(Int::<4>::from_i64(42)));
2974 assert_eq!(Int::<4>::try_from_f64(-42.0), Some(Int::<4>::from_i64(-42)));
2975 assert_eq!(Int::<4>::try_from_f32(7.0), Some(Int::<4>::from_i64(7)));
2976 assert_eq!(Int::<4>::try_from_f32(-7.0), Some(Int::<4>::from_i64(-7)));
2977 assert!(<Int<2> as TryFrom<f64>>::try_from(f64::NAN).is_err());
2979 assert_eq!(<Int<2> as TryFrom<f64>>::try_from(-9.0), Ok(Int::<2>::from_i64(-9)));
2980 assert_eq!(<Int<2> as TryFrom<f32>>::try_from(-9.0), Ok(Int::<2>::from_i64(-9)));
2981 assert_eq!(Int::<4>::from_i64(123).to_f64(), 123.0);
2983 assert_eq!(Int::<4>::from_i64(-123).to_f64(), -123.0);
2984 assert_eq!(Int::<4>::from_i64(123).to_f32(), 123.0_f32);
2985 }
2986
2987 #[test]
2988 fn float_conversions_wide_and_boundaries() {
2989 let big = 2f64.powi(64); assert_eq!(Int::<1>::try_from_f64(big), None);
2993 assert_eq!(
2994 Int::<2>::try_from_f64(big),
2995 Some(Int::<2>::from_u128(1u128 << 64))
2996 );
2997
2998 let two_63 = 2f64.powi(63);
3001 assert_eq!(Int::<1>::try_from_f64(two_63), None);
3002 let near_max = (i64::MAX - 1023) as f64; assert_eq!(near_max as i64, i64::MAX - 1023);
3006 assert_eq!(
3007 Int::<1>::try_from_f64(near_max),
3008 Some(Int::<1>::from_i64(i64::MAX - 1023))
3009 );
3010
3011 let min_edge = -(2f64.powi(63));
3013 assert_eq!(
3014 Int::<1>::try_from_f64(min_edge),
3015 Some(Int::<1>::from_i64(i64::MIN))
3016 );
3017 assert_eq!(Int::<1>::try_from_f64(-(2f64.powi(64))), None);
3019
3020 let two_24 = 2f32.powi(24);
3022 assert_eq!(
3023 Int::<1>::try_from_f32(two_24),
3024 Some(Int::<1>::from_i64(1 << 24))
3025 );
3026 }
3027
3028 #[test]
3029 fn float_conversions_are_const() {
3030 const X: Option<Int<2>> = Int::<2>::try_from_f64(42.0);
3032 const Y: Option<Int<2>> = Int::<2>::try_from_f32(42.0);
3033 assert_eq!(X, Some(Int::<2>::from_i64(42)));
3034 assert_eq!(Y, Some(Int::<2>::from_i64(42)));
3035 }
3036
3037 #[test]
3038 fn from_traits_are_infallible_for_fitting_prims() {
3039 assert_eq!(Int::<1>::from(-7_i32), Int::<1>::from_i64(-7));
3040 assert_eq!(Int::<4>::from(42_i64), Int::<4>::from_i64(42));
3041 assert_eq!(Uint::<1>::from(7_u32), Uint::<1>::from_u64(7));
3042 assert_eq!(Uint::<4>::from(u64::MAX), Uint::<4>::from_u64(u64::MAX));
3043 }
3044
3045 #[test]
3049 fn fixed_int_trait_surface() {
3050 fn exercises<T: BigInt>(seven: T, three: T) {
3051 assert_eq!(T::LIMBS as u32 * 64, T::BITS);
3052 assert!(T::ZERO.is_zero());
3053 assert!(T::ONE.is_one());
3054 assert!(!T::ZERO.is_one());
3055
3056 let ten = seven + three;
3058 assert_eq!(ten - three, seven);
3059 assert_eq!(ten, seven.wrapping_add(three));
3060 assert_eq!(seven.wrapping_sub(three) + three, seven);
3061
3062 let _ = (seven & three) | (seven ^ three);
3064 let _ = !T::ZERO;
3065 assert_eq!((T::ONE << 4) >> 4, T::ONE);
3066
3067 assert_eq!(seven.checked_add(three), Some(ten));
3069 assert!(seven.checked_mul(three).is_some());
3070
3071 assert_eq!(three.sqr(), three * three);
3073 assert_eq!(three.cube(), three * three * three);
3074 assert_eq!(three.pow(2), three.sqr());
3075 assert_eq!(three.wrapping_pow(3), three.cube());
3076 assert_eq!(three.checked_pow(2), Some(three.sqr()));
3077
3078 assert_eq!(T::ONE.bit_length(), 1);
3080 assert_eq!(T::ZERO.bit_length(), 0);
3081 assert_eq!(T::ONE.leading_zeros(), T::BITS - 1);
3082
3083 let items = [T::ONE, T::ONE, T::ONE];
3085 assert_eq!(T::sum(items), three);
3086 assert_eq!(T::product([three, T::ONE]), three);
3087 assert_eq!(T::from_limbs(seven.to_limbs()), seven);
3088 }
3089
3090 exercises(Int::<4>::from_i64(7), Int::<4>::from_i64(3));
3091 exercises(Int::<6>::from_i64(7), Int::<6>::from_i64(3));
3092 }
3093
3094 #[test]
3097 fn limbs_mul_low_matches_full_product_low_half() {
3098 fn check<const N: usize, const D: usize>(lhs: [u64; N], rhs: [u64; N]) {
3099 debug_assert!(D == 2 * N);
3100 let mut full = [0u64; D];
3101 mul_schoolbook_fixed::<N, D>(&lhs, &rhs, &mut full);
3102 let mut low = [0u64; N];
3103 mul_low_fixed::<N>(&lhs, &rhs, &mut low);
3104 let mut expected = [0u64; N];
3105 expected.copy_from_slice(&full[..N]);
3106 assert_eq!(low, expected, "low-half mismatch for {lhs:?} * {rhs:?}");
3107 }
3108
3109 check::<4, 8>([0, 0, 0, 0], [0, 0, 0, 0]);
3111 check::<4, 8>([1, 0, 0, 0], [u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
3112 check::<4, 8>([u64::MAX; 4], [u64::MAX; 4]);
3113 check::<4, 8>([0, 1, 0, 0], [0, 1, 0, 0]); check::<4, 8>(
3115 [0xDEAD_BEEF, 0xCAFE_F00D, 0x1234, 0x5678_9ABC],
3116 [0xFEED_FACE, 0x0BAD_C0DE, 0x9999, 0x0000_0001],
3117 );
3118 check::<2, 4>([u64::MAX, u64::MAX], [3, 0]);
3120 check::<6, 12>([7, 8, 9, 10, 11, 12], [1, 2, 3, 4, 5, 6]);
3121 }
3122
3123 #[test]
3126 fn dedicated_sqr_matches_general_mul() {
3127 fn check<const N: usize>(limbs: [u64; N]) {
3128 let value = Uint::<N>::from_limbs(limbs);
3129 assert_eq!(
3130 value.wrapping_sqr(),
3131 value.wrapping_mul(value),
3132 "sqr != mul(self,self) for {limbs:?}"
3133 );
3134 }
3135
3136 check::<4>([0, 0, 0, 0]);
3138 check::<4>([1, 0, 0, 0]);
3139 check::<4>([u64::MAX; 4]);
3140 check::<4>([0x1234_5678, 0, 0, 0]);
3141 check::<4>([u64::MAX, u64::MAX, 0, 0]);
3142 check::<4>([0xDEAD_BEEF_CAFE_F00D, 0x0123_4567_89AB_CDEF, 0xFEDC, 0x99]);
3143 check::<4>([u64::MAX, u64::MAX, u64::MAX, 0]);
3145 check::<1>([u64::MAX]);
3147 check::<2>([u64::MAX, u64::MAX]);
3148 check::<6>([7, 8, 9, 10, 11, 12]);
3149 check::<8>([u64::MAX, 1, u64::MAX, 2, u64::MAX, 3, u64::MAX, 4]);
3150 let mut state = 0x9E37_79B9_7F4A_7C15u64;
3152 let mut next = || {
3153 state ^= state << 13;
3154 state ^= state >> 7;
3155 state ^= state << 17;
3156 state
3157 };
3158 for _ in 0..64 {
3159 check::<5>([next(), next(), next(), next(), next()]);
3160 }
3161 }
3162
3163 #[test]
3164 fn uint_sqr_cube_match_naive() {
3165 let x = Uint::<4>::from_limbs([123_456_789, 0, 0, 0]);
3166 assert_eq!(x.wrapping_sqr(), x.wrapping_mul(x));
3167 assert_eq!(x.wrapping_cube(), x.wrapping_mul(x).wrapping_mul(x));
3168
3169 let y = Uint::<4>::from_limbs([0xDEAD_BEEF_CAFE, 0x1234_5678, 0, 0]);
3171 assert_eq!(y.wrapping_sqr(), y.wrapping_mul(y));
3172 assert_eq!(y.wrapping_cube(), y.wrapping_mul(y).wrapping_mul(y));
3173 }
3174
3175 #[cfg(feature = "_wide-support")]
3183 #[test]
3184 fn root_int_floor_and_exactness() {
3185 fn brute(m: u128, k: u32) -> (u128, bool) {
3187 if m == 0 {
3188 return (0, true);
3189 }
3190 let mut root: u128 = 0;
3191 while {
3193 let next = root + 1;
3194 next.checked_pow(k).is_some_and(|power| power <= m)
3195 } {
3196 root += 1;
3197 }
3198 (root, root.pow(k) == m)
3199 }
3200
3201 fn check<const N: usize>(m: u128, k: u32) {
3202 let lo = (m & 0xFFFF_FFFF_FFFF_FFFF) as u64;
3203 let hi = (m >> 64) as u64;
3204 let mut limbs = [0u64; N];
3205 limbs[0] = lo;
3206 if N > 1 {
3207 limbs[1] = hi;
3208 }
3209 let value = Uint::<N>::from_limbs(limbs);
3210 let (root, exact) = value.root_int(k);
3211 let (expected_root, expected_exact) = brute(m, k);
3212 let root_lo = root.as_limbs()[0] as u128
3213 | ((if N > 1 { root.as_limbs()[1] as u128 } else { 0 }) << 64);
3214 assert_eq!(root_lo, expected_root, "root mismatch for m={m}, k={k}");
3215 assert_eq!(exact, expected_exact, "exact flag mismatch for m={m}, k={k}");
3216
3217 let root_pow = root.pow(k);
3219 assert!(root_pow <= value, "root^k > m for m={m}, k={k}");
3220 let next = root.wrapping_add(Uint::<N>::ONE);
3221 if let Some(next_pow) = next.checked_pow(k) { assert!(next_pow > value, "(root+1)^k <= m for m={m}, k={k}") }
3223 }
3224
3225 let samples: [u128; 14] = [
3226 0,
3227 1,
3228 2,
3229 7,
3230 8,
3231 9,
3232 26,
3233 27,
3234 28,
3235 1000,
3236 1023,
3237 1024,
3238 1_000_000,
3239 u64::MAX as u128,
3240 ];
3241 for &m in &samples {
3242 for k in [2u32, 3, 5] {
3243 check::<4>(m, k);
3244 check::<2>(m, k);
3245 check::<8>(m, k);
3246 }
3247 }
3248
3249 let big = Uint::<4>::from_limbs([0xFFFF_FFFF_FFFF_FFFF, 0x1234_5678, 0, 0]);
3251 assert_eq!(big.root_int(2).0, big.isqrt());
3252
3253 let base = Uint::<4>::ONE.shl(40);
3255 let cube = base.wrapping_cube();
3256 let (r, exact) = cube.root_int(3);
3257 assert_eq!(r, base);
3258 assert!(exact);
3259 let (r2, exact2) = cube.wrapping_sub(Uint::<4>::ONE).root_int(3);
3261 assert_eq!(r2, base.wrapping_sub(Uint::<4>::ONE));
3262 assert!(!exact2);
3263 }
3264
3265 #[test]
3266 fn uint_widen_zero_extends() {
3267 let a = Uint::<2>::from_limbs([7, 8]);
3268 let w = a.widen::<4>();
3269 assert_eq!(*w.as_limbs(), [7, 8, 0, 0]);
3270 assert_eq!(a.resize_n::<4>(), w);
3271 }
3272
3273 #[test]
3274 fn uint_narrow_checks_dropped_limbs() {
3275 let fits = Uint::<4>::from_limbs([7, 8, 0, 0]);
3276 assert_eq!(*fits.narrow::<2>().unwrap().as_limbs(), [7, 8]);
3277
3278 let too_big = Uint::<4>::from_limbs([7, 8, 1, 0]);
3279 assert!(too_big.narrow::<2>().is_none());
3280
3281 let a = Uint::<2>::from_limbs([3, 4]);
3283 assert_eq!(a.widen::<4>().narrow::<2>().unwrap(), a);
3284 }
3285
3286 #[test]
3287 fn int_widen_sign_extends() {
3288 let neg = Int::<2>::from_i64(-1);
3290 assert_eq!(*neg.widen::<4>().as_limbs(), [u64::MAX; 4]);
3291 assert_eq!(neg.widen::<4>(), Int::<4>::from_i64(-1));
3292 let pos = Int::<2>::from_i64(5);
3294 assert_eq!(*pos.widen::<4>().as_limbs(), [5, 0, 0, 0]);
3295 }
3296
3297 #[test]
3298 fn int_narrow_requires_sign_consistency() {
3299 let neg = Int::<4>::from_i64(-1);
3301 assert_eq!(neg.narrow::<2>().unwrap(), Int::<2>::from_i64(-1));
3302 let big = Int::<4>::from_limbs([0, 0, 1, 0]);
3304 assert!(big.narrow::<2>().is_none());
3305 let weird = Int::<4>::from_limbs([1, 0, 0, u64::MAX]);
3307 assert!(weird.narrow::<2>().is_none());
3308 let p = Int::<2>::from_i64(42);
3310 assert_eq!(p.widen::<4>().narrow::<2>().unwrap(), p);
3311 }
3312
3313 #[test]
3314 fn int_resize_const_two_complement() {
3315 let pos = Int::<2>::from_i64(123);
3317 let wide: Int<4> = pos.resize_n::<4>();
3318 assert_eq!(*wide.as_limbs(), [123, 0, 0, 0]);
3319 assert_eq!(wide.resize_n::<2>(), pos);
3320
3321 let neg = Int::<2>::from_i64(-7);
3323 let wneg: Int<4> = neg.resize_n::<4>();
3324 assert_eq!(*wneg.as_limbs(), [(-7i64) as u64, u64::MAX, u64::MAX, u64::MAX]);
3325 assert_eq!(wneg, Int::<4>::from_i64(-7));
3326
3327 let v = Int::<4>::from_limbs([1, 2, 3, 4]);
3329 assert_eq!(*v.resize_n::<2>().as_limbs(), [1, 2]);
3330
3331 assert_eq!(Int::<4>::from_i64(-1).try_narrow::<2>().unwrap(), Int::<2>::from_i64(-1));
3334 assert!(Int::<4>::from_limbs([0, 0, 1, 0]).try_narrow::<2>().is_none());
3336 let too_big = Int::<2>::from_limbs([0x8000_0000_0000_0000, 0]);
3340 assert!(too_big.try_narrow::<1>().is_none());
3341 let min2 = Int::<2>::from_i64(i64::MIN);
3343 assert_eq!(min2.try_narrow::<1>().unwrap(), Int::<1>::from_i64(i64::MIN));
3344 assert_eq!(min2.resize_n::<4>().try_narrow::<2>().unwrap(), min2);
3346
3347 const W: Int<4> = Int::<2>::from_i64(-7).resize_n::<4>();
3349 assert_eq!(W, Int::<4>::from_i64(-7));
3350 }
3351
3352 #[test]
3353 fn bit_count_is_const() {
3354 const Z: u32 = Int::<2>::leading_zeros(&Int::<2>::MAX);
3360 const BL: u32 = Int::<2>::bit_length(&Int::<2>::MAX);
3361 const UZ: u32 = Uint::<2>::leading_zeros(&Uint::<2>::MAX);
3362 const UBL: u32 = Uint::<2>::bit_length(&Uint::<2>::MAX);
3363 assert_eq!(Z, 1);
3366 assert_eq!(BL, 127);
3367 assert_eq!(UZ, 0);
3369 assert_eq!(UBL, 128);
3370 }
3371
3372 #[test]
3373 fn int_cross_width_comparison() {
3374 let a = Int::<1>::from_i64(5);
3376 let b = Int::<2>::from_i64(5);
3377 assert!(a == b);
3378 assert!(b == a);
3379 assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal));
3380
3381 let small = Int::<1>::from_i64(3);
3383 let big = Int::<2>::from_i64(100);
3384 assert!(small < big);
3385 assert!(big > small);
3386
3387 let huge = Int::<2>::from_limbs([0, 64]); assert!(huge > Int::<1>::MAX);
3392 assert!(Int::<1>::from_i64(-1) < huge);
3393
3394 assert!(Int::<1>::from_i64(-1) < Int::<2>::from_i64(1));
3396 assert!(Int::<1>::from_i64(-100) < Int::<2>::from_i64(-3));
3398 assert!(Int::<2>::from_i64(-3) > Int::<1>::from_i64(-100));
3399 assert!(Int::<1>::from_i64(-7) == Int::<2>::from_i64(-7));
3401
3402 let mut v = vec![
3404 Int::<2>::from_i64(3),
3405 Int::<2>::from_i64(-10),
3406 Int::<2>::from_i64(0),
3407 Int::<2>::from_i64(7),
3408 ];
3409 v.sort();
3410 assert_eq!(
3411 v,
3412 vec![
3413 Int::<2>::from_i64(-10),
3414 Int::<2>::from_i64(0),
3415 Int::<2>::from_i64(3),
3416 Int::<2>::from_i64(7),
3417 ]
3418 );
3419 }
3420
3421 #[test]
3422 fn consts_and_round_trip() {
3423 assert_eq!(Uint::<4>::LIMBS, 4);
3424 assert_eq!(Uint::<4>::BITS, 256);
3425 assert_eq!(*Uint::<4>::ZERO.as_limbs(), [0, 0, 0, 0]);
3426 assert_eq!(*Uint::<4>::ONE.as_limbs(), [1, 0, 0, 0]);
3427 assert_eq!(*Uint::<4>::MAX.as_limbs(), [u64::MAX; 4]);
3428
3429 let v = Uint::<4>::from_limbs([7, 8, 9, 10]);
3430 assert_eq!(*v.as_limbs(), [7, 8, 9, 10]);
3431 }
3432
3433 #[test]
3434 fn widths_have_expected_bits() {
3435 assert_eq!(Int::<4>::BITS, 256);
3436 assert_eq!(Int::<64>::BITS, 4096);
3437 assert_eq!(Uint::<16>::LIMBS, 16);
3438 }
3439
3440 #[test]
3441 fn wrapping_sub_borrows_across_limbs() {
3442 let a = Uint::<4>::from_limbs([0, 1, 0, 0]);
3444 let d = a.wrapping_sub(Uint::<4>::ONE);
3445 assert_eq!(*d.as_limbs(), [u64::MAX, 0, 0, 0]);
3446
3447 let wrap = Uint::<4>::ZERO.wrapping_sub(Uint::<4>::ONE);
3449 assert_eq!(*wrap.as_limbs(), [u64::MAX; 4]);
3450 }
3451
3452 #[test]
3453 fn unsigned_ordering() {
3454 let small = Uint::<4>::from_limbs([5, 0, 0, 0]);
3455 let big = Uint::<4>::from_limbs([0, 1, 0, 0]); assert!(small < big);
3457 assert!(big > small);
3458 assert_eq!(small, small);
3459 assert!(Uint::<4>::ZERO < Uint::<4>::MAX);
3460 assert_eq!(small.max(big), big);
3462 }
3463
3464 #[test]
3465 fn wrapping_add_carries_across_limbs() {
3466 let a = Uint::<4>::from_limbs([u64::MAX, 0, 0, 0]);
3468 let sum = a.wrapping_add(Uint::<4>::ONE);
3469 assert_eq!(*sum.as_limbs(), [0, 1, 0, 0]);
3470
3471 let wrap = Uint::<4>::MAX.wrapping_add(Uint::<4>::ONE);
3473 assert_eq!(*wrap.as_limbs(), [0, 0, 0, 0]);
3474 }
3475
3476 #[test]
3477 fn uint_wrapping_mul_cross_limb_product() {
3478 let a = Uint::<4>::from_limbs([0, 1, 0, 0]);
3480 let p = a.wrapping_mul(a);
3481 assert_eq!(*p.as_limbs(), [0, 0, 1, 0]);
3482
3483 let m = Uint::<4>::from_limbs([u64::MAX, 0, 0, 0]);
3485 let three = Uint::<4>::from_limbs([3, 0, 0, 0]);
3486 let q = m.wrapping_mul(three);
3487 assert_eq!(*q.as_limbs(), [u64::MAX - 2, 2, 0, 0]);
3488
3489 let v = Uint::<4>::from_limbs([7, 8, 9, 10]);
3491 assert_eq!(v.wrapping_mul(Uint::<4>::ONE), v);
3492 }
3493
3494 #[test]
3495 fn uint_wrapping_mul_truncates_modulo_width() {
3496 let hi = Uint::<4>::from_limbs([0, 0, 0, 1]);
3498 assert_eq!(hi.wrapping_mul(hi), Uint::<4>::ZERO);
3499
3500 let r = Uint::<4>::MAX.wrapping_mul(Uint::<4>::MAX);
3504 assert_eq!(*r.as_limbs(), [1, 0, 0, 0]);
3505 }
3506
3507 #[test]
3508 fn uint_checked_add_sub_overflow() {
3509 assert_eq!(
3510 Uint::<4>::ONE.checked_add(Uint::<4>::ONE),
3511 Some(Uint::<4>::from_limbs([2, 0, 0, 0]))
3512 );
3513 assert_eq!(Uint::<4>::MAX.checked_add(Uint::<4>::ONE), None);
3515
3516 assert_eq!(
3517 Uint::<4>::from_limbs([5, 0, 0, 0]).checked_sub(Uint::<4>::from_limbs([3, 0, 0, 0])),
3518 Some(Uint::<4>::from_limbs([2, 0, 0, 0]))
3519 );
3520 assert_eq!(Uint::<4>::ZERO.checked_sub(Uint::<4>::ONE), None);
3522 }
3523
3524 #[test]
3525 fn uint_checked_mul_overflow() {
3526 let a = Uint::<4>::from_limbs([0, 1, 0, 0]);
3528 assert_eq!(a.checked_mul(a), Some(Uint::<4>::from_limbs([0, 0, 1, 0])));
3529 let hi = Uint::<4>::from_limbs([0, 0, 0, 1]);
3531 assert_eq!(hi.checked_mul(hi), None);
3532 assert_eq!(
3534 Uint::<4>::MAX.checked_mul(Uint::<4>::from_limbs([2, 0, 0, 0])),
3535 None
3536 );
3537 }
3538
3539 #[test]
3540 fn uint_div_rem_with_remainder() {
3541 let n = Uint::<4>::from_limbs([1000, 0, 0, 0]);
3543 let d = Uint::<4>::from_limbs([7, 0, 0, 0]);
3544 assert_eq!(*n.wrapping_div(d).as_limbs(), [142, 0, 0, 0]);
3545 assert_eq!(*n.wrapping_rem(d).as_limbs(), [6, 0, 0, 0]);
3546
3547 let big = Uint::<4>::from_limbs([0, 0, 1, 0]);
3549 let by = Uint::<4>::from_limbs([0, 1, 0, 0]);
3550 assert_eq!(*big.wrapping_div(by).as_limbs(), [0, 1, 0, 0]);
3551 assert!(big.wrapping_rem(by).is_zero());
3552 }
3553
3554 #[test]
3555 #[should_panic(expected = "divide by zero")]
3556 fn uint_div_by_zero_panics() {
3557 let _ = Uint::<4>::ONE.wrapping_div(Uint::<4>::ZERO);
3558 }
3559
3560 #[test]
3561 fn uint_bitwise_ops() {
3562 let a = Uint::<4>::from_limbs([0b1100, 0xFF, 0, 0]);
3563 let b = Uint::<4>::from_limbs([0b1010, 0x0F, 0, 0]);
3564 assert_eq!(*(a & b).as_limbs(), [0b1000, 0x0F, 0, 0]);
3565 assert_eq!(*(a | b).as_limbs(), [0b1110, 0xFF, 0, 0]);
3566 assert_eq!(*(a ^ b).as_limbs(), [0b0110, 0xF0, 0, 0]);
3567 assert_eq!(*(!Uint::<4>::ZERO).as_limbs(), [u64::MAX; 4]);
3568 }
3569
3570 #[test]
3571 fn uint_shifts() {
3572 let one = Uint::<4>::ONE;
3573 assert_eq!(*(one << 64).as_limbs(), [0, 1, 0, 0]);
3575 assert_eq!(*(one << 130).as_limbs(), [0, 0, 0b100, 0]);
3577 let v = Uint::<4>::from_limbs([0, 0, 0b100, 0]);
3579 assert_eq!(*(v >> 130).as_limbs(), [1, 0, 0, 0]);
3580 assert_eq!(one << 256, Uint::<4>::ZERO);
3582 }
3583
3584 #[test]
3585 fn uint_is_zero_bitlen_leading_zeros() {
3586 assert!(Uint::<4>::ZERO.is_zero());
3587 assert!(!Uint::<4>::ONE.is_zero());
3588 assert_eq!(Uint::<4>::ZERO.bit_length(), 0);
3589 assert_eq!(Uint::<4>::ONE.bit_length(), 1);
3590 let b = Uint::<4>::from_limbs([0, 1, 0, 0]);
3592 assert_eq!(b.bit_length(), 65);
3593 assert_eq!(b.leading_zeros(), 256 - 65);
3594 assert_eq!(Uint::<4>::ZERO.leading_zeros(), 256);
3595 assert_eq!(Uint::<4>::MAX.leading_zeros(), 0);
3596 }
3597
3598 #[test]
3599 fn uint_operator_traits_delegate() {
3600 let a = Uint::<4>::from_limbs([10, 0, 0, 0]);
3601 let b = Uint::<4>::from_limbs([3, 0, 0, 0]);
3602 assert_eq!(*(a + b).as_limbs(), [13, 0, 0, 0]);
3603 assert_eq!(*(a - b).as_limbs(), [7, 0, 0, 0]);
3604 assert_eq!(*(a * b).as_limbs(), [30, 0, 0, 0]);
3605 }
3606
3607 #[test]
3608 fn int_from_i64_sign_extends() {
3609 assert_eq!(*Int::<4>::from_i64(5).as_limbs(), [5, 0, 0, 0]);
3611 assert_eq!(*Int::<4>::from_i64(-1).as_limbs(), [u64::MAX; 4]);
3613 assert_eq!(
3615 *Int::<4>::from_i64(-2).as_limbs(),
3616 [u64::MAX - 1, u64::MAX, u64::MAX, u64::MAX]
3617 );
3618 assert!(Int::<4>::from_i64(-1).is_negative());
3619 assert!(Int::<4>::from_i64(1).is_positive());
3620 assert!(Int::<4>::from_i64(0).is_zero());
3621 }
3622
3623 #[test]
3624 fn int_wrapping_neg_two_complement() {
3625 let five = Int::<4>::from_i64(5);
3626 let neg_five = five.wrapping_neg();
3627 assert_eq!(neg_five, Int::<4>::from_i64(-5));
3628 assert_eq!(neg_five.wrapping_neg(), five);
3630 assert_eq!(Int::<4>::from_i64(-1).wrapping_neg(), Int::<4>::ONE);
3632 assert_eq!(-five, neg_five);
3634 }
3635
3636 #[test]
3637 fn int_add_sub_mul_with_signs() {
3638 let a = Int::<4>::from_i64(7);
3639 let b = Int::<4>::from_i64(-3);
3640 assert_eq!(a.wrapping_add(b), Int::<4>::from_i64(4));
3642 assert_eq!(a.wrapping_sub(b), Int::<4>::from_i64(10));
3644 assert_eq!(a.wrapping_mul(b), Int::<4>::from_i64(-21));
3646 assert_eq!(b.wrapping_mul(b), Int::<4>::from_i64(9));
3648 assert_eq!(a + b, Int::<4>::from_i64(4));
3650 assert_eq!(a - b, Int::<4>::from_i64(10));
3651 assert_eq!(a * b, Int::<4>::from_i64(-21));
3652 }
3653
3654 #[test]
3655 fn int_mul_crosses_limbs_with_sign() {
3656 let big = Int::<4>::from_i64(0).wrapping_add(Int::<4>::from_limbs([0, 1, 0, 0]));
3658 let neg = big.wrapping_mul(Int::<4>::from_i64(-1));
3659 assert_eq!(neg, big.wrapping_neg());
3660 assert_eq!(*neg.as_limbs(), [0, u64::MAX, u64::MAX, u64::MAX]);
3662 }
3663
3664 #[test]
3665 fn int_abs_signum() {
3666 assert_eq!(Int::<4>::from_i64(-9).abs(), Int::<4>::from_i64(9));
3667 assert_eq!(Int::<4>::from_i64(9).abs(), Int::<4>::from_i64(9));
3668 assert_eq!(Int::<4>::from_i64(-9).signum(), -1);
3669 assert_eq!(Int::<4>::from_i64(9).signum(), 1);
3670 assert_eq!(Int::<4>::from_i64(0).signum(), 0);
3671 }
3672
3673 #[test]
3674 fn int_from_i128_round_trips() {
3675 for v in [
3676 0i128,
3677 1,
3678 -1,
3679 42,
3680 -42,
3681 i64::MAX as i128,
3682 i64::MIN as i128,
3683 i128::MAX,
3684 i128::MIN,
3685 123_456_789_012_345_678,
3686 ] {
3687 let a = Int::<4>::from_i128(v);
3688 assert_eq!(a.to_i128_checked(), Some(v), "round-trip i128 {v}");
3689 let b = Int::<8>::from_i128(v);
3690 assert_eq!(b.to_i128_checked(), Some(v), "round-trip i128 {v} (N=8)");
3691 }
3692 let big = Int::<4>::from_u128(u128::MAX);
3694 assert_eq!(big.to_i128_checked(), None);
3695 assert_eq!(big.to_u128_checked(), Some(u128::MAX));
3696 assert_eq!(Int::<4>::from_i128(-1).to_u128_checked(), None);
3698 }
3699
3700 #[test]
3701 fn int_from_str_radix_and_display_round_trip() {
3702 let cases = [
3703 "0",
3704 "1",
3705 "-1",
3706 "42",
3707 "-42",
3708 "1000000000000000000000",
3709 "-340282366920938463463374607431768211455",
3710 ];
3711 for s in cases {
3712 let v = Int::<4>::from_str_radix(s, 10).unwrap();
3713 assert_eq!(format!("{v}"), s, "display round-trip {s}");
3714 let v2: Int<4> = s.parse().unwrap();
3716 assert_eq!(v, v2);
3717 }
3718 assert!(Int::<4>::from_str_radix("10", 16).is_err());
3720 assert!(Int::<4>::from_str_radix("12x", 10).is_err());
3721 assert!(Int::<4>::from_str_radix("", 10).is_err());
3722 assert!(Int::<4>::from_str_radix("-", 10).is_err());
3723 }
3724
3725 #[test]
3726 fn int_div_rem_signs_match_truncating() {
3727 let cases: [(i128, i128); 6] = [
3730 (1000, 7),
3731 (-1000, 7),
3732 (1000, -7),
3733 (-1000, -7),
3734 (7, 1000),
3735 (-7, 1000),
3736 ];
3737 for (a, b) in cases {
3738 let (q, r) = Int::<4>::from_i128(a).div_rem(Int::<4>::from_i128(b));
3739 assert_eq!(q.to_i128_checked(), Some(a / b), "quot {a}/{b}");
3740 assert_eq!(r.to_i128_checked(), Some(a % b), "rem {a}%{b}");
3741 }
3742 }
3743
3744 #[test]
3745 #[should_panic(expected = "divide by zero")]
3746 fn int_div_rem_by_zero_panics() {
3747 let _ = Int::<4>::ONE.div_rem(Int::<4>::ZERO);
3748 }
3749
3750 #[test]
3751 fn int_bit_reads_twos_complement() {
3752 let v = Int::<4>::from_i128(0b1010);
3753 assert!(!v.bit(0));
3754 assert!(v.bit(1));
3755 assert!(!v.bit(2));
3756 assert!(v.bit(3));
3757 assert!(!v.bit(200));
3759 let neg = Int::<4>::from_i128(-1);
3761 assert!(neg.bit(0));
3762 assert!(neg.bit(255));
3763 assert!(neg.bit(1000)); }
3765
3766 #[test]
3767 fn int_mul_u64_matches_wide_mul() {
3768 let v = Int::<4>::from_i128(123_456_789);
3769 assert_eq!(
3770 v.mul_u64(1000),
3771 Int::<4>::from_i128(123_456_789_000)
3772 );
3773 let n = Int::<4>::from_i128(-123_456_789);
3775 assert_eq!(
3776 n.mul_u64(1000),
3777 Int::<4>::from_i128(-123_456_789_000)
3778 );
3779 assert_eq!(v.mul_u64(0), Int::<4>::ZERO);
3781 assert_eq!(v.mul_u64(1), v);
3782 }
3783
3784 #[test]
3785 #[should_panic(expected = "mul overflow")]
3786 fn int_mul_u64_overflow_panics() {
3787 let _ = Int::<4>::max_value().mul_u64(2);
3789 }
3790
3791 #[test]
3792 fn int_div_rem_operators_match_div_rem() {
3793 let a = Int::<4>::from_i128(-1000);
3796 let b = Int::<4>::from_i128(7);
3797 assert_eq!(a / b, Int::<4>::from_i128(-1000 / 7));
3798 assert_eq!(a % b, Int::<4>::from_i128(-1000 % 7));
3799 let (q, r) = a.div_rem(b);
3800 assert_eq!(a / b, q);
3801 assert_eq!(a % b, r);
3802 }
3803
3804 #[cfg(feature = "_wide-support")]
3806 #[test]
3807 fn int_wide_storage_surface() {
3808 use crate::int::types::traits::BigInt;
3809 fn exercises<T: BigInt>() {
3810 assert!(<T as BigInt>::ZERO == <T as BigInt>::from_i128(0));
3811 assert!(<T as BigInt>::ONE == <T as BigInt>::from_i128(1));
3812 assert!(<T as BigInt>::TEN == <T as BigInt>::from_i128(10));
3813
3814 let twelve = <T as BigInt>::from_i128(12);
3815 let three = <T as BigInt>::from_i128(3);
3816 assert!(three.pow(3) == <T as BigInt>::from_i128(27));
3818 assert!(<T as BigInt>::from_i128(144).isqrt() == <T as BigInt>::from_i128(12));
3819 let (q, r) = twelve.div_rem(<T as BigInt>::from_i128(5));
3821 assert!(q == <T as BigInt>::from_i128(2));
3822 assert!(r == <T as BigInt>::from_i128(2));
3823 assert!(twelve.bit(2) && twelve.bit(3) && !twelve.bit(0));
3825 assert!(<T as BigInt>::ONE.leading_zeros() == <T as BigInt>::BITS - 1);
3826 assert!(twelve.mul_u64(10) == <T as BigInt>::from_i128(120));
3828 assert!(twelve.to_f64() == 12.0);
3829 assert!(<T as BigInt>::from_f64_val(7.9) == <T as BigInt>::from_i128(7));
3830 }
3831 exercises::<Int<4>>();
3832 exercises::<Int<8>>();
3833
3834 let v = Int::<4>::from_i128(-123_456_789);
3836 let w: Int<8> = BigInt::resize_to(v);
3837 assert_eq!(w.to_i128_checked(), Some(-123_456_789));
3838 let back: Int<4> = BigInt::resize_to(w);
3839 assert_eq!(back, v);
3840 }
3841
3842 #[cfg(feature = "_wide-support")]
3844 #[test]
3845 fn int_isqrt_matches_uint_magnitude() {
3846 use crate::int::types::traits::BigInt;
3847 let n = Int::<4>::from_i128(1_000_000_000_000);
3849 let r = BigInt::isqrt(n);
3850 assert_eq!(r, Int::<4>::from_i128(1_000_000));
3851 let big = Int::<8>::from_i128(987_654_321);
3853 let sq = big.checked_mul(big).unwrap();
3854 assert_eq!(BigInt::isqrt(sq), big);
3855 }
3856
3857 #[test]
3860 fn uint_sqr_policy_matches_wrapping_sqr() {
3861 fn check<const N: usize>(limbs: [u64; N]) {
3862 let value = Uint::<N>::from_limbs(limbs);
3863 assert_eq!(value.sqr(), value.wrapping_sqr(), "sqr mismatch at {limbs:?}");
3864 assert_eq!(value.sqr(), value.wrapping_mul(value), "sqr != x*x at {limbs:?}");
3865 }
3866 check::<1>([0]);
3868 check::<1>([1]);
3869 check::<1>([u64::MAX]);
3870 check::<1>([12345]);
3871 check::<2>([0, 0]);
3873 check::<2>([1, 0]);
3874 check::<2>([u64::MAX, u64::MAX]);
3875 check::<2>([0xDEAD_BEEF, 0x1234]);
3876 check::<4>([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
3878 check::<4>([0x1234_5678_9ABC_DEF0, 0xFEDC_BA98, 0, 0]);
3879 check::<6>([7, 8, 9, 10, 11, 12]);
3881 }
3882
3883 #[test]
3885 fn uint_cube_policy_matches_wrapping_cube() {
3886 fn check<const N: usize>(limbs: [u64; N]) {
3887 let value = Uint::<N>::from_limbs(limbs);
3888 assert_eq!(value.cube(), value.wrapping_cube(), "cube mismatch at {limbs:?}");
3889 assert_eq!(
3890 value.cube(),
3891 value.wrapping_mul(value).wrapping_mul(value),
3892 "cube != x*x*x at {limbs:?}"
3893 );
3894 }
3895 check::<1>([0]);
3896 check::<1>([1]);
3897 check::<1>([3]);
3898 check::<1>([u64::MAX]);
3899 check::<2>([0, 0]);
3900 check::<2>([1, 0]);
3901 check::<2>([100, 0]);
3902 check::<2>([u64::MAX, u64::MAX]);
3903 check::<4>([5, 0, 0, 0]);
3904 check::<4>([0x1234, 0x5678, 0, 0]);
3905 }
3906
3907 #[test]
3909 fn int_sqr_cube_match_wrapping() {
3910 fn check<const N: usize>(value: i128) {
3911 let int = Int::<N>::from_i128(value);
3912 assert_eq!(int.sqr(), int.wrapping_sqr(), "int sqr mismatch v={value}");
3913 assert_eq!(int.cube(), int.wrapping_cube(), "int cube mismatch v={value}");
3914 }
3915 for value in [0i128, 1, -1, 12, -12, 100, -100, 1_000_000, -1_000_000] {
3916 check::<4>(value);
3917 check::<8>(value);
3918 }
3919 }
3920
3921 #[test]
3924 fn uint_icbrt_floor_correctness() {
3925 fn brute_cbrt(value: u64) -> u64 {
3927 if value == 0 {
3928 return 0;
3929 }
3930 let mut root: u64 = 0;
3931 while (root + 1).checked_mul((root + 1) * (root + 1) + root + 1)
3932 .is_some_and(|power| power <= value)
3933 || (root + 1).checked_pow(3).is_some_and(|power| power <= value)
3934 {
3935 root += 1;
3936 }
3937 root
3938 }
3939
3940 fn check<const N: usize>(value: u64) {
3941 let uint = Uint::<N>::from_u64(value);
3942 let root = uint.icbrt();
3943 let root_u64 = root.as_limbs()[0];
3944 let expected = brute_cbrt(value);
3945 assert_eq!(root_u64, expected, "icbrt({value}) = {root_u64}, expected {expected}");
3946 for i in 1..N {
3948 assert_eq!(root.as_limbs()[i], 0, "icbrt({value}) high limb {i} nonzero");
3949 }
3950 }
3951
3952 for value in [0u64, 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000,
3954 1_000_000_000u64, 8_000_000_000u64] {
3955 check::<1>(value);
3956 check::<2>(value);
3957 check::<4>(value);
3958 }
3959
3960 for value in [2u64, 3, 4, 5, 6, 7, 9, 10, 26, 28, 63, 65, 999,
3962 1_000_000_001u64] {
3963 check::<1>(value);
3964 check::<2>(value);
3965 check::<4>(value);
3966 }
3967
3968 check::<1>(0);
3970 check::<1>(1);
3971 check::<4>(0);
3972 check::<4>(1);
3973
3974 for value in [u64::MAX, u64::MAX - 1, u64::MAX - 100, 1 << 60, 1 << 48] {
3976 check::<2>(value);
3977 check::<4>(value);
3978 }
3979 }
3980
3981 #[test]
3985 fn uint_icbrt_wide_floor_identity() {
3986 fn check_wide<const N: usize>(limbs: [u64; N]) {
3987 let value = Uint::<N>::from_limbs(limbs);
3988 let root = value.icbrt();
3989 let root_cubed = root.wrapping_pow(3);
3991 assert!(
3992 root_cubed <= value,
3993 "icbrt violated: r³ > x for {limbs:?}"
3994 );
3995 let next_root = root.wrapping_add(Uint::<N>::ONE);
3997 let next_root_cubed = next_root.wrapping_pow(3);
3998 assert!(
4001 next_root_cubed > value || next_root == Uint::<N>::ZERO,
4002 "icbrt not floor: (r+1)³ <= x for {limbs:?}"
4003 );
4004 }
4005
4006 let base = 1_000_000u64;
4010 let base_cubed = base * base * base; check_wide::<4>([base_cubed, 0, 0, 0]);
4012 check_wide::<4>([base_cubed + 1, 0, 0, 0]);
4013 check_wide::<4>([base_cubed - 1, 0, 0, 0]);
4014
4015 let hi = 1u64;
4017 let lo = 0u64;
4018 check_wide::<4>([lo, hi, 0, 0]); check_wide::<4>([u64::MAX, u64::MAX, 0, 0]); check_wide::<6>([base_cubed, 0, 0, 0, 0, 0]);
4024 check_wide::<6>([u64::MAX, u64::MAX, u64::MAX, 0, 0, 0]); }
4026
4027 #[test]
4029 fn int_icbrt_magnitude() {
4030 for v in [0i128, 1, -1, 8, -8, 27, -27, 1000, -1000] {
4031 let x = Int::<4>::from_i128(v);
4032 let expected = Int::<4>::from_i128((v.unsigned_abs() as f64).cbrt() as i128);
4033 let got = x.icbrt();
4034 assert_eq!(got, expected, "int icbrt({v}) mismatch");
4035 }
4036 }
4037
4038 #[test]
4039 fn int_wideint_mag_sign_round_trips() {
4040 use crate::int::types::traits::BigInt;
4041 for v in [0i128, 1, -1, 123_456_789_012_345_678, -987_654_321] {
4044 let a = Int::<4>::from_i128(v);
4045 let mut mag = [0u128; 2];
4046 let neg = a.mag_into_u128(&mut mag);
4047 assert_eq!(neg, a.is_negative());
4048 assert_eq!(Int::<4>::from_mag_sign_u128(&mag, neg), a, "mag/sign {v}");
4049 }
4050 assert_eq!(<Int<4> as BigInt>::U128_LIMBS, 2);
4052 assert_eq!(<Int<3> as BigInt>::U128_LIMBS, 2);
4053 assert_eq!(<Int<8> as BigInt>::U128_LIMBS, 4);
4054
4055 let v3 = Int::<3>::from_i128(-170_141_183_460_469_231_731);
4058 let mut buf = [0u128; 2];
4059 let neg = v3.mag_into_u128(&mut buf);
4060 assert_eq!(Int::<3>::from_mag_sign_u128(&buf, neg), v3);
4061
4062 let v4 = Int::<4>::from_i128(i128::MIN);
4063 let mut buf4 = [0u128; 2];
4064 let neg4 = v4.mag_into_u128(&mut buf4);
4065 assert_eq!(Int::<4>::from_mag_sign_u128(&buf4, neg4), v4);
4066 }
4067
4068 #[test]
4069 fn int_to_from_f64_and_negate_ten() {
4070 assert_eq!(Int::<4>::from_i64(5).to_f64(), 5.0);
4071 assert_eq!(Int::<4>::from_i64(-5).to_f64(), -5.0);
4072 assert_eq!(Int::<4>::from_f64(42.9), Int::<4>::from_i64(42));
4073 assert_eq!(Int::<4>::from_f64(-42.9), Int::<4>::from_i64(-42));
4074 assert_eq!(Int::<4>::from_f64(f64::NAN), Int::<4>::ZERO);
4076 assert_eq!(Int::<4>::from_i64(5).negate(), Int::<4>::from_i64(-5));
4078 assert_eq!(Int::<4>::TEN, Int::<4>::from_i64(10));
4079 let v = Int::<4>::from_i128(-9_876_543_210);
4081 assert_eq!(Int::<4>::from_limbs_le(v.limbs_le()), v);
4082 }
4083
4084 #[test]
4085 fn int_signed_ordering() {
4086 let neg = Int::<4>::from_i64(-5);
4087 let zero = Int::<4>::ZERO;
4088 let pos = Int::<4>::from_i64(5);
4089 assert!(neg < zero);
4092 assert!(zero < pos);
4093 assert!(neg < pos);
4094 assert!(Int::<4>::from_i64(-10) < Int::<4>::from_i64(-1));
4096 assert_eq!(neg.max(pos), pos);
4097 assert_eq!(neg.min(pos), neg);
4098 assert_eq!(pos.cmp(&pos), Ordering::Equal);
4099 }
4100}
4101
4102#[cfg(all(test, feature = "wide"))]
4111mod unified_mg_feasibility {
4112 use super::Int;
4113 use crate::algos::support::mg_divide::div_wide_pow10;
4114 use crate::int::types::compute_limbs::{ComputeLimbs, Limbs};
4115 use crate::int::types::traits::BigInt;
4116 use crate::support::rounding::RoundingMode;
4117
4118 fn scaled<const N: usize, const M: usize>(lhs: Int<N>, rhs: Int<N>, scale: u32) -> Int<M>
4126 where
4127 Limbs<N>: ComputeLimbs,
4128 Int<M>: BigInt,
4129 Limbs<M>: ComputeLimbs,
4130 <Int<M> as BigInt>::Scratch: ComputeLimbs,
4131 {
4132 let prod: Int<M> = lhs.widen_mul::<Int<M>>(rhs);
4133 div_wide_pow10::<Int<M>>(prod, scale, RoundingMode::HalfToEven)
4134 }
4135
4136 #[test]
4138 fn n2_widen4_scale5() {
4139 let a = Int::<2>::from_i64(123456789);
4140 let b = Int::<2>::from_i64(987654321);
4141 let got = scaled::<2, 4>(a, b, 5);
4142 assert_eq!(got, Int::<4>::from_i64(1219326311126));
4143 }
4144
4145 #[test]
4147 fn n1_widen2_scale3() {
4148 let a = Int::<1>::from_i64(123456);
4149 let b = Int::<1>::from_i64(654321);
4150 let got = scaled::<1, 2>(a, b, 3);
4151 assert_eq!(got, Int::<2>::from_i64(80779853));
4152 }
4153
4154 #[test]
4158 fn round_trip_mul_then_div() {
4159 let x1 = 4242i64;
4161 let ten_pow_4 = Int::<1>::from_i64(10_000);
4162 let rt1 = scaled::<1, 2>(Int::<1>::from_i64(x1), ten_pow_4, 4);
4163 assert_eq!(rt1, Int::<2>::from_i64(x1));
4164
4165 let x2 = 9_876_543_210i64;
4167 let ten_pow_7 = Int::<2>::from_i64(10_000_000);
4168 let rt2 = scaled::<2, 4>(Int::<2>::from_i64(x2), ten_pow_7, 7);
4169 assert_eq!(rt2, Int::<4>::from_i64(x2));
4170 }
4171
4172 #[test]
4177 fn scale_zero_is_widen_mul_identity() {
4178 let a1 = Int::<1>::from_i64(123456);
4180 let b1 = Int::<1>::from_i64(654321);
4181 let prod1: Int<2> = a1.widen_mul::<Int<2>>(b1);
4182 assert_eq!(prod1, Int::<2>::from_i64(123456 * 654321));
4183
4184 let a2 = Int::<2>::from_i64(123456789);
4186 let b2 = Int::<2>::from_i64(987654321);
4187 let prod2: Int<4> = a2.widen_mul::<Int<4>>(b2);
4188 assert_eq!(prod2, Int::<4>::from_i64(123456789i64 * 987654321i64));
4189 }
4190
4191 #[test]
4194 fn max_operand_each_width() {
4195 let a1 = Int::<1>::from_i64(i64::MAX);
4199 let b1 = Int::<1>::from_i64(i64::MAX);
4200 let got1 = scaled::<1, 2>(a1, b1, 9);
4201 let exact1 = (i64::MAX as i128) * (i64::MAX as i128);
4202 let pow9 = 1_000_000_000i128;
4203 let q1 = exact1 / pow9;
4204 let r1 = exact1 % pow9;
4205 let half = pow9 / 2;
4207 let expect1 = if r1 > half || (r1 == half && (q1 & 1) == 1) {
4208 q1 + 1
4209 } else {
4210 q1
4211 };
4212 assert_eq!(got1, Int::<2>::from_i128(expect1));
4213
4214 let big = Int::<2>::MAX; let got2 = scaled::<2, 4>(big, big, 20);
4219 let prod2: Int<4> = big.widen_mul::<Int<4>>(big);
4220 let pow20 = Int::<4>::TEN.pow(20);
4223 let (q2, r2) = prod2.div_rem(pow20);
4224 let half20 = pow20.div_rem(Int::<4>::from_i64(2)).0;
4225 let expect2 = match r2.cmp(&half20) {
4226 core::cmp::Ordering::Greater => q2.wrapping_add(Int::<4>::ONE),
4227 core::cmp::Ordering::Equal => {
4228 if (q2.as_limbs()[0] & 1) == 1 {
4229 q2.wrapping_add(Int::<4>::ONE)
4230 } else {
4231 q2
4232 }
4233 }
4234 core::cmp::Ordering::Less => q2,
4235 };
4236 assert_eq!(got2, expect2);
4237 }
4238}
4239
4240#[cfg(test)]
4241mod bit_count_contract_tests {
4242 use super::{Int, Uint};
4243
4244 #[test]
4249 fn int_bit_counts_match_signed_contract_at_edges() {
4250 for v in [0_i64, 1, -1, i64::MAX, i64::MIN, 42, -42, 1 << 40, -(1 << 40)] {
4252 let x = Int::<1>::from_i64(v);
4253 assert_eq!(x.leading_zeros(), v.leading_zeros(), "i64 lz {v}");
4254 assert_eq!(x.trailing_zeros(), v.trailing_zeros(), "i64 tz {v}");
4255 assert_eq!(x.count_ones(), v.count_ones(), "i64 popcount {v}");
4256 assert_eq!(x.count_zeros(), v.count_zeros(), "i64 cz {v}");
4257 let mag_bits = 64 - v.unsigned_abs().leading_zeros();
4259 assert_eq!(x.bit_length(), mag_bits, "i64 bit_length {v}");
4260 }
4261
4262 for v in [
4264 0_i128,
4265 1,
4266 -1,
4267 i128::MAX,
4268 i128::MIN,
4269 (1_i128 << 64), (1_i128 << 64) - 1, -(1_i128 << 64),
4272 i64::MAX as i128,
4273 i64::MIN as i128,
4274 ] {
4275 let x = Int::<2>::from_i128(v);
4276 assert_eq!(x.leading_zeros(), v.leading_zeros(), "i128 lz {v}");
4277 assert_eq!(x.trailing_zeros(), v.trailing_zeros(), "i128 tz {v}");
4278 assert_eq!(x.count_ones(), v.count_ones(), "i128 popcount {v}");
4279 assert_eq!(x.count_zeros(), v.count_zeros(), "i128 cz {v}");
4280 let mag_bits = 128 - v.unsigned_abs().leading_zeros();
4281 assert_eq!(x.bit_length(), mag_bits, "i128 bit_length {v}");
4282 }
4283
4284 const B: u32 = Int::<4>::BITS; let z = Int::<4>::ZERO;
4291 assert_eq!(z.leading_zeros(), B);
4292 assert_eq!(z.trailing_zeros(), B);
4293 assert_eq!(z.count_ones(), 0);
4294 assert_eq!(z.count_zeros(), B);
4295 assert_eq!(z.bit_length(), 0);
4296
4297 let one = Int::<4>::ONE;
4299 assert_eq!(one.leading_zeros(), B - 1);
4300 assert_eq!(one.trailing_zeros(), 0);
4301 assert_eq!(one.count_ones(), 1);
4302 assert_eq!(one.count_zeros(), B - 1);
4303 assert_eq!(one.bit_length(), 1);
4304
4305 let neg_one = Int::<4>::from_i64(-1);
4309 assert_eq!(*neg_one.as_limbs(), [u64::MAX; 4]);
4310 assert_eq!(neg_one.leading_zeros(), 0);
4311 assert_eq!(neg_one.trailing_zeros(), 0);
4312 assert_eq!(neg_one.count_ones(), B);
4313 assert_eq!(neg_one.count_zeros(), 0);
4314 assert_eq!(neg_one.bit_length(), 1);
4315
4316 let max = Int::<4>::MAX;
4318 assert_eq!(max.leading_zeros(), 1);
4319 assert_eq!(max.trailing_zeros(), 0);
4320 assert_eq!(max.count_ones(), B - 1);
4321 assert_eq!(max.count_zeros(), 1);
4322 assert_eq!(max.bit_length(), B - 1); let min = Int::<4>::MIN;
4328 assert_eq!(min.leading_zeros(), 0);
4329 assert_eq!(min.trailing_zeros(), B - 1);
4330 assert_eq!(min.count_ones(), 1);
4331 assert_eq!(min.count_zeros(), B - 1);
4332 assert_eq!(min.bit_length(), B); let two_64 = Int::<4>::from_u128(1u128 << 64);
4336 assert_eq!(two_64.trailing_zeros(), 64);
4337 assert_eq!(two_64.count_ones(), 1);
4338 assert_eq!(two_64.leading_zeros(), B - 65);
4339 assert_eq!(two_64.bit_length(), 65);
4340
4341 let two_64_m1 = Int::<4>::from_u128((1u128 << 64) - 1);
4342 assert_eq!(two_64_m1.trailing_zeros(), 0);
4343 assert_eq!(two_64_m1.count_ones(), 64);
4344 assert_eq!(two_64_m1.leading_zeros(), B - 64);
4345 assert_eq!(two_64_m1.bit_length(), 64);
4346 }
4347
4348 #[test]
4351 fn uint_bit_counts_match_unsigned_contract_at_edges() {
4352 for v in [0_u64, 1, u64::MAX, 42, 1 << 40] {
4354 let x = Uint::<1>::from_u64(v);
4355 assert_eq!(x.leading_zeros(), v.leading_zeros(), "u64 lz {v}");
4356 assert_eq!(x.count_ones(), v.count_ones(), "u64 popcount {v}");
4357 assert_eq!(x.bit_length(), 64 - v.leading_zeros(), "u64 bit_length {v}");
4359 }
4360
4361 for v in [0_u128, 1, u128::MAX, 1u128 << 64, (1u128 << 64) - 1] {
4364 let x = Uint::<2>::from_u128(v);
4365 assert_eq!(x.leading_zeros(), v.leading_zeros(), "u128 lz {v}");
4366 assert_eq!(x.count_ones(), v.count_ones(), "u128 popcount {v}");
4367 assert_eq!(x.bit_length(), 128 - v.leading_zeros(), "u128 bit_length {v}");
4368 }
4369
4370 const B: u32 = Uint::<4>::BITS; let zero = Uint::<4>::ZERO;
4373 assert_eq!(zero.leading_zeros(), B);
4374 assert_eq!(zero.count_ones(), 0);
4375 assert_eq!(zero.bit_length(), 0);
4376
4377 let umax = Uint::<4>::from_limbs([u64::MAX; 4]);
4379 assert_eq!(umax.leading_zeros(), 0);
4380 assert_eq!(umax.count_ones(), B);
4381 assert_eq!(umax.bit_length(), B);
4382
4383 let two_64 = Uint::<4>::from_u128(1u128 << 64);
4385 assert_eq!(two_64.count_ones(), 1);
4386 assert_eq!(two_64.leading_zeros(), B - 65);
4387 assert_eq!(two_64.bit_length(), 65);
4388 }
4389}
4390
4391#[cfg(test)]
4396mod hint_tests {
4397 use super::{Int, Uint};
4398
4399 #[test]
4400 fn signed_add_sub_neg() {
4401 let a = Int::<4>::from_i128(5);
4402 let b = Int::<4>::from_i128(3);
4403 assert_eq!(a.wrapping_add(b), Int::<4>::from_i128(8));
4404 assert_eq!(a.wrapping_sub(b), Int::<4>::from_i128(2));
4405 assert_eq!(b.wrapping_sub(a), Int::<4>::from_i128(-2));
4406 assert_eq!(a.negate(), Int::<4>::from_i128(-5));
4407 assert_eq!(Int::<4>::ZERO.negate(), Int::<4>::ZERO);
4408 }
4409
4410 #[test]
4411 fn signed_mul_div_rem() {
4412 let six = Int::<8>::from_i128(6);
4413 let two = Int::<8>::from_i128(2);
4414 let three = Int::<8>::from_i128(3);
4415 assert_eq!(six.wrapping_mul(three), Int::<8>::from_i128(18));
4416 assert_eq!(six.wrapping_div(two), three);
4417 assert_eq!(
4418 Int::<8>::from_i128(7).wrapping_rem(three),
4419 Int::<8>::from_i128(1)
4420 );
4421 assert_eq!(
4422 Int::<8>::from_i128(-7).wrapping_rem(three),
4423 Int::<8>::from_i128(-1)
4424 );
4425 assert_eq!(six.negate().wrapping_mul(three), Int::<8>::from_i128(-18));
4426 }
4427
4428 #[test]
4429 fn checked_overflow() {
4430 assert_eq!(Int::<4>::MAX.checked_add(Int::<4>::ONE), None);
4431 assert_eq!(Int::<4>::MIN.checked_sub(Int::<4>::ONE), None);
4432 assert_eq!(Int::<4>::MIN.checked_neg(), None);
4433 assert_eq!(
4434 Int::<4>::from_i128(2).checked_add(Int::<4>::from_i128(3)),
4435 Some(Int::<4>::from_i128(5))
4436 );
4437 }
4438
4439 #[test]
4440 fn from_str_and_pow() {
4441 let ten = Int::<16>::from_str_radix("10", 10).unwrap();
4442 assert_eq!(ten, Int::<16>::from_i128(10));
4443 assert_eq!(ten.pow(3), Int::<16>::from_i128(1000));
4444 let big = Int::<16>::from_str_radix("10", 10).unwrap().pow(40);
4445 let from_str =
4446 Int::<16>::from_str_radix("10000000000000000000000000000000000000000", 10).unwrap();
4447 assert_eq!(big, from_str);
4448 assert_eq!(
4449 Int::<4>::from_str_radix("-42", 10).unwrap(),
4450 Int::<4>::from_i128(-42)
4451 );
4452 }
4453
4454 #[test]
4455 fn ordering_and_resize() {
4456 assert!(Int::<4>::from_i128(-1) < Int::<4>::ZERO);
4457 assert!(Int::<4>::MIN < Int::<4>::MAX);
4458 let v = Int::<4>::from_i128(-123_456_789);
4459 let wide: Int<16> = v.resize();
4460 let back: Int<4> = wide.resize();
4461 assert_eq!(back, v);
4462 assert_eq!(wide, Int::<16>::from_i128(-123_456_789));
4463 }
4464
4465 #[cfg(feature = "_wide-support")]
4467 #[test]
4468 fn isqrt_and_f64() {
4469 assert_eq!(Int::<8>::from_i128(144).isqrt(), Int::<8>::from_i128(12));
4470 assert_eq!(Int::<4>::from_i128(1_000_000).as_f64(), 1_000_000.0);
4471 assert_eq!(Int::<4>::from_f64(-2_500.0), Int::<4>::from_i128(-2500));
4472 }
4473
4474 #[test]
4477 fn uint256_is_zero_and_bit_helpers() {
4478 let zero = Uint::<4>::ZERO;
4479 let one = Uint::<4>::from_str_radix("1", 10).unwrap();
4480 let two = Uint::<4>::from_str_radix("2", 10).unwrap();
4481 assert!(zero.is_zero());
4482 assert!(!one.is_zero());
4483 assert!(one.is_power_of_two());
4484 assert!(two.is_power_of_two());
4485 let three = Uint::<4>::from_str_radix("3", 10).unwrap();
4486 assert!(!three.is_power_of_two());
4487 assert_eq!(zero.next_power_of_two(), one);
4488 assert_eq!(one.next_power_of_two(), one);
4489 let four = Uint::<4>::from_str_radix("4", 10).unwrap();
4490 assert_eq!(three.next_power_of_two(), four);
4491 assert_eq!(zero.count_ones(), 0);
4492 assert_eq!(one.count_ones(), 1);
4493 assert_eq!(zero.leading_zeros(), Uint::<4>::BITS);
4494 assert_eq!(one.leading_zeros(), Uint::<4>::BITS - 1);
4495 }
4496
4497 #[test]
4498 fn uint256_parse_arithmetic_and_pow() {
4499 assert!(Uint::<4>::from_str_radix("10", 2).is_err());
4500 assert!(Uint::<4>::from_str_radix("1a", 10).is_err());
4501 let two = Uint::<4>::from_str_radix("2", 10).unwrap();
4502 let three = Uint::<4>::from_str_radix("3", 10).unwrap();
4503 let six = Uint::<4>::from_str_radix("6", 10).unwrap();
4504 let seven = Uint::<4>::from_str_radix("7", 10).unwrap();
4505 assert_eq!(three - two, Uint::<4>::from_str_radix("1", 10).unwrap());
4506 assert_eq!(six / two, three);
4507 assert_eq!(seven % three, Uint::<4>::from_str_radix("1", 10).unwrap());
4508 let five = Uint::<4>::from_str_radix("5", 10).unwrap();
4509 let four = Uint::<4>::from_str_radix("4", 10).unwrap();
4510 let one = Uint::<4>::from_str_radix("1", 10).unwrap();
4511 assert_eq!(five & four, four);
4512 assert_eq!(five | one, five);
4513 assert_eq!(five ^ four, one);
4514 let p10 = two.pow(10);
4515 assert_eq!(p10, Uint::<4>::from_str_radix("1024", 10).unwrap());
4516 let signed = three.cast_signed();
4517 assert_eq!(signed, Int::<4>::from_i128(3));
4518 }
4519
4520 #[test]
4522 fn signed_bit_and_trailing_zeros() {
4523 let v = Int::<4>::from_i128(0b1100);
4524 assert!(v.bit(2));
4525 assert!(v.bit(3));
4526 assert!(!v.bit(0));
4527 assert!(!v.bit(1));
4528 assert!(!v.bit(1000));
4529 let n = Int::<4>::from_i128(-1);
4530 assert!(n.bit(1000));
4531 assert_eq!(Int::<4>::from_i128(8).trailing_zeros(), 3);
4532 assert_eq!(Int::<4>::ZERO.trailing_zeros(), Int::<4>::BITS);
4533 }
4534
4535 #[test]
4537 fn as_u128_returns_low_magnitude_bits() {
4538 let src = Int::<4>::from_i128(123_456_789);
4539 let dst: u128 = src.as_u128();
4540 assert_eq!(dst, 123_456_789);
4541 let dst: u128 = Int::<4>::ZERO.as_u128();
4542 assert_eq!(dst, 0);
4543 }
4544}