diff options
| author | bors <bors@rust-lang.org> | 2023-03-07 09:43:12 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-03-07 09:43:12 +0000 |
| commit | 0a3b557d528dd7c8a88ceca6f7dc0699b89a3ef4 (patch) | |
| tree | ad02b3e1690da2f936e346d44840d552b97f9f1e /library | |
| parent | 8f9e09ac3ef3fa85d23ad6a0c920d49987144b13 (diff) | |
| parent | 371d57084d7c2e2dd9b4ac6b5bb9fcc8b0dacd1e (diff) | |
| download | rust-0a3b557d528dd7c8a88ceca6f7dc0699b89a3ef4.tar.gz rust-0a3b557d528dd7c8a88ceca6f7dc0699b89a3ef4.zip | |
Auto merge of #95317 - Jules-Bertholet:round_ties_to_even, r=pnkfelix,m-ou-se,scottmcm
Add `round_ties_even` to `f32` and `f64` Tracking issue: #96710 Redux of #82273. See also #55107 Adds a new method, `round_ties_even`, to `f32` and `f64`, that rounds the float to the nearest integer , rounding halfway cases to the number with an even least significant bit. Uses the `roundeven` LLVM intrinsic to do this. Of the five IEEE 754 rounding modes, this is the only one that doesn't already have a round-to-integer function exposed by Rust (others are `round`, `floor`, `ceil`, and `trunc`). Ties-to-even is also the rounding mode used for int-to-float and float-to-float `as` casts, as well as float arithmentic operations. So not having an explicit rounding method for it seems like an oversight. Bikeshed: this PR currently uses `round_ties_even` for the name of the method. But maybe `round_ties_to_even` is better, or `round_even`, or `round_to_even`?
Diffstat (limited to 'library')
| -rw-r--r-- | library/core/src/intrinsics.rs | 19 | ||||
| -rw-r--r-- | library/std/src/f32.rs | 30 | ||||
| -rw-r--r-- | library/std/src/f32/tests.rs | 16 | ||||
| -rw-r--r-- | library/std/src/f64.rs | 30 | ||||
| -rw-r--r-- | library/std/src/f64/tests.rs | 16 | ||||
| -rw-r--r-- | library/std/src/lib.rs | 1 |
6 files changed, 112 insertions, 0 deletions
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 18a90599c4d..c6321587adc 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1585,9 +1585,15 @@ extern "rust-intrinsic" { /// Returns the nearest integer to an `f32`. May raise an inexact floating-point exception /// if the argument is not an integer. + /// + /// The stabilized version of this intrinsic is + /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) pub fn rintf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. May raise an inexact floating-point exception /// if the argument is not an integer. + /// + /// The stabilized version of this intrinsic is + /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) pub fn rintf64(x: f64) -> f64; /// Returns the nearest integer to an `f32`. @@ -1610,6 +1616,19 @@ extern "rust-intrinsic" { /// [`f64::round`](../../std/primitive.f64.html#method.round) pub fn roundf64(x: f64) -> f64; + /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[cfg(not(bootstrap))] + pub fn roundevenf32(x: f32) -> f32; + /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[cfg(not(bootstrap))] + pub fn roundevenf64(x: f64) -> f64; + /// Float addition that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 6b1f0cba82d..c7c33678fd3 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -78,10 +78,14 @@ impl f32 { /// let f = 3.3_f32; /// let g = -3.3_f32; /// let h = -3.7_f32; + /// let i = 3.5_f32; + /// let j = 4.5_f32; /// /// assert_eq!(f.round(), 3.0); /// assert_eq!(g.round(), -3.0); /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -91,6 +95,32 @@ impl f32 { unsafe { intrinsics::roundf32(self) } } + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// # Examples + /// + /// ``` + /// #![feature(round_ties_even)] + /// + /// let f = 3.3_f32; + /// let g = -3.3_f32; + /// let h = 3.5_f32; + /// let i = 4.5_f32; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "round_ties_even", issue = "96710")] + #[inline] + pub fn round_ties_even(self) -> f32 { + unsafe { intrinsics::rintf32(self) } + } + /// Returns the integer part of `self`. /// This means that non-integer numbers are always truncated towards zero. /// diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 6ee295de616..e949def00bb 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -209,6 +209,7 @@ fn test_ceil() { #[test] fn test_round() { + assert_approx_eq!(2.5f32.round(), 3.0f32); assert_approx_eq!(1.0f32.round(), 1.0f32); assert_approx_eq!(1.3f32.round(), 1.0f32); assert_approx_eq!(1.5f32.round(), 2.0f32); @@ -222,6 +223,21 @@ fn test_round() { } #[test] +fn test_round_ties_even() { + assert_approx_eq!(2.5f32.round_ties_even(), 2.0f32); + assert_approx_eq!(1.0f32.round_ties_even(), 1.0f32); + assert_approx_eq!(1.3f32.round_ties_even(), 1.0f32); + assert_approx_eq!(1.5f32.round_ties_even(), 2.0f32); + assert_approx_eq!(1.7f32.round_ties_even(), 2.0f32); + assert_approx_eq!(0.0f32.round_ties_even(), 0.0f32); + assert_approx_eq!((-0.0f32).round_ties_even(), -0.0f32); + assert_approx_eq!((-1.0f32).round_ties_even(), -1.0f32); + assert_approx_eq!((-1.3f32).round_ties_even(), -1.0f32); + assert_approx_eq!((-1.5f32).round_ties_even(), -2.0f32); + assert_approx_eq!((-1.7f32).round_ties_even(), -2.0f32); +} + +#[test] fn test_trunc() { assert_approx_eq!(1.0f32.trunc(), 1.0f32); assert_approx_eq!(1.3f32.trunc(), 1.0f32); diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 16359766b51..b1faa670307 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -78,10 +78,14 @@ impl f64 { /// let f = 3.3_f64; /// let g = -3.3_f64; /// let h = -3.7_f64; + /// let i = 3.5_f64; + /// let j = 4.5_f64; /// /// assert_eq!(f.round(), 3.0); /// assert_eq!(g.round(), -3.0); /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -91,6 +95,32 @@ impl f64 { unsafe { intrinsics::roundf64(self) } } + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// # Examples + /// + /// ``` + /// #![feature(round_ties_even)] + /// + /// let f = 3.3_f64; + /// let g = -3.3_f64; + /// let h = 3.5_f64; + /// let i = 4.5_f64; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "round_ties_even", issue = "96710")] + #[inline] + pub fn round_ties_even(self) -> f64 { + unsafe { intrinsics::rintf64(self) } + } + /// Returns the integer part of `self`. /// This means that non-integer numbers are always truncated towards zero. /// diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 5b039d445ce..53d351cceef 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -199,6 +199,7 @@ fn test_ceil() { #[test] fn test_round() { + assert_approx_eq!(2.5f64.round(), 3.0f64); assert_approx_eq!(1.0f64.round(), 1.0f64); assert_approx_eq!(1.3f64.round(), 1.0f64); assert_approx_eq!(1.5f64.round(), 2.0f64); @@ -212,6 +213,21 @@ fn test_round() { } #[test] +fn test_round_ties_even() { + assert_approx_eq!(2.5f64.round_ties_even(), 2.0f64); + assert_approx_eq!(1.0f64.round_ties_even(), 1.0f64); + assert_approx_eq!(1.3f64.round_ties_even(), 1.0f64); + assert_approx_eq!(1.5f64.round_ties_even(), 2.0f64); + assert_approx_eq!(1.7f64.round_ties_even(), 2.0f64); + assert_approx_eq!(0.0f64.round_ties_even(), 0.0f64); + assert_approx_eq!((-0.0f64).round_ties_even(), -0.0f64); + assert_approx_eq!((-1.0f64).round_ties_even(), -1.0f64); + assert_approx_eq!((-1.3f64).round_ties_even(), -1.0f64); + assert_approx_eq!((-1.5f64).round_ties_even(), -2.0f64); + assert_approx_eq!((-1.7f64).round_ties_even(), -2.0f64); +} + +#[test] fn test_trunc() { assert_approx_eq!(1.0f64.trunc(), 1.0f64); assert_approx_eq!(1.3f64.trunc(), 1.0f64); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b62f3ad29d3..7837dd276d2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -304,6 +304,7 @@ #![feature(provide_any)] #![feature(ptr_as_uninit)] #![feature(raw_os_nonzero)] +#![feature(round_ties_even)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(std_internals)] |
