1use core::ops::{Add, Mul, Sub};
14
15#[cfg(target_pointer_width = "16")]
16type UDoubleSize = u32;
17#[cfg(target_pointer_width = "32")]
18type UDoubleSize = u64;
19#[cfg(target_pointer_width = "64")]
20type UDoubleSize = u128;
21
22#[cfg(target_pointer_width = "16")]
23type IDoubleSize = i32;
24#[cfg(target_pointer_width = "32")]
25type IDoubleSize = i64;
26#[cfg(target_pointer_width = "64")]
27type IDoubleSize = i128;
28
29c0nst::c0nst! {
30pub c0nst trait CarryingAdd: Sized + [c0nst] Add<Self> {
32 fn carrying_add(self, rhs: Self, carry: bool) -> (<Self as Add<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 #[inline]
57 fn carrying_add(self, rhs: Self, carry: bool) -> ($t, bool) {
58 let (a, c1) = <$t>::overflowing_add(self, rhs);
59 let (b, c2) = <$t>::overflowing_add(a, carry as $t);
60 (b, c1 | c2)
62 }
63 }
64 }
65 )*};
66 (signed $($t:ty)*) => {$(
68 c0nst::c0nst! {
69 c0nst impl CarryingAdd for $t {
70 #[inline]
71 fn carrying_add(self, rhs: Self, carry: bool) -> ($t, bool) {
72 let (a, b) = <$t>::overflowing_add(self, rhs);
73 let (c, d) = <$t>::overflowing_add(a, carry as $t);
74 (c, b != d)
75 }
76 }
77 }
78 )*};
79}
80
81carrying_add_impl!(unsigned usize u8 u16 u32 u64 u128);
82carrying_add_impl!(signed isize i8 i16 i32 i64 i128);
83
84c0nst::c0nst! {
85pub c0nst trait BorrowingSub: Sized + [c0nst] Sub<Self> {
87 fn borrowing_sub(self, rhs: Self, borrow: bool) -> (<Self as Sub<Self>>::Output, bool);
102}
103}
104
105macro_rules! borrowing_sub_impl {
106 (unsigned $($t:ty)*) => {$(
107 c0nst::c0nst! {
108 c0nst impl BorrowingSub for $t {
109 #[inline]
110 fn borrowing_sub(self, rhs: Self, borrow: bool) -> ($t, bool) {
111 let (a, c1) = <$t>::overflowing_sub(self, rhs);
112 let (b, c2) = <$t>::overflowing_sub(a, borrow as $t);
113 (b, c1 | c2)
114 }
115 }
116 }
117 )*};
118 (signed $($t:ty)*) => {$(
119 c0nst::c0nst! {
120 c0nst impl BorrowingSub for $t {
121 #[inline]
122 fn borrowing_sub(self, rhs: Self, borrow: bool) -> ($t, bool) {
123 let (a, b) = <$t>::overflowing_sub(self, rhs);
124 let (c, d) = <$t>::overflowing_sub(a, borrow as $t);
125 (c, b != d)
126 }
127 }
128 }
129 )*};
130}
131
132borrowing_sub_impl!(unsigned usize u8 u16 u32 u64 u128);
133borrowing_sub_impl!(signed isize i8 i16 i32 i64 i128);
134
135c0nst::c0nst! {
136pub c0nst trait CarryingMul: Sized + [c0nst] Mul<Self> {
139 type Unsigned;
143
144 fn carrying_mul(self, rhs: Self, carry: Self) -> (Self::Unsigned, <Self as Mul<Self>>::Output);
154
155 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (Self::Unsigned, <Self as Mul<Self>>::Output);
161}
162}
163
164macro_rules! carrying_mul_impl {
165 ($($t:ty, $u:ty, $w:ty;)*) => {$(
168 c0nst::c0nst! {
169 c0nst impl CarryingMul for $t {
170 type Unsigned = $u;
171
172 #[inline]
173 fn carrying_mul(self, rhs: Self, carry: Self) -> ($u, $t) {
174 let wide = (self as $w) * (rhs as $w) + (carry as $w);
175 (wide as $u, (wide >> <$t>::BITS) as $t)
176 }
177
178 #[inline]
179 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> ($u, $t) {
180 let wide = (self as $w) * (rhs as $w) + (carry as $w) + (add as $w);
181 (wide as $u, (wide >> <$t>::BITS) as $t)
182 }
183 }
184 }
185 )*};
186}
187
188carrying_mul_impl! {
189 u8, u8, u16;
190 u16, u16, u32;
191 u32, u32, u64;
192 u64, u64, u128;
193 usize, usize, UDoubleSize;
194 i8, u8, i16;
195 i16, u16, i32;
196 i32, u32, i64;
197 i64, u64, i128;
198 isize, usize, IDoubleSize;
199}
200
201pub(crate) const fn wide_mul_u128(a: u128, b: u128) -> (u128, u128) {
204 const MASK: u128 = u64::MAX as u128;
205 let (a_lo, a_hi) = (a & MASK, a >> 64);
206 let (b_lo, b_hi) = (b & MASK, b >> 64);
207
208 let t = a_lo * b_lo;
210 let (low0, c) = (t & MASK, t >> 64);
211 let t = a_hi * b_lo + c;
212 let (low1, low2) = (t & MASK, t >> 64);
213
214 let t = a_lo * b_hi;
216 let (high0, c) = (t & MASK, t >> 64);
217 let t = a_hi * b_hi + c;
218 let (high1, high2) = (t & MASK, t >> 64);
219
220 let t = low1 + high0;
221 let (r1, c) = (t & MASK, t >> 64);
222 let t = low2 + high1 + c;
223 let (r2, c) = (t & MASK, t >> 64);
224 let r3 = high2 + c;
225 (low0 | (r1 << 64), r2 | (r3 << 64))
226}
227
228c0nst::c0nst! {
229c0nst impl CarryingMul for u128 {
230 type Unsigned = u128;
231
232 #[inline]
233 fn carrying_mul(self, rhs: Self, carry: Self) -> (u128, u128) {
234 let (low, mut high) = wide_mul_u128(self, rhs);
235 let (low, c) = u128::overflowing_add(low, carry);
236 high += c as u128;
237 (low, high)
238 }
239
240 #[inline]
241 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (u128, u128) {
242 let (low, mut high) = wide_mul_u128(self, rhs);
243 let (low, c) = u128::overflowing_add(low, carry);
244 high += c as u128;
245 let (low, c) = u128::overflowing_add(low, add);
246 high += c as u128;
247 (low, high)
248 }
249}
250}
251
252c0nst::c0nst! {
253c0nst impl CarryingMul for i128 {
254 type Unsigned = u128;
255
256 #[inline]
257 fn carrying_mul(self, rhs: Self, carry: Self) -> (u128, i128) {
258 let zero = 0i128;
259 CarryingMul::carrying_mul_add(self, rhs, carry, zero)
260 }
261
262 #[inline]
265 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (u128, i128) {
266 let (low, high) = wide_mul_u128(self as u128, rhs as u128);
267 let mut high = high as i128;
268 high = high.wrapping_add(i128::wrapping_mul(self >> 127, rhs));
269 high = high.wrapping_add(i128::wrapping_mul(self, rhs >> 127));
270 let (low, c) = u128::overflowing_add(low, carry as u128);
271 high = high.wrapping_add((c as i128) + (carry >> 127));
272 let (low, c) = u128::overflowing_add(low, add as u128);
273 high = high.wrapping_add((c as i128) + (add >> 127));
274 (low, high)
275 }
276}
277}
278
279c0nst::c0nst! {
280pub c0nst trait WideningMul: Sized + [c0nst] Mul<Self> {
283 type Wide;
285
286 fn widening_mul(self, rhs: Self) -> Self::Wide;
304}
305}
306
307macro_rules! widening_mul_impl {
308 ($($t:ty => $w:ty;)*) => {$(
309 c0nst::c0nst! {
310 c0nst impl WideningMul for $t {
311 type Wide = $w;
312
313 #[inline]
314 fn widening_mul(self, rhs: Self) -> $w {
315 (self as $w) * (rhs as $w)
316 }
317 }
318 }
319 )*};
320}
321
322widening_mul_impl! {
323 u8 => u16;
324 u16 => u32;
325 u32 => u64;
326 u64 => u128;
327 i8 => i16;
328 i16 => i32;
329 i32 => i64;
330 i64 => i128;
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336
337 #[test]
338 fn carrying_add_borrowing_sub() {
339 assert_eq!(
340 CarryingAdd::carrying_add(u8::MAX, u8::MAX, true),
341 (255, true)
342 );
343 assert_eq!(
344 CarryingAdd::carrying_add(0xFFFF_FFFF_FFFF_FFFFu64, 0, true),
345 (0, true)
346 );
347 assert_eq!(CarryingAdd::carrying_add(i8::MAX, 0, true), (i8::MIN, true));
348 assert_eq!(CarryingAdd::carrying_add(-1i8, 1, false), (0, false));
349 assert_eq!(BorrowingSub::borrowing_sub(0u8, u8::MAX, true), (0, true));
350 assert_eq!(BorrowingSub::borrowing_sub(10u8, 3, true), (6, false));
351 assert_eq!(
352 BorrowingSub::borrowing_sub(i8::MIN, 0, true),
353 (i8::MAX, true)
354 );
355 }
356
357 #[test]
358 fn carrying_mul_small() {
359 assert_eq!(CarryingMul::carrying_mul(u8::MAX, u8::MAX, 0), (1, 254));
361 assert_eq!(
362 CarryingMul::carrying_mul_add(u8::MAX, u8::MAX, u8::MAX, u8::MAX),
363 (255, 255)
364 );
365 assert_eq!(CarryingMul::carrying_mul(-1i8, -1, 0), (1, 0));
366 assert_eq!(CarryingMul::carrying_mul(i8::MIN, i8::MIN, 0), (0, 64));
367 assert_eq!(CarryingMul::carrying_mul(-1i8, 1, 0), (255, -1));
368 }
369
370 #[test]
371 fn carrying_mul_128() {
372 assert_eq!(CarryingMul::carrying_mul(1u128 << 127, 2, 0), (0, 1));
374 assert_eq!(
375 CarryingMul::carrying_mul(u128::MAX, u128::MAX, u128::MAX),
376 (0, u128::MAX)
377 );
378 let a = 0x0123_4567_89ab_cdef_fedc_ba98_7654_3210u128;
380 let b = 0x0fed_cba9_8765_4321_1234_5678_9abc_def0u128;
381 let (low, high) = CarryingMul::carrying_mul(a, b, 0);
382 assert_eq!(a.wrapping_mul(b), low);
384 let (l2, h2) = super::wide_mul_u128(a, b);
386 assert_eq!((low, high), (l2, h2));
387
388 assert_eq!(CarryingMul::carrying_mul(-1i128, -1, 0), (1, 0));
390 assert_eq!(
392 CarryingMul::carrying_mul(i128::MIN, -1, 0),
393 (1u128 << 127, 0)
394 );
395 assert_eq!(CarryingMul::carrying_mul(-1i128, 1, 0), (u128::MAX, -1));
396 }
397
398 #[test]
399 fn widening_mul() {
400 assert_eq!(WideningMul::widening_mul(u8::MAX, u8::MAX), 65025u16);
402 assert_eq!(
403 WideningMul::widening_mul(u64::MAX, u64::MAX),
404 u64::MAX as u128 * u64::MAX as u128
405 );
406 assert_eq!(WideningMul::widening_mul(i8::MIN, i8::MIN), 16384i16);
407 assert_eq!(
408 WideningMul::widening_mul(-1i32, i32::MAX),
409 -(i32::MAX as i64)
410 );
411 }
412}