Skip to content

Commit

Permalink
Tidy up bigint mul implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
clarfonthey committed Oct 28, 2024
1 parent 5f5c243 commit 35e3b3c
Show file tree
Hide file tree
Showing 12 changed files with 574 additions and 120 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(const_fmt_arguments_new))]
#![feature(array_ptr_get)]
#![feature(asm_experimental_arch)]
#![feature(bigint_helper_methods)]
#![feature(const_align_of_val)]
#![feature(const_align_of_val_raw)]
#![feature(const_align_offset)]
Expand Down
111 changes: 111 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2540,6 +2540,117 @@ 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 = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(const_bigint_helper_methods)]
#[inline]
pub const fn widening_mul(self, rhs: Self) -> ($UnsignedT, Self) {
self.widening_mul_impl(rhs)
}

/// 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 = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(const_bigint_helper_methods)]
#[inline]
pub const fn carrying_mul(self, rhs: Self, carry: Self) -> ($UnsignedT, Self) {
self.carrying_mul_impl(rhs, carry)
}

/// 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.carrying2_mul(-2, 0, 0), (4294967286, -1));
/// assert_eq!(5i32.carrying2_mul(-2, 10, 10), (10, 0));
/// assert_eq!(1_000_000_000i32.carrying2_mul(-10, 0, 0), (2884901888, -3));
/// assert_eq!(1_000_000_000i32.carrying2_mul(-10, 10, 10), (2884901908, -3));
#[doc = concat!("assert_eq!(",
stringify!($SelfT), "::MAX.carrying2_mul(", 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 = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(const_bigint_helper_methods)]
#[inline]
pub const fn carrying2_mul(self, rhs: Self, carry1: Self, carry2: Self) -> ($UnsignedT, Self) {
self.carrying2_mul_impl(rhs, carry1, carry2)
}

/// 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 35e3b3c

Please sign in to comment.