Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rem_floor and rem_ceil #108193

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3030,6 +3030,45 @@ macro_rules! int_impl {
}
}

/// Calculates the remainder of `self / rhs` if the quotient is rounded toward negative infinity.
///
/// # Panics
///
/// This function will panic if `rhs` is zero.
///
/// ## Overflow behavior
///
/// On overflow, this function will panic if overflow checks are enabled (default in debug
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signed % always panics on overflow (MIN / -1) regardless of the overflow checks compile option. At least this particular method will panic iff the % inside it panics. Therefor, the documentation is incorrect. The already merged ceil and floor div functions should be double checked with this in mind.

Once that is fixed I suggest explaining exactly what constitutes an overflow. (The remainder function never truly overflows, but it panics whenever the corresponding division would also panic.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The already merged ceil and floor div functions should be double checked with this in mind.

Submitted a PR for that and some other stuff. #119726

/// mode) and wrap if overflow checks are disabled (default in release mode).
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(int_roundings)]
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
/// let b = 3;
///
/// assert_eq!(a.rem_floor(b), 2);
/// assert_eq!(a.rem_floor(-b), -1);
/// assert_eq!((-a).rem_floor(b), 1);
/// assert_eq!((-a).rem_floor(-b), -2);
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn rem_floor(self, rhs: Self) -> Self {
let r = self % rhs;
if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
r + rhs
} else {
r
}
}

/// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
///
/// # Panics
Expand Down Expand Up @@ -3066,6 +3105,48 @@ macro_rules! int_impl {
}
}

/// Calculates the remainder of `self / rhs` if the quotient is rounded towards positive infinity.
///
/// This operation is *only* available for signed integers,
/// since the result would be negative if both operands are positive.
///
/// # Panics
///
/// This function will panic if `rhs` is zero.
///
/// ## Overflow behavior
///
/// On overflow, this function will panic if overflow checks are enabled (default in debug
/// mode) and wrap if overflow checks are disabled (default in release mode).
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(rem_ceil)]
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
/// let b = 3;
///
/// assert_eq!(a.rem_ceil(b), -1);
/// assert_eq!(a.rem_ceil(-b), 2);
/// assert_eq!((-a).rem_ceil(b), -2);
/// assert_eq!((-a).rem_ceil(-b), 1);
/// ```
#[unstable(feature = "rem_ceil", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn rem_ceil(self, rhs: Self) -> Self {
let r = self % rhs;
if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) {
r - rhs
} else {
r
}
}

/// If `rhs` is positive, calculates the smallest value greater than or
/// equal to `self` that is a multiple of `rhs`. If `rhs` is negative,
/// calculates the largest value less than or equal to `self` that is a
Expand Down
64 changes: 64 additions & 0 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2863,6 +2863,32 @@ macro_rules! uint_impl {
self / rhs
}

/// Calculates the remainder of `self / rhs` if the quotient is rounded toward negative infinity.
///
/// This is the same as performing `self % rhs` for all unsigned integers.
///
/// # Panics
///
/// This function will panic if `rhs` is zero.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".rem_floor(4), 3);")]
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn rem_floor(self, rhs: Self) -> Self {
self % rhs
}


/// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
///
/// # Panics
Expand Down Expand Up @@ -2892,6 +2918,44 @@ macro_rules! uint_impl {
}
}

/// Calculates the remainder of `self / rhs` if the quotient is rounded towards positive infinity.
///
/// Since this remainder can never be positive, we return the opposite of the actual remainder.
/// If you want the sign to reflect the actual remainder, you need to use the [signed version].
///
#[doc = concat!("[signed version]: primitive.", stringify!($SignedT), ".html#method.rem_ceil")]
///
/// # Panics
///
/// This function will panic if `rhs` is zero.
///
/// ## Overflow behavior
///
/// On overflow, this function will panic if overflow checks are enabled (default in debug
/// mode) and wrap if overflow checks are disabled (default in release mode).
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(rem_ceil)]
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unsigned_rem_ceil(4), 1);")]
/// ```
#[unstable(feature = "rem_ceil", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn unsigned_rem_ceil(self, rhs: Self) -> Self {
let r = self % rhs;
if r != 0 {
rhs - r
} else {
r
}
}

/// Calculates the smallest value greater than or equal to `self` that
/// is a multiple of `rhs`.
///
Expand Down
Loading