Auto merge of #49389 - fanzier:euclidean-division, r=KodrAus

Implement RFC #2169 (Euclidean modulo).

Tracking issue: #49048
This commit is contained in:
bors 2018-04-13 07:34:37 +00:00
commit f9f9050f50
3 changed files with 541 additions and 0 deletions

View file

@ -643,6 +643,32 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`,
returning `None` if `rhs == 0` or the division results in overflow.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!((", stringify!($SelfT),
"::min_value() + 1).checked_div_euc(-1), Some(", stringify!($Max), "));
assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euc(-1), None);
assert_eq!((1", stringify!($SelfT), ").checked_div_euc(0), None);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn checked_div_euc(self, rhs: Self) -> Option<Self> {
if rhs == 0 || (self == Self::min_value() && rhs == -1) {
None
} else {
Some(self.div_euc(rhs))
}
}
}
doc_comment! {
concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if
`rhs == 0` or the division results in overflow.
@ -670,6 +696,33 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` if
`rhs == 0` or the division results in overflow.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
use std::", stringify!($SelfT), ";
assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1));
assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None);
assert_eq!(", stringify!($SelfT), "::MIN.checked_mod_euc(-1), None);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn checked_mod_euc(self, rhs: Self) -> Option<Self> {
if rhs == 0 || (self == Self::min_value() && rhs == -1) {
None
} else {
Some(self.mod_euc(rhs))
}
}
}
doc_comment! {
concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`.
@ -1003,6 +1056,34 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`,
wrapping around at the boundary of the type.
Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value
for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the
type. In this case, this method returns `MIN` itself.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10);
assert_eq!((-128i8).wrapping_div_euc(-1), -128);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn wrapping_div_euc(self, rhs: Self) -> Self {
self.overflowing_div_euc(rhs).0
}
}
doc_comment! {
concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the
boundary of the type.
@ -1031,6 +1112,33 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`, wrapping around at the
boundary of the type.
Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value
for the type). In this case, this method returns 0.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0);
assert_eq!((-128i8).wrapping_mod_euc(-1), 0);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn wrapping_mod_euc(self, rhs: Self) -> Self {
self.overflowing_mod_euc(rhs).0
}
}
doc_comment! {
concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
of the type.
@ -1296,6 +1404,39 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`.
Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
occur. If an overflow would occur then `self` is returned.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
use std::", stringify!($SelfT), ";
assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));
assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euc(-1), (", stringify!($SelfT),
"::MIN, true));
```"),
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) {
if self == Self::min_value() && rhs == -1 {
(self, true)
} else {
(self.div_euc(rhs), false)
}
}
}
doc_comment! {
concat!("Calculates the remainder when `self` is divided by `rhs`.
@ -1328,6 +1469,40 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division.
Returns a tuple of the remainder after dividing along with a boolean indicating whether an
arithmetic overflow would occur. If an overflow would occur then 0 is returned.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
use std::", stringify!($SelfT), ";
assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));
assert_eq!(", stringify!($SelfT), "::MIN.overflowing_mod_euc(-1), (0, true));
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) {
if self == Self::min_value() && rhs == -1 {
(0, true)
} else {
(self.mod_euc(rhs), false)
}
}
}
doc_comment! {
concat!("Negates self, overflowing if this is equal to the minimum value.
@ -1522,6 +1697,80 @@ $EndFeature, "
}
}
doc_comment! {
concat!("Calculates the quotient of Euclidean division of `self` by `rhs`.
This computes the integer `n` such that `self = n * rhs + self.mod_euc(rhs)`.
In other words, the result is `self / rhs` rounded to the integer `n`
such that `self >= n * rhs`.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
let a: ", stringify!($SelfT), " = 7; // or any other integer type
let b = 4;
assert_eq!(a.div_euc(b), 1); // 7 >= 4 * 1
assert_eq!(a.div_euc(-b), -1); // 7 >= -4 * -1
assert_eq!((-a).div_euc(b), -2); // -7 >= 4 * -2
assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
#[rustc_inherit_overflow_checks]
pub fn div_euc(self, rhs: Self) -> Self {
let q = self / rhs;
if self % rhs < 0 {
return if rhs > 0 { q - 1 } else { q + 1 }
}
q
}
}
doc_comment! {
concat!("Calculates the remainder `self mod rhs` by Euclidean division.
In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
let a: ", stringify!($SelfT), " = 7; // or any other integer type
let b = 4;
assert_eq!(a.mod_euc(b), 3);
assert_eq!((-a).mod_euc(b), 1);
assert_eq!(a.mod_euc(-b), 3);
assert_eq!((-a).mod_euc(-b), 1);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
#[rustc_inherit_overflow_checks]
pub fn mod_euc(self, rhs: Self) -> Self {
let r = self % rhs;
if r < 0 {
r + rhs.abs()
} else {
r
}
}
}
doc_comment! {
concat!("Computes the absolute value of `self`.
@ -2109,6 +2358,31 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, "
}
}
doc_comment! {
concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None`
if `rhs == 0`.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));
assert_eq!(1", stringify!($SelfT), ".checked_div_euc(0), None);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn checked_div_euc(self, rhs: Self) -> Option<Self> {
if rhs == 0 {
None
} else {
Some(self.div_euc(rhs))
}
}
}
doc_comment! {
concat!("Checked integer remainder. Computes `self % rhs`, returning `None`
if `rhs == 0`.
@ -2132,6 +2406,30 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, "
}
}
doc_comment! {
concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None`
if `rhs == 0`.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1));
assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn checked_mod_euc(self, rhs: Self) -> Option<Self> {
if rhs == 0 {
None
} else {
Some(self.mod_euc(rhs))
}
}
}
doc_comment! {
concat!("Checked negation. Computes `-self`, returning `None` unless `self ==
0`.
@ -2411,6 +2709,28 @@ Basic usage:
}
}
doc_comment! {
concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`.
Wrapped division on unsigned types is just normal division.
There's no way wrapping could ever happen.
This function exists, so that all operations
are accounted for in the wrapping operations.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn wrapping_div_euc(self, rhs: Self) -> Self {
self / rhs
}
}
doc_comment! {
concat!("Wrapping (modular) remainder. Computes `self % rhs`.
Wrapped remainder calculation on unsigned types is
@ -2433,6 +2753,29 @@ Basic usage:
}
}
doc_comment! {
concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`.
Wrapped modulo calculation on unsigned types is
just the regular remainder calculation.
There's no way wrapping could ever happen.
This function exists, so that all operations
are accounted for in the wrapping operations.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0);
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
pub fn wrapping_mod_euc(self, rhs: Self) -> Self {
self % rhs
}
}
/// Wrapping (modular) negation. Computes `-self`,
/// wrapping around at the boundary of the type.
///
@ -2666,6 +3009,33 @@ Basic usage
}
}
doc_comment! {
concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`.
Returns a tuple of the divisor along with a boolean indicating
whether an arithmetic overflow would occur. Note that for unsigned
integers overflow never occurs, so the second value is always
`false`.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage
```
#![feature(euclidean_division)]
assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));
```"),
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) {
(self / rhs, false)
}
}
doc_comment! {
concat!("Calculates the remainder when `self` is divided by `rhs`.
@ -2692,6 +3062,33 @@ Basic usage
}
}
doc_comment! {
concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division.
Returns a tuple of the modulo after dividing along with a boolean
indicating whether an arithmetic overflow would occur. Note that for
unsigned integers overflow never occurs, so the second value is
always `false`.
# Panics
This function will panic if `rhs` is 0.
# Examples
Basic usage
```
#![feature(euclidean_division)]
assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));
```"),
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) {
(self % rhs, false)
}
}
doc_comment! {
concat!("Negates self in an overflowing fashion.
@ -2849,6 +3246,49 @@ Basic usage:
}
}
doc_comment! {
concat!("Performs Euclidean division.
For unsigned types, this is just the same as `self / rhs`.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
#[rustc_inherit_overflow_checks]
pub fn div_euc(self, rhs: Self) -> Self {
self / rhs
}
}
doc_comment! {
concat!("Calculates the remainder `self mod rhs` by Euclidean division.
For unsigned types, this is just the same as `self % rhs`.
# Examples
Basic usage:
```
#![feature(euclidean_division)]
assert_eq!(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type
```"),
#[unstable(feature = "euclidean_division", issue = "49048")]
#[inline]
#[rustc_inherit_overflow_checks]
pub fn mod_euc(self, rhs: Self) -> Self {
self % rhs
}
}
doc_comment! {
concat!("Returns `true` if and only if `self == 2^k` for some `k`.

View file

@ -329,6 +329,57 @@ impl f32 {
unsafe { intrinsics::fmaf32(self, a, b) }
}
/// Calculates Euclidean division, the matching method for `mod_euc`.
///
/// This computes the integer `n` such that
/// `self = n * rhs + self.mod_euc(rhs)`.
/// In other words, the result is `self / rhs` rounded to the integer `n`
/// such that `self >= n * rhs`.
///
/// ```
/// #![feature(euclidean_division)]
/// let a: f32 = 7.0;
/// let b = 4.0;
/// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0
/// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0
/// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0
/// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0
/// ```
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
pub fn div_euc(self, rhs: f32) -> f32 {
let q = (self / rhs).trunc();
if self % rhs < 0.0 {
return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }
}
q
}
/// Calculates the Euclidean modulo (self mod rhs), which is never negative.
///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
///
/// ```
/// #![feature(euclidean_division)]
/// let a: f32 = 7.0;
/// let b = 4.0;
/// assert_eq!(a.mod_euc(b), 3.0);
/// assert_eq!((-a).mod_euc(b), 1.0);
/// assert_eq!(a.mod_euc(-b), 3.0);
/// assert_eq!((-a).mod_euc(-b), 1.0);
/// ```
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
pub fn mod_euc(self, rhs: f32) -> f32 {
let r = self % rhs;
if r < 0.0 {
r + rhs.abs()
} else {
r
}
}
/// Takes the reciprocal (inverse) of a number, `1/x`.
///
/// ```

View file

@ -315,6 +315,56 @@ impl f64 {
unsafe { intrinsics::fmaf64(self, a, b) }
}
/// Calculates Euclidean division, the matching method for `mod_euc`.
///
/// This computes the integer `n` such that
/// `self = n * rhs + self.mod_euc(rhs)`.
/// In other words, the result is `self / rhs` rounded to the integer `n`
/// such that `self >= n * rhs`.
///
/// ```
/// #![feature(euclidean_division)]
/// let a: f64 = 7.0;
/// let b = 4.0;
/// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0
/// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0
/// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0
/// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0
/// ```
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
pub fn div_euc(self, rhs: f64) -> f64 {
let q = (self / rhs).trunc();
if self % rhs < 0.0 {
return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }
}
q
}
/// Calculates the Euclidean modulo (self mod rhs), which is never negative.
///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
///
/// ```
/// #![feature(euclidean_division)]
/// let a: f64 = 7.0;
/// let b = 4.0;
/// assert_eq!(a.mod_euc(b), 3.0);
/// assert_eq!((-a).mod_euc(b), 1.0);
/// assert_eq!(a.mod_euc(-b), 3.0);
/// assert_eq!((-a).mod_euc(-b), 1.0);
/// ```
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
pub fn mod_euc(self, rhs: f64) -> f64 {
let r = self % rhs;
if r < 0.0 {
r + rhs.abs()
} else {
r
}
}
/// Takes the reciprocal (inverse) of a number, `1/x`.
///
/// ```