From f228458e3032117fc2752c094332758aaf68cab4 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sat, 26 Oct 2024 14:02:50 -0400 Subject: [PATCH] Tidy up bigint mul methods --- library/core/src/lib.rs | 1 + library/core/src/num/int_macros.rs | 108 ++++++++++ library/core/src/num/uint_macros.rs | 272 +++++++++++++++----------- library/core/tests/lib.rs | 5 +- library/core/tests/num/i128.rs | 2 +- library/core/tests/num/i16.rs | 2 +- library/core/tests/num/i32.rs | 2 +- library/core/tests/num/i64.rs | 2 +- library/core/tests/num/i8.rs | 2 +- library/core/tests/num/int_macros.rs | 100 +++++++++- library/core/tests/num/uint_macros.rs | 15 ++ 11 files changed, 388 insertions(+), 123 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 82d7d045bf571..ba122ddbb64d0 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -110,6 +110,7 @@ #![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] +#![feature(bigint_helper_methods)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(const_typed_swap)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 9a202600988c4..96a290ad5a09d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2512,6 +2512,114 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates the complete product `self * rhs` without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// If you also need to add a carry to the wide result, then you want + /// [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5i32.widening_mul(-2), (4294967286, -1)); + /// assert_eq!(1_000_000_000i32.widening_mul(-10), (2884901888, -3)); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn widening_mul(self, rhs: Self) -> ($UnsignedT, Self) { + Self::carrying_mul_add(self, rhs, 0, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5i32.carrying_mul(-2, 0), (4294967286, -1)); + /// assert_eq!(5i32.carrying_mul(-2, 10), (0, 0)); + /// assert_eq!(1_000_000_000i32.carrying_mul(-10, 0), (2884901888, -3)); + /// assert_eq!(1_000_000_000i32.carrying_mul(-10, 10), (2884901898, -3)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(", stringify!($SelfT), "::MAX.unsigned_abs() + 1, ", stringify!($SelfT), "::MAX / 2));" + )] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> ($UnsignedT, Self) { + Self::carrying_mul_add(self, rhs, carry, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry1 + carry2` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need either `carry`, then you can use [`Self::widening_mul`] instead, + /// and if you only need one `carry`, then you can use [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5i32.carrying_mul_add(-2, 0, 0), (4294967286, -1)); + /// assert_eq!(5i32.carrying_mul_add(-2, 10, 10), (10, 0)); + /// assert_eq!(1_000_000_000i32.carrying_mul_add(-10, 0, 0), (2884901888, -3)); + /// assert_eq!(1_000_000_000i32.carrying_mul_add(-10, 10, 10), (2884901908, -3)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul_add(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(", stringify!($UnsignedT), "::MAX, ", stringify!($SelfT), "::MAX / 2));" + )] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> ($UnsignedT, Self) { + intrinsics::carrying_mul_add(self, rhs, carry, add) + } + /// Calculates the divisor when `self` is divided by `rhs`. /// /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 4a5fdbfb0ea2c..404e4bcffd379 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2530,6 +2530,162 @@ macro_rules! uint_impl { (a as Self, b) } + /// Calculates the complete product `self * rhs` without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// If you also need to add a carry to the wide result, then you want + /// [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.widening_mul(2), (10, 0)); + /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { + Self::carrying_mul_add(self, rhs, 0, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); + /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(0, ", stringify!($SelfT), "::MAX));" + )] + /// ``` + /// + /// This is the core operation needed for scalar multiplication when + /// implementing it for wider-than-native types. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// fn scalar_mul_eq(little_endian_digits: &mut Vec, multiplicand: u16) { + /// let mut carry = 0; + /// for d in little_endian_digits.iter_mut() { + /// (*d, carry) = d.carrying_mul(multiplicand, carry); + /// } + /// if carry != 0 { + /// little_endian_digits.push(carry); + /// } + /// } + /// + /// let mut v = vec![10, 20]; + /// scalar_mul_eq(&mut v, 3); + /// assert_eq!(v, [30, 60]); + /// + /// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D); + /// let mut v = vec![0x4321, 0x8765]; + /// scalar_mul_eq(&mut v, 0xFEED); + /// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]); + /// ``` + /// + /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul), + /// except that it gives the value of the overflow instead of just whether one happened: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// let r = u8::carrying_mul(7, 13, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); + /// let r = u8::carrying_mul(13, 42, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42)); + /// ``` + /// + /// The value of the first field in the returned tuple matches what you'd get + /// by combining the [`wrapping_mul`](Self::wrapping_mul) and + /// [`wrapping_add`](Self::wrapping_add) methods: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!( + /// 789_u16.carrying_mul(456, 123).0, + /// 789_u16.wrapping_mul(456).wrapping_add(123), + /// ); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { + Self::carrying_mul_add(self, rhs, carry, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry1 + carry2` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need either `carry`, then you can use [`Self::widening_mul`] instead, + /// and if you only need one `carry`, then you can use [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.carrying_mul_add(2, 0, 0), (10, 0)); + /// assert_eq!(5u32.carrying_mul_add(2, 10, 10), (30, 0)); + /// assert_eq!(1_000_000_000u32.carrying_mul_add(10, 0, 0), (1410065408, 2)); + /// assert_eq!(1_000_000_000u32.carrying_mul_add(10, 10, 10), (1410065428, 2)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul_add(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX));" + )] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (Self, Self) { + intrinsics::carrying_mul_add(self, rhs, carry, add) + } + /// Calculates the divisor when `self` is divided by `rhs`. /// /// Returns a tuple of the divisor along with a boolean indicating @@ -3347,122 +3503,6 @@ macro_rules! uint_impl { unsafe { mem::transmute(bytes) } } - /// Calculates the complete product `self * rhs` without the possibility to overflow. - /// - /// This returns the low-order (wrapping) bits and the high-order (overflow) bits - /// of the result as two separate values, in that order. - /// - /// If you also need to add a carry to the wide result, then you want - /// [`Self::carrying_mul`] instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!(5u32.widening_mul(2), (10, 0)); - /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); - /// ``` - #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { - Self::carrying_mul(self, rhs, 0) - } - - /// Calculates the "full multiplication" `self * rhs + carry` - /// without the possibility to overflow. - /// - /// This returns the low-order (wrapping) bits and the high-order (overflow) bits - /// of the result as two separate values, in that order. - /// - /// Performs "long multiplication" which takes in an extra amount to add, and may return an - /// additional amount of overflow. This allows for chaining together multiple - /// multiplications to create "big integers" which represent larger values. - /// - /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); - /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); - /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); - /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); - #[doc = concat!("assert_eq!(", - stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", - "(0, ", stringify!($SelfT), "::MAX));" - )] - /// ``` - /// - /// This is the core operation needed for scalar multiplication when - /// implementing it for wider-than-native types. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// fn scalar_mul_eq(little_endian_digits: &mut Vec, multiplicand: u16) { - /// let mut carry = 0; - /// for d in little_endian_digits.iter_mut() { - /// (*d, carry) = d.carrying_mul(multiplicand, carry); - /// } - /// if carry != 0 { - /// little_endian_digits.push(carry); - /// } - /// } - /// - /// let mut v = vec![10, 20]; - /// scalar_mul_eq(&mut v, 3); - /// assert_eq!(v, [30, 60]); - /// - /// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D); - /// let mut v = vec![0x4321, 0x8765]; - /// scalar_mul_eq(&mut v, 0xFEED); - /// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]); - /// ``` - /// - /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul), - /// except that it gives the value of the overflow instead of just whether one happened: - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// let r = u8::carrying_mul(7, 13, 0); - /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); - /// let r = u8::carrying_mul(13, 42, 0); - /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42)); - /// ``` - /// - /// The value of the first field in the returned tuple matches what you'd get - /// by combining the [`wrapping_mul`](Self::wrapping_mul) and - /// [`wrapping_add`](Self::wrapping_add) methods: - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!( - /// 789_u16.carrying_mul(456, 123).0, - /// 789_u16.wrapping_mul(456).wrapping_add(123), - /// ); - /// ``` - #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { - intrinsics::carrying_mul_add(self, rhs, 0, carry) - } - /// New code should prefer to use #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`] instead.")] /// diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8716c09492834..2135960061003 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -99,10 +99,13 @@ /// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. macro_rules! assert_eq_const_safe { + ($left:expr, $right:expr) => { + assert_eq_const_safe!($left, $right, concat!(stringify!($left), " == ", stringify!($right))); + }; ($left:expr, $right:expr$(, $($arg:tt)+)?) => { { fn runtime() { - assert_eq!($left, $right, $($arg)*); + assert_eq!($left, $right, $($($arg)*),*); } const fn compiletime() { assert!(matches!($left, const { $right })); diff --git a/library/core/tests/num/i128.rs b/library/core/tests/num/i128.rs index 1ddd20f33d0b1..745fee05164c9 100644 --- a/library/core/tests/num/i128.rs +++ b/library/core/tests/num/i128.rs @@ -1 +1 @@ -int_module!(i128); +int_module!(i128, u128); diff --git a/library/core/tests/num/i16.rs b/library/core/tests/num/i16.rs index c7aa9fff964ed..6acb8371b87d8 100644 --- a/library/core/tests/num/i16.rs +++ b/library/core/tests/num/i16.rs @@ -1 +1 @@ -int_module!(i16); +int_module!(i16, u16); diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index efd5b1596a80d..38d5071f71d6c 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -1,4 +1,4 @@ -int_module!(i32); +int_module!(i32, u32); #[test] fn test_arith_operation() { diff --git a/library/core/tests/num/i64.rs b/library/core/tests/num/i64.rs index 93d23c10adf7e..f8dd5f9be7fe2 100644 --- a/library/core/tests/num/i64.rs +++ b/library/core/tests/num/i64.rs @@ -1 +1 @@ -int_module!(i64); +int_module!(i64, u64); diff --git a/library/core/tests/num/i8.rs b/library/core/tests/num/i8.rs index 887d4f17d25ff..a10906618c937 100644 --- a/library/core/tests/num/i8.rs +++ b/library/core/tests/num/i8.rs @@ -1 +1 @@ -int_module!(i8); +int_module!(i8, u8); diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 474d57049ab65..f13b836378b9e 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -1,8 +1,10 @@ macro_rules! int_module { - ($T:ident) => { + ($T:ident, $U:ident) => { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T::*; + const UMAX: $U = $U::MAX; + use crate::num; #[test] @@ -355,6 +357,102 @@ macro_rules! int_module { assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false)); } + fn test_widening_mul() { + assert_eq_const_safe!(MAX.widening_mul(MAX), (1, MAX / 2)); + assert_eq_const_safe!(MIN.widening_mul(MAX), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(MIN.widening_mul(MIN), (0, MAX / 2 + 1)); + } + + fn test_carrying_mul() { + assert_eq_const_safe!(MAX.carrying_mul(MAX, 0), (1, MAX / 2)); + assert_eq_const_safe!( + MAX.carrying_mul(MAX, MAX), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul(MAX, MIN), + (UMAX / 2 + 2, MAX / 2 - 1) + ); + assert_eq_const_safe!(MIN.carrying_mul(MAX, 0), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MAX, MAX), (UMAX, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MAX, MIN), (0, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MIN, 0), (0, MAX / 2 + 1)); + assert_eq_const_safe!( + MIN.carrying_mul(MIN, MAX), + (UMAX / 2, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul(MIN, MIN), + (UMAX / 2 + 1, MAX / 2) + ); + } + + fn test_carrying_mul_add() { + assert_eq_const_safe!(MAX.carrying_mul_add(MAX, 0, 0), (1, MAX / 2)); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, 0), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MIN, 0), + (UMAX / 2 + 2, MAX / 2 - 1) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, MAX), + (UMAX, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, MIN), + (0, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MIN, MIN), + (1, MAX / 2 - 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, 0, 0), + (MIN as $U, MIN / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, 0), + (UMAX, MIN / 2) + ); + assert_eq_const_safe!(MIN.carrying_mul_add(MAX, MIN, 0), (0, MIN / 2)); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, MAX), + (UMAX / 2 - 1, MIN / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, MIN), + (UMAX / 2, MIN / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MIN, MIN), + (UMAX / 2 + 1, MIN / 2 - 1) + ); + assert_eq_const_safe!(MIN.carrying_mul_add(MIN, 0, 0), (0, MAX / 2 + 1)); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, 0), + (UMAX / 2, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MIN, 0), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, MAX), + (UMAX - 1, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, MIN), + (UMAX, MAX / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MIN, MIN), + (0, MAX / 2) + ); + } + fn test_midpoint() { assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index ad8e48491e829..99a2d4cd462b1 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -277,6 +277,21 @@ macro_rules! uint_module { assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); } + fn test_widening_mul() { + assert_eq_const_safe!($T::MAX.widening_mul($T::MAX), (1, $T::MAX - 1)); + } + + fn test_carrying_mul() { + assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, $T::MAX), (0, $T::MAX)); + } + + fn test_carrying_mul_add() { + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, 0, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, 0), (0, $T::MAX)); + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, $T::MAX), ($T::MAX, $T::MAX)); + } + fn test_midpoint() { assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); assert_eq_const_safe!(<$T>::midpoint(3, 1), 2);