1#[cfg(target_pointer_width = "16")]
14type UDoubleSize = u32;
15#[cfg(target_pointer_width = "32")]
16type UDoubleSize = u64;
17#[cfg(target_pointer_width = "64")]
18type UDoubleSize = u128;
19
20#[cfg(target_pointer_width = "16")]
21type IDoubleSize = i32;
22#[cfg(target_pointer_width = "32")]
23type IDoubleSize = i64;
24#[cfg(target_pointer_width = "64")]
25type IDoubleSize = i128;
26
27c0nst::c0nst! {
28pub c0nst trait CarryingAdd: Sized {
30 type Output;
32 fn carrying_add(self, rhs: Self, carry: bool) -> (Self::Output, bool);
48}
49}
50
51macro_rules! carrying_add_impl {
52 (unsigned $($t:ty)*) => {$(
54 c0nst::c0nst! {
55 c0nst impl CarryingAdd for $t {
56 type Output = $t;
57 #[inline]
58 fn carrying_add(self, rhs: Self, carry: bool) -> ($t, bool) {
59 let (a, c1) = <$t>::overflowing_add(self, rhs);
60 let (b, c2) = <$t>::overflowing_add(a, carry as $t);
61 (b, c1 | c2)
63 }
64 }
65 }
66 )*};
67 (signed $($t:ty)*) => {$(
69 c0nst::c0nst! {
70 c0nst impl CarryingAdd for $t {
71 type Output = $t;
72 #[inline]
73 fn carrying_add(self, rhs: Self, carry: bool) -> ($t, bool) {
74 let (a, b) = <$t>::overflowing_add(self, rhs);
75 let (c, d) = <$t>::overflowing_add(a, carry as $t);
76 (c, b != d)
77 }
78 }
79 }
80 )*};
81}
82
83carrying_add_impl!(unsigned usize u8 u16 u32 u64 u128);
84carrying_add_impl!(signed isize i8 i16 i32 i64 i128);
85
86c0nst::c0nst! {
87pub c0nst trait BorrowingSub: Sized {
89 type Output;
91 fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self::Output, bool);
106}
107}
108
109macro_rules! borrowing_sub_impl {
110 (unsigned $($t:ty)*) => {$(
111 c0nst::c0nst! {
112 c0nst impl BorrowingSub for $t {
113 type Output = $t;
114 #[inline]
115 fn borrowing_sub(self, rhs: Self, borrow: bool) -> ($t, bool) {
116 let (a, c1) = <$t>::overflowing_sub(self, rhs);
117 let (b, c2) = <$t>::overflowing_sub(a, borrow as $t);
118 (b, c1 | c2)
119 }
120 }
121 }
122 )*};
123 (signed $($t:ty)*) => {$(
124 c0nst::c0nst! {
125 c0nst impl BorrowingSub for $t {
126 type Output = $t;
127 #[inline]
128 fn borrowing_sub(self, rhs: Self, borrow: bool) -> ($t, bool) {
129 let (a, b) = <$t>::overflowing_sub(self, rhs);
130 let (c, d) = <$t>::overflowing_sub(a, borrow as $t);
131 (c, b != d)
132 }
133 }
134 }
135 )*};
136}
137
138borrowing_sub_impl!(unsigned usize u8 u16 u32 u64 u128);
139borrowing_sub_impl!(signed isize i8 i16 i32 i64 i128);
140
141c0nst::c0nst! {
142pub c0nst trait CarryingMul: Sized {
145 type Unsigned;
149
150 type Output;
152
153 fn carrying_mul(self, rhs: Self, carry: Self) -> (Self::Unsigned, Self::Output);
163
164 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (Self::Unsigned, Self::Output);
170}
171}
172
173macro_rules! carrying_mul_impl {
174 ($($t:ty, $u:ty, $w:ty;)*) => {$(
177 c0nst::c0nst! {
178 c0nst impl CarryingMul for $t {
179 type Unsigned = $u;
180 type Output = $t;
181
182 #[inline]
183 fn carrying_mul(self, rhs: Self, carry: Self) -> ($u, $t) {
184 let wide = (self as $w) * (rhs as $w) + (carry as $w);
185 (wide as $u, (wide >> <$t>::BITS) as $t)
186 }
187
188 #[inline]
189 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> ($u, $t) {
190 let wide = (self as $w) * (rhs as $w) + (carry as $w) + (add as $w);
191 (wide as $u, (wide >> <$t>::BITS) as $t)
192 }
193 }
194 }
195 )*};
196}
197
198carrying_mul_impl! {
199 u8, u8, u16;
200 u16, u16, u32;
201 u32, u32, u64;
202 u64, u64, u128;
203 usize, usize, UDoubleSize;
204 i8, u8, i16;
205 i16, u16, i32;
206 i32, u32, i64;
207 i64, u64, i128;
208 isize, usize, IDoubleSize;
209}
210
211pub(crate) const fn wide_mul_u128(a: u128, b: u128) -> (u128, u128) {
214 const MASK: u128 = u64::MAX as u128;
215 let (a_lo, a_hi) = (a & MASK, a >> 64);
216 let (b_lo, b_hi) = (b & MASK, b >> 64);
217
218 let t = a_lo * b_lo;
220 let (low0, c) = (t & MASK, t >> 64);
221 let t = a_hi * b_lo + c;
222 let (low1, low2) = (t & MASK, t >> 64);
223
224 let t = a_lo * b_hi;
226 let (high0, c) = (t & MASK, t >> 64);
227 let t = a_hi * b_hi + c;
228 let (high1, high2) = (t & MASK, t >> 64);
229
230 let t = low1 + high0;
231 let (r1, c) = (t & MASK, t >> 64);
232 let t = low2 + high1 + c;
233 let (r2, c) = (t & MASK, t >> 64);
234 let r3 = high2 + c;
235 (low0 | (r1 << 64), r2 | (r3 << 64))
236}
237
238c0nst::c0nst! {
239c0nst impl CarryingMul for u128 {
240 type Unsigned = u128;
241 type Output = u128;
242
243 #[inline]
244 fn carrying_mul(self, rhs: Self, carry: Self) -> (u128, u128) {
245 let (low, mut high) = wide_mul_u128(self, rhs);
246 let (low, c) = u128::overflowing_add(low, carry);
247 high += c as u128;
248 (low, high)
249 }
250
251 #[inline]
252 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (u128, u128) {
253 let (low, mut high) = wide_mul_u128(self, rhs);
254 let (low, c) = u128::overflowing_add(low, carry);
255 high += c as u128;
256 let (low, c) = u128::overflowing_add(low, add);
257 high += c as u128;
258 (low, high)
259 }
260}
261}
262
263c0nst::c0nst! {
264c0nst impl CarryingMul for i128 {
265 type Unsigned = u128;
266 type Output = i128;
267
268 #[inline]
269 fn carrying_mul(self, rhs: Self, carry: Self) -> (u128, i128) {
270 let zero = 0i128;
271 CarryingMul::carrying_mul_add(self, rhs, carry, zero)
272 }
273
274 #[inline]
277 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (u128, i128) {
278 let (low, high) = wide_mul_u128(self as u128, rhs as u128);
279 let mut high = high as i128;
280 high = high.wrapping_add(i128::wrapping_mul(self >> 127, rhs));
281 high = high.wrapping_add(i128::wrapping_mul(self, rhs >> 127));
282 let (low, c) = u128::overflowing_add(low, carry as u128);
283 high = high.wrapping_add((c as i128) + (carry >> 127));
284 let (low, c) = u128::overflowing_add(low, add as u128);
285 high = high.wrapping_add((c as i128) + (add >> 127));
286 (low, high)
287 }
288}
289}
290
291c0nst::c0nst! {
292pub c0nst trait WideningMul: Sized {
295 type Wide;
297
298 fn widening_mul(self, rhs: Self) -> Self::Wide;
316}
317}
318
319macro_rules! widening_mul_impl {
320 ($($t:ty => $w:ty;)*) => {$(
321 c0nst::c0nst! {
322 c0nst impl WideningMul for $t {
323 type Wide = $w;
324
325 #[inline]
326 fn widening_mul(self, rhs: Self) -> $w {
327 (self as $w) * (rhs as $w)
328 }
329 }
330 }
331 )*};
332}
333
334widening_mul_impl! {
335 u8 => u16;
336 u16 => u32;
337 u32 => u64;
338 u64 => u128;
339 i8 => i16;
340 i16 => i32;
341 i32 => i64;
342 i64 => i128;
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348
349 #[test]
350 fn carrying_add_borrowing_sub() {
351 assert_eq!(
352 CarryingAdd::carrying_add(u8::MAX, u8::MAX, true),
353 (255, true)
354 );
355 assert_eq!(
356 CarryingAdd::carrying_add(0xFFFF_FFFF_FFFF_FFFFu64, 0, true),
357 (0, true)
358 );
359 assert_eq!(CarryingAdd::carrying_add(i8::MAX, 0, true), (i8::MIN, true));
360 assert_eq!(CarryingAdd::carrying_add(-1i8, 1, false), (0, false));
361 assert_eq!(BorrowingSub::borrowing_sub(0u8, u8::MAX, true), (0, true));
362 assert_eq!(BorrowingSub::borrowing_sub(10u8, 3, true), (6, false));
363 assert_eq!(
364 BorrowingSub::borrowing_sub(i8::MIN, 0, true),
365 (i8::MAX, true)
366 );
367 }
368
369 #[test]
370 fn carrying_mul_small() {
371 assert_eq!(CarryingMul::carrying_mul(u8::MAX, u8::MAX, 0), (1, 254));
373 assert_eq!(
374 CarryingMul::carrying_mul_add(u8::MAX, u8::MAX, u8::MAX, u8::MAX),
375 (255, 255)
376 );
377 assert_eq!(CarryingMul::carrying_mul(-1i8, -1, 0), (1, 0));
378 assert_eq!(CarryingMul::carrying_mul(i8::MIN, i8::MIN, 0), (0, 64));
379 assert_eq!(CarryingMul::carrying_mul(-1i8, 1, 0), (255, -1));
380 }
381
382 #[test]
383 fn carrying_mul_128() {
384 assert_eq!(CarryingMul::carrying_mul(1u128 << 127, 2, 0), (0, 1));
386 assert_eq!(
387 CarryingMul::carrying_mul(u128::MAX, u128::MAX, u128::MAX),
388 (0, u128::MAX)
389 );
390 let a = 0x0123_4567_89ab_cdef_fedc_ba98_7654_3210u128;
392 let b = 0x0fed_cba9_8765_4321_1234_5678_9abc_def0u128;
393 let (low, high) = CarryingMul::carrying_mul(a, b, 0);
394 assert_eq!(a.wrapping_mul(b), low);
396 let (l2, h2) = super::wide_mul_u128(a, b);
398 assert_eq!((low, high), (l2, h2));
399
400 assert_eq!(CarryingMul::carrying_mul(-1i128, -1, 0), (1, 0));
402 assert_eq!(
404 CarryingMul::carrying_mul(i128::MIN, -1, 0),
405 (1u128 << 127, 0)
406 );
407 assert_eq!(CarryingMul::carrying_mul(-1i128, 1, 0), (u128::MAX, -1));
408 }
409
410 #[test]
411 fn widening_mul() {
412 assert_eq!(WideningMul::widening_mul(u8::MAX, u8::MAX), 65025u16);
414 assert_eq!(
415 WideningMul::widening_mul(u64::MAX, u64::MAX),
416 u64::MAX as u128 * u64::MAX as u128
417 );
418 assert_eq!(WideningMul::widening_mul(i8::MIN, i8::MIN), 16384i16);
419 assert_eq!(
420 WideningMul::widening_mul(-1i32, i32::MAX),
421 -(i32::MAX as i64)
422 );
423 }
424}