hmath/ubigint/arith/
mul.rs1use crate::UBigInt;
2use crate::utils::{v64_to_v32, remove_suffix_0};
3
4const KARATSUBA_THRES: usize = 64;
5
6#[cfg(test)]
7const KARATSUBA_TEST: bool = crate::consts::RUN_ALL_TESTS & true;
8
9#[cfg(test)]
10static mut KARATSUBA_ENABLE: bool = true;
11
12impl UBigInt {
13
14 #[must_use = "method returns a new number and does not mutate the original value"]
15 pub fn mul_ubi(&self, other: &UBigInt) -> Self {
16
17 #[cfg(test)]
18 let go_kara = unsafe { KARATSUBA_ENABLE };
19 #[cfg(not(test))]
20 let go_kara = true;
21
22 if self.len() > KARATSUBA_THRES && other.len() > KARATSUBA_THRES && go_kara {
24
25 let m = (self.len() / 2).min(other.len() / 2);
29 let x1 = self.shift_right(m); let x0 = self.slice_right(m); let y1 = other.shift_right(m); let y0 = other.slice_right(m); let z2 = x1.mul_ubi(&y1); let z0 = x0.mul_ubi(&y0); let z1 = x1.add_ubi(&x0).mul_ubi(&y1.add_ubi(&y0)).sub_ubi(&z2).sub_ubi(&z0); let result = z2.shift_left(2 * m).add_ubi(&z1.shift_left(m)).add_ubi(&z0);
40
41 #[cfg(test)] unsafe {
42
43 if KARATSUBA_TEST {
44 KARATSUBA_ENABLE = false;
45 let result2 = self.mul_ubi(&other);
46 KARATSUBA_ENABLE = true;
47
48 assert_eq!(result, result2);
49 }
50
51 }
52
53 return result;
54 }
55
56 let mut result = vec![0; self.len() + other.len()];
57
58 for i in 0..self.len() {
59
60 for j in 0..other.len() {
61 let curr = self.0[i] as u64 * other.0[j] as u64;
62 result[i + j] += curr % (1 << 32);
63 result[i + j + 1] += curr >> 32;
64 }
65
66 }
67
68 let mut result = v64_to_v32(result);
69 remove_suffix_0(&mut result);
70
71 let result = UBigInt::from_raw(result);
72
73 #[cfg(test)] assert!(result.is_valid());
74
75 result
76 }
77
78 pub fn mul_ubi_mut(&mut self, other: &UBigInt) {
79 let result = self.mul_ubi(other);
80 *self = result;
81 }
82
83 #[must_use = "method returns a new number and does not mutate the original value"]
84 pub fn mul_u32(&self, other: u32) -> Self {
85 let mut result = self.clone();
86 result.mul_u32_mut(other);
87
88 #[cfg(test)] {
89 let t = self.mul_ubi(&UBigInt::from_u32(other));
90 assert_eq!(t, result);
91 assert!(result.is_valid());
92 }
93
94 result
95 }
96
97 pub fn mul_u32_mut(&mut self, other: u32) {
98 let mut carry = 0;
99
100 for i in 0..self.len() {
101
102 match self.0[i].checked_mul(other) {
103 Some(n) => match n.checked_add(carry as u32) {
104 Some(n) => {
105 self.0[i] = n;
106 carry = 0;
107 }
108 _ => {
109 self.0[i] = ((n as u64 + carry) % (1 << 32)) as u32;
110 carry = (n as u64 + carry) >> 32;
111 }
112 }
113 _ => {
114 let curr = self.0[i] as u64 * other as u64 + carry;
115 carry = curr >> 32;
116 self.0[i] = (curr % (1 << 32)) as u32;
117 }
118 }
119
120 }
121
122 if carry > 0 {
123 self.0.push(carry as u32);
124 }
125
126 remove_suffix_0(&mut self.0);
127 #[cfg(test)] assert!(self.is_valid());
128 }
129
130 #[must_use = "method returns a new number and does not mutate the original value"]
133 pub fn mul_pow2(&self, exp: u32) -> Self {
134 let mut result = self.clone();
135 result.mul_pow2_mut(exp);
136
137 result
138 }
139
140 pub fn mul_pow2_mut(&mut self, exp: u32) {
143 let small = 1 << (exp % 32);
144 let big = exp / 32;
145
146 self.mul_u32_mut(small);
147 self.shift_left_mut(big as usize);
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use crate::UBigInt;
154
155 #[test]
156 fn mul_pow2_test() {
157 let two = UBigInt::from_u32(2);
158 let three = UBigInt::from_u32(3);
159
160 for i in 16..64 {
161 assert_eq!(
162 three.mul_pow2(i * 8),
163 three.mul_ubi(&two.pow_u32(i * 8))
164 );
165 }
166
167 }
168
169}