about summary refs log tree commit diff
diff options
context:
space:
mode:
authorltdk <usr@ltdk.xyz>2024-10-26 14:02:50 -0400
committerltdk <usr@ltdk.xyz>2024-12-27 22:01:51 -0500
commitf228458e3032117fc2752c094332758aaf68cab4 (patch)
treeb061917cee51c474122338f5f6af25f609a06aa9
parentdd84b7d5eec3c20d7fcd13e6450af029d3cece9d (diff)
downloadrust-f228458e3032117fc2752c094332758aaf68cab4.tar.gz
rust-f228458e3032117fc2752c094332758aaf68cab4.zip
Tidy up bigint mul methods
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/num/int_macros.rs108
-rw-r--r--library/core/src/num/uint_macros.rs272
-rw-r--r--library/core/tests/lib.rs5
-rw-r--r--library/core/tests/num/i128.rs2
-rw-r--r--library/core/tests/num/i16.rs2
-rw-r--r--library/core/tests/num/i32.rs2
-rw-r--r--library/core/tests/num/i64.rs2
-rw-r--r--library/core/tests/num/i8.rs2
-rw-r--r--library/core/tests/num/int_macros.rs100
-rw-r--r--library/core/tests/num/uint_macros.rs15
11 files changed, 388 insertions, 123 deletions
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 82d7d045bf5..ba122ddbb64 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 9a202600988..96a290ad5a0 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 4a5fdbfb0ea..404e4bcffd3 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<u16>, 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<u16>, 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 8716c094928..21359600610 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 1ddd20f33d0..745fee05164 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 c7aa9fff964..6acb8371b87 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 efd5b1596a8..38d5071f71d 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 93d23c10adf..f8dd5f9be7f 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 887d4f17d25..a10906618c9 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 474d57049ab..f13b836378b 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 ad8e48491e8..99a2d4cd462 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);