Add round_ties_even to f32 and f64

This commit is contained in:
Jules Bertholet 2022-03-25 02:44:16 -04:00 committed by Jules Bertholet
parent e1c91213ff
commit be681fefed
No known key found for this signature in database
GPG key ID: 32034DAFC38C1BFC
12 changed files with 127 additions and 0 deletions

View file

@ -297,6 +297,8 @@ fn codegen_float_intrinsic_call<'tcx>(
sym::truncf64 => ("trunc", 1, fx.tcx.types.f64),
sym::roundf32 => ("roundf", 1, fx.tcx.types.f32),
sym::roundf64 => ("round", 1, fx.tcx.types.f64),
sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32),
sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64),
sym::sinf32 => ("sinf", 1, fx.tcx.types.f32),
sym::sinf64 => ("sin", 1, fx.tcx.types.f64),
sym::cosf32 => ("cosf", 1, fx.tcx.types.f32),

View file

@ -68,6 +68,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) ->
sym::nearbyintf64 => "nearbyint",
sym::roundf32 => "roundf",
sym::roundf64 => "round",
sym::roundevenf32 => "roundevenf",
sym::roundevenf64 => "roundeven",
sym::abort => "abort",
_ => return None,
};

View file

@ -745,9 +745,13 @@ macro_rules! mk_struct {
ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32);
ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64);
ifn!("llvm.round.f32", fn(t_f32) -> t_f32);
ifn!("llvm.round.f64", fn(t_f64) -> t_f64);
ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32);
ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64);
ifn!("llvm.rint.f32", fn(t_f32) -> t_f32);
ifn!("llvm.rint.f64", fn(t_f64) -> t_f64);
ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32);

View file

@ -72,6 +72,8 @@ fn get_simple_intrinsic<'ll>(
sym::roundf32 => "llvm.round.f32",
sym::roundf64 => "llvm.round.f64",
sym::ptr_mask => "llvm.ptrmask",
sym::roundevenf32 => "llvm.roundeven.f32",
sym::roundevenf64 => "llvm.roundeven.f64",
_ => return None,
};
Some(cx.get_intrinsic(llvm_name))

View file

@ -300,6 +300,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32),
sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64),
sym::roundevenf32 => (0, vec![tcx.types.f32], tcx.types.f32),
sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64),
sym::volatile_load | sym::unaligned_volatile_load => {
(1, vec![tcx.mk_imm_ptr(param(0))], param(0))

View file

@ -1179,6 +1179,8 @@
rlib,
rotate_left,
rotate_right,
roundevenf32,
roundevenf64,
roundf32,
roundf64,
rt,

View file

@ -1613,6 +1613,22 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
/// [`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.
///
/// The stabilized version of this intrinsic is
/// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even)
#[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.
///
/// The stabilized version of this intrinsic is
/// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
#[cfg(not(bootstrap))]
pub fn roundevenf64(x: f64) -> f64;
/// Float addition that allows optimizations based on algebraic rules.
/// May assume inputs are finite.
///

View file

@ -78,10 +78,14 @@ pub fn ceil(self) -> 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,33 @@ pub fn round(self) -> 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);
/// ```
#[cfg(not(bootstrap))]
#[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "round_ties_even", issue = "none")]
#[inline]
pub fn round_ties_even(self) -> f32 {
unsafe { intrinsics::roundevenf32(self) }
}
/// Returns the integer part of `self`.
/// This means that non-integer numbers are always truncated towards zero.
///

View file

@ -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);
@ -221,6 +222,22 @@ fn test_round() {
assert_approx_eq!((-1.7f32).round(), -2.0f32);
}
#[cfg(not(bootstrap))]
#[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);

View file

@ -78,10 +78,14 @@ pub fn ceil(self) -> 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,33 @@ pub fn round(self) -> 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);
/// ```
#[cfg(not(bootstrap))]
#[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "round_ties_even", issue = "none")]
#[inline]
pub fn round_ties_even(self) -> f64 {
unsafe { intrinsics::roundevenf64(self) }
}
/// Returns the integer part of `self`.
/// This means that non-integer numbers are always truncated towards zero.
///

View file

@ -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);
@ -211,6 +212,22 @@ fn test_round() {
assert_approx_eq!((-1.7f64).round(), -2.0f64);
}
#[cfg(not(bootstrap))]
#[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);

View file

@ -307,6 +307,7 @@
#![feature(provide_any)]
#![feature(ptr_as_uninit)]
#![feature(raw_os_nonzero)]
#![cfg_attr(not(bootstrap), feature(round_ties_even))]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
#![feature(std_internals)]