Skip to content

Commit

Permalink
Tidy up bigint mul methods
Browse files Browse the repository at this point in the history
  • Loading branch information
clarfonthey committed Dec 28, 2024
1 parent dd84b7d commit f228458
Show file tree
Hide file tree
Showing 11 changed files with 388 additions and 123 deletions.
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
108 changes: 108 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit f228458

Please sign in to comment.