fixed_bigint/heapless/
num_integer_impl.rs1use super::HeaplessBigInt;
9use crate::MachineWord;
10use const_num_traits::{CarryingMul, Nct, One, PrimBits, Zero};
11
12impl<T, const CAP: usize> num_integer::Integer for HeaplessBigInt<T, CAP, Nct>
13where
14 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
15{
16 fn div_floor(&self, other: &Self) -> Self {
17 *self / *other
18 }
19
20 fn mod_floor(&self, other: &Self) -> Self {
21 *self % *other
22 }
23
24 fn gcd(&self, other: &Self) -> Self {
25 let width = core::cmp::max(self.len(), other.len());
31 let mut m = *self;
32 let mut n = *other;
33 let zero = <Self as Zero>::zero();
34 if m == zero || n == zero {
35 return m | n; }
37
38 let shift = PrimBits::trailing_zeros(m | n);
40 m = m >> (PrimBits::trailing_zeros(m) as usize);
41 n = n >> (PrimBits::trailing_zeros(n) as usize);
42
43 while m != n {
44 if m > n {
45 m -= n;
46 m = m >> (PrimBits::trailing_zeros(m) as usize);
47 } else {
48 n -= m;
49 n = n >> (PrimBits::trailing_zeros(n) as usize);
50 }
51 }
52 m.widened(width) << (shift as usize)
53 }
54
55 fn lcm(&self, other: &Self) -> Self {
56 if <Self as Zero>::is_zero(self) && <Self as Zero>::is_zero(other) {
57 return <Self as Zero>::zero().widened(core::cmp::max(self.len(), other.len()));
59 }
60 let gcd = self.gcd(other);
61 *self * (*other / gcd)
62 }
63
64 fn is_multiple_of(&self, other: &Self) -> bool {
65 if <Self as Zero>::is_zero(other) {
68 return <Self as Zero>::is_zero(self);
69 }
70 *self % *other == <Self as Zero>::zero()
71 }
72
73 fn is_even(&self) -> bool {
74 self.len == 0 || self.limbs[0] & <T as One>::one() == <T as Zero>::zero()
77 }
78
79 fn is_odd(&self) -> bool {
80 !self.is_even()
81 }
82
83 fn div_rem(&self, other: &Self) -> (Self, Self) {
84 self.div_rem(other)
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use num_integer::Integer;
94
95 type H = HeaplessBigInt<u32, 8, Nct>; #[test]
98 fn gcd_preserves_operand_width() {
99 let a = H::from_le_bytes(&12u64.to_le_bytes()); let b = H::from_le_bytes(&18u64.to_le_bytes()); let g = a.gcd(&b);
105 assert_eq!(g.len(), 2, "gcd resolves at the operand width");
106 assert_eq!(g.limbs[0], 6);
107 assert_eq!(g.limbs[1], 0);
108 }
109
110 #[test]
111 fn gcd_lcm_multi_limb() {
112 let a = H::from_le_bytes(&0x1_0000_0000u64.to_le_bytes()); let b = H::from_le_bytes(&0x1_8000_0000u64.to_le_bytes()); assert_eq!(a.gcd(&b), H::from_le_bytes(&0x8000_0000u64.to_le_bytes())); assert_eq!(a.lcm(&b), H::from_le_bytes(&0x3_0000_0000u64.to_le_bytes()));
118 }
119
120 #[test]
121 fn is_multiple_of_zero_divisor_no_panic() {
122 let zero = H::from_le_bytes(&0u32.to_le_bytes());
124 let five = H::from_le_bytes(&5u32.to_le_bytes());
125 assert!(zero.is_multiple_of(&zero)); assert!(!five.is_multiple_of(&zero)); }
128
129 #[test]
130 fn lcm_of_zeros_keeps_operand_width() {
131 let z = H::from_le_bytes(&0u64.to_le_bytes()); assert_eq!(z.len(), 2);
134 assert_eq!(z.lcm(&z).len(), 2);
135 }
136}