Merge pull request rust-lang/libm#454 from tgross35/generic-rint
Add `rintf16` and `rintf128`
This commit is contained in:
commit
6c6354bbe1
16 changed files with 130 additions and 100 deletions
|
|
@ -145,6 +145,8 @@ no_mangle! {
|
|||
remquof(x: f32, y: f32 | q: &mut c_int) -> f32;
|
||||
rint(x: f64) -> f64;
|
||||
rintf(x: f32) -> f32;
|
||||
rintf128(x: f128) -> f128;
|
||||
rintf16(x: f16) -> f16;
|
||||
round(x: f64) -> f64;
|
||||
roundf(x: f32) -> f32;
|
||||
scalbn(x: f64, y: c_int) -> f64;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
|
|||
FloatTy::F16,
|
||||
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
|
||||
None,
|
||||
&["ceilf16", "fabsf16", "floorf16", "sqrtf16", "truncf16"],
|
||||
&["ceilf16", "fabsf16", "floorf16", "rintf16", "sqrtf16", "truncf16"],
|
||||
),
|
||||
(
|
||||
// `fn(f32) -> f32`
|
||||
|
|
@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
|
|||
FloatTy::F128,
|
||||
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
|
||||
None,
|
||||
&["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"],
|
||||
&["ceilf128", "fabsf128", "floorf128", "rintf128", "sqrtf128", "truncf128"],
|
||||
),
|
||||
(
|
||||
// `(f16, f16) -> f16`
|
||||
|
|
|
|||
|
|
@ -149,6 +149,8 @@ main!(
|
|||
icount_bench_remquo_group,
|
||||
icount_bench_remquof_group,
|
||||
icount_bench_rint_group,
|
||||
icount_bench_rintf128_group,
|
||||
icount_bench_rintf16_group,
|
||||
icount_bench_rintf_group,
|
||||
icount_bench_round_group,
|
||||
icount_bench_roundf_group,
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ libm_macros::for_each_function! {
|
|||
| fdimf16
|
||||
| floorf128
|
||||
| floorf16
|
||||
| rintf128
|
||||
| rintf16
|
||||
| sqrtf128
|
||||
| sqrtf16
|
||||
| truncf128
|
||||
|
|
|
|||
|
|
@ -170,6 +170,8 @@ libm_macros::for_each_function! {
|
|||
remquof,
|
||||
rint,
|
||||
rintf,
|
||||
rintf128,
|
||||
rintf16,
|
||||
round,
|
||||
roundf,
|
||||
scalbn,
|
||||
|
|
@ -240,17 +242,19 @@ impl_no_round! {
|
|||
|
||||
#[cfg(f16_enabled)]
|
||||
impl_no_round! {
|
||||
fabsf16 => abs_mut;
|
||||
ceilf16 => ceil_mut;
|
||||
fabsf16 => abs_mut;
|
||||
floorf16 => floor_mut;
|
||||
rintf16 => round_even_mut; // FIXME: respect rounding mode
|
||||
truncf16 => trunc_mut;
|
||||
}
|
||||
|
||||
#[cfg(f128_enabled)]
|
||||
impl_no_round! {
|
||||
fabsf128 => abs_mut;
|
||||
ceilf128 => ceil_mut;
|
||||
fabsf128 => abs_mut;
|
||||
floorf128 => floor_mut;
|
||||
rintf128 => round_even_mut; // FIXME: respect rounding mode
|
||||
truncf128 => trunc_mut;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,9 +89,11 @@ libm_macros::for_each_function! {
|
|||
fdimf16,
|
||||
floorf128,
|
||||
floorf16,
|
||||
rintf128,
|
||||
rintf16,
|
||||
sqrtf128,
|
||||
sqrtf16,
|
||||
truncf128,
|
||||
truncf16,
|
||||
sqrtf16,
|
||||
sqrtf128,
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
|
|||
| fdimf16
|
||||
| floorf128
|
||||
| floorf16
|
||||
| rintf128
|
||||
| rintf16
|
||||
| sqrtf128
|
||||
| sqrtf16
|
||||
| truncf128
|
||||
|
|
|
|||
|
|
@ -654,6 +654,7 @@
|
|||
"src/libm_helper.rs",
|
||||
"src/math/arch/aarch64.rs",
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rint.rs"
|
||||
],
|
||||
"type": "f64"
|
||||
|
|
@ -662,10 +663,25 @@
|
|||
"sources": [
|
||||
"src/math/arch/aarch64.rs",
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rintf.rs"
|
||||
],
|
||||
"type": "f32"
|
||||
},
|
||||
"rintf128": {
|
||||
"sources": [
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rintf128.rs"
|
||||
],
|
||||
"type": "f128"
|
||||
},
|
||||
"rintf16": {
|
||||
"sources": [
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rintf16.rs"
|
||||
],
|
||||
"type": "f16"
|
||||
},
|
||||
"round": {
|
||||
"sources": [
|
||||
"src/libm_helper.rs",
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ remquo
|
|||
remquof
|
||||
rint
|
||||
rintf
|
||||
rintf128
|
||||
rintf16
|
||||
round
|
||||
roundf
|
||||
scalbn
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ mod copysign;
|
|||
mod fabs;
|
||||
mod fdim;
|
||||
mod floor;
|
||||
mod rint;
|
||||
mod sqrt;
|
||||
mod trunc;
|
||||
|
||||
|
|
@ -11,5 +12,6 @@ pub use copysign::copysign;
|
|||
pub use fabs::fabs;
|
||||
pub use fdim::fdim;
|
||||
pub use floor::floor;
|
||||
pub use rint::rint;
|
||||
pub use sqrt::sqrt;
|
||||
pub use trunc::trunc;
|
||||
|
|
|
|||
72
library/compiler-builtins/libm/src/math/generic/rint.rs
Normal file
72
library/compiler-builtins/libm/src/math/generic/rint.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/* origin: musl src/math/rint.c */
|
||||
|
||||
use super::super::Float;
|
||||
|
||||
pub fn rint<F: Float>(x: F) -> F {
|
||||
let toint = F::ONE / F::EPSILON;
|
||||
let e = x.exp();
|
||||
let positive = x.is_sign_positive();
|
||||
|
||||
// On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise,
|
||||
// the excess precission from x87 would cause an incorrect final result.
|
||||
let use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64;
|
||||
|
||||
if e >= F::EXP_BIAS + F::SIG_BITS {
|
||||
// No fractional part; exact result can be returned.
|
||||
x
|
||||
} else {
|
||||
// Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode.
|
||||
let y = if positive {
|
||||
let tmp = if use_force { force_eval!(x) } else { x } + toint;
|
||||
(if use_force { force_eval!(tmp) } else { tmp } - toint)
|
||||
} else {
|
||||
let tmp = if use_force { force_eval!(x) } else { x } - toint;
|
||||
(if use_force { force_eval!(tmp) } else { tmp } + toint)
|
||||
};
|
||||
|
||||
if y == F::ZERO {
|
||||
// A zero result takes the sign of the input.
|
||||
if positive { F::ZERO } else { F::NEG_ZERO }
|
||||
} else {
|
||||
y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn zeroes_f32() {
|
||||
assert_biteq!(rint(0.0_f32), 0.0_f32);
|
||||
assert_biteq!(rint(-0.0_f32), -0.0_f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_f32() {
|
||||
assert_biteq!(rint(-1.0_f32), -1.0);
|
||||
assert_biteq!(rint(2.8_f32), 3.0);
|
||||
assert_biteq!(rint(-0.5_f32), -0.0);
|
||||
assert_biteq!(rint(0.5_f32), 0.0);
|
||||
assert_biteq!(rint(-1.5_f32), -2.0);
|
||||
assert_biteq!(rint(1.5_f32), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zeroes_f64() {
|
||||
assert_biteq!(rint(0.0_f64), 0.0_f64);
|
||||
assert_biteq!(rint(-0.0_f64), -0.0_f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_f64() {
|
||||
assert_biteq!(rint(-1.0_f64), -1.0);
|
||||
assert_biteq!(rint(2.8_f64), 3.0);
|
||||
assert_biteq!(rint(-0.5_f64), -0.0);
|
||||
assert_biteq!(rint(0.5_f64), 0.0);
|
||||
assert_biteq!(rint(-1.5_f64), -2.0);
|
||||
assert_biteq!(rint(1.5_f64), 2.0);
|
||||
}
|
||||
}
|
||||
|
|
@ -346,6 +346,7 @@ cfg_if! {
|
|||
mod fabsf16;
|
||||
mod fdimf16;
|
||||
mod floorf16;
|
||||
mod rintf16;
|
||||
mod sqrtf16;
|
||||
mod truncf16;
|
||||
|
||||
|
|
@ -354,6 +355,7 @@ cfg_if! {
|
|||
pub use self::fabsf16::fabsf16;
|
||||
pub use self::fdimf16::fdimf16;
|
||||
pub use self::floorf16::floorf16;
|
||||
pub use self::rintf16::rintf16;
|
||||
pub use self::sqrtf16::sqrtf16;
|
||||
pub use self::truncf16::truncf16;
|
||||
}
|
||||
|
|
@ -366,6 +368,7 @@ cfg_if! {
|
|||
mod fabsf128;
|
||||
mod fdimf128;
|
||||
mod floorf128;
|
||||
mod rintf128;
|
||||
mod sqrtf128;
|
||||
mod truncf128;
|
||||
|
||||
|
|
@ -374,6 +377,7 @@ cfg_if! {
|
|||
pub use self::fabsf128::fabsf128;
|
||||
pub use self::fdimf128::fdimf128;
|
||||
pub use self::floorf128::floorf128;
|
||||
pub use self::rintf128::rintf128;
|
||||
pub use self::sqrtf128::sqrtf128;
|
||||
pub use self::truncf128::truncf128;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rint(x: f64) -> f64 {
|
||||
select_implementation! {
|
||||
|
|
@ -9,51 +10,5 @@ pub fn rint(x: f64) -> f64 {
|
|||
args: x,
|
||||
}
|
||||
|
||||
let one_over_e = 1.0 / f64::EPSILON;
|
||||
let as_u64: u64 = x.to_bits();
|
||||
let exponent: u64 = (as_u64 >> 52) & 0x7ff;
|
||||
let is_positive = (as_u64 >> 63) == 0;
|
||||
if exponent >= 0x3ff + 52 {
|
||||
x
|
||||
} else {
|
||||
let ans = if is_positive {
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let x = force_eval!(x);
|
||||
let xplusoneovere = x + one_over_e;
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let xplusoneovere = force_eval!(xplusoneovere);
|
||||
xplusoneovere - one_over_e
|
||||
} else {
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let x = force_eval!(x);
|
||||
let xminusoneovere = x - one_over_e;
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let xminusoneovere = force_eval!(xminusoneovere);
|
||||
xminusoneovere + one_over_e
|
||||
};
|
||||
|
||||
if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans }
|
||||
}
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::rint;
|
||||
|
||||
#[test]
|
||||
fn negative_zero() {
|
||||
assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check() {
|
||||
assert_eq!(rint(-1.0), -1.0);
|
||||
assert_eq!(rint(2.8), 3.0);
|
||||
assert_eq!(rint(-0.5), -0.0);
|
||||
assert_eq!(rint(0.5), 0.0);
|
||||
assert_eq!(rint(-1.5), -2.0);
|
||||
assert_eq!(rint(1.5), 2.0);
|
||||
}
|
||||
super::generic::rint(x)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf(x: f32) -> f32 {
|
||||
select_implementation! {
|
||||
|
|
@ -9,51 +10,5 @@ pub fn rintf(x: f32) -> f32 {
|
|||
args: x,
|
||||
}
|
||||
|
||||
let one_over_e = 1.0 / f32::EPSILON;
|
||||
let as_u32: u32 = x.to_bits();
|
||||
let exponent: u32 = (as_u32 >> 23) & 0xff;
|
||||
let is_positive = (as_u32 >> 31) == 0;
|
||||
if exponent >= 0x7f + 23 {
|
||||
x
|
||||
} else {
|
||||
let ans = if is_positive {
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let x = force_eval!(x);
|
||||
let xplusoneovere = x + one_over_e;
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let xplusoneovere = force_eval!(xplusoneovere);
|
||||
xplusoneovere - one_over_e
|
||||
} else {
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let x = force_eval!(x);
|
||||
let xminusoneovere = x - one_over_e;
|
||||
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
|
||||
let xminusoneovere = force_eval!(xminusoneovere);
|
||||
xminusoneovere + one_over_e
|
||||
};
|
||||
|
||||
if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans }
|
||||
}
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::rintf;
|
||||
|
||||
#[test]
|
||||
fn negative_zero() {
|
||||
assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check() {
|
||||
assert_eq!(rintf(-1.0), -1.0);
|
||||
assert_eq!(rintf(2.8), 3.0);
|
||||
assert_eq!(rintf(-0.5), -0.0);
|
||||
assert_eq!(rintf(0.5), 0.0);
|
||||
assert_eq!(rintf(-1.5), -2.0);
|
||||
assert_eq!(rintf(1.5), 2.0);
|
||||
}
|
||||
super::generic::rint(x)
|
||||
}
|
||||
|
|
|
|||
5
library/compiler-builtins/libm/src/math/rintf128.rs
Normal file
5
library/compiler-builtins/libm/src/math/rintf128.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf128(x: f128) -> f128 {
|
||||
super::generic::rint(x)
|
||||
}
|
||||
5
library/compiler-builtins/libm/src/math/rintf16.rs
Normal file
5
library/compiler-builtins/libm/src/math/rintf16.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf16(x: f16) -> f16 {
|
||||
super::generic::rint(x)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue