Merge pull request rust-lang/libm#437 from tgross35/generic-floor
Add `floorf16` and `floorf128`
This commit is contained in:
commit
3a96a55e70
17 changed files with 175 additions and 100 deletions
|
|
@ -67,6 +67,8 @@ no_mangle! {
|
|||
cbrtf(x: f32) -> f32;
|
||||
ceil(x: f64) -> f64;
|
||||
ceilf(x: f32) -> f32;
|
||||
ceilf128(x: f128) -> f128;
|
||||
ceilf16(x: f16) -> f16;
|
||||
copysign(x: f64, y: f64) -> f64;
|
||||
copysignf(x: f32, y: f32) -> f32;
|
||||
copysignf128(x: f128, y: f128) -> f128;
|
||||
|
|
@ -97,6 +99,8 @@ no_mangle! {
|
|||
fdimf16(x: f16, y: f16) -> f16;
|
||||
floor(x: f64) -> f64;
|
||||
floorf(x: f32) -> f32;
|
||||
floorf128(x: f128) -> f128;
|
||||
floorf16(x: f16) -> f16;
|
||||
fma(x: f64, y: f64, z: f64) -> f64;
|
||||
fmaf(x: f32, y: f32, z: f32) -> f32;
|
||||
fmax(x: f64, y: f64) -> 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", "sqrtf16", "truncf16"],
|
||||
&["ceilf16", "fabsf16", "floorf16", "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", "sqrtf128", "truncf128"],
|
||||
&["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"],
|
||||
),
|
||||
(
|
||||
// `(f16, f16) -> f16`
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ main!(
|
|||
icount_bench_fdimf16_group,
|
||||
icount_bench_fdimf_group,
|
||||
icount_bench_floor_group,
|
||||
icount_bench_floorf128_group,
|
||||
icount_bench_floorf16_group,
|
||||
icount_bench_floorf_group,
|
||||
icount_bench_fma_group,
|
||||
icount_bench_fmaf_group,
|
||||
|
|
|
|||
|
|
@ -125,8 +125,10 @@ libm_macros::for_each_function! {
|
|||
| fabsf16
|
||||
| fdimf128
|
||||
| fdimf16
|
||||
| sqrtf16
|
||||
| floorf128
|
||||
| floorf16
|
||||
| sqrtf128
|
||||
| sqrtf16
|
||||
| truncf128
|
||||
| truncf16 => (false, None),
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@ libm_macros::for_each_function! {
|
|||
fabsf128,
|
||||
fabsf16,floor,
|
||||
floorf,
|
||||
floorf128,
|
||||
floorf16,
|
||||
fmod,
|
||||
fmodf,
|
||||
frexp,
|
||||
|
|
@ -240,6 +242,7 @@ impl_no_round! {
|
|||
impl_no_round! {
|
||||
fabsf16 => abs_mut;
|
||||
ceilf16 => ceil_mut;
|
||||
floorf16 => floor_mut;
|
||||
truncf16 => trunc_mut;
|
||||
}
|
||||
|
||||
|
|
@ -247,6 +250,7 @@ impl_no_round! {
|
|||
impl_no_round! {
|
||||
fabsf128 => abs_mut;
|
||||
ceilf128 => ceil_mut;
|
||||
floorf128 => floor_mut;
|
||||
truncf128 => trunc_mut;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ libm_macros::for_each_function! {
|
|||
fabsf16,
|
||||
fdimf128,
|
||||
fdimf16,
|
||||
floorf128,
|
||||
floorf16,
|
||||
truncf128,
|
||||
truncf16,
|
||||
sqrtf16,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
|
|||
| fabsf16
|
||||
| fdimf128
|
||||
| fdimf16
|
||||
| floorf128
|
||||
| floorf16
|
||||
| sqrtf128
|
||||
| sqrtf16
|
||||
| truncf128
|
||||
|
|
|
|||
|
|
@ -336,17 +336,33 @@
|
|||
"src/libm_helper.rs",
|
||||
"src/math/arch/i586.rs",
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/floor.rs"
|
||||
"src/math/floor.rs",
|
||||
"src/math/generic/floor.rs"
|
||||
],
|
||||
"type": "f64"
|
||||
},
|
||||
"floorf": {
|
||||
"sources": [
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/floorf.rs"
|
||||
"src/math/floorf.rs",
|
||||
"src/math/generic/floor.rs"
|
||||
],
|
||||
"type": "f32"
|
||||
},
|
||||
"floorf128": {
|
||||
"sources": [
|
||||
"src/math/floorf128.rs",
|
||||
"src/math/generic/floor.rs"
|
||||
],
|
||||
"type": "f128"
|
||||
},
|
||||
"floorf16": {
|
||||
"sources": [
|
||||
"src/math/floorf16.rs",
|
||||
"src/math/generic/floor.rs"
|
||||
],
|
||||
"type": "f16"
|
||||
},
|
||||
"fma": {
|
||||
"sources": [
|
||||
"src/libm_helper.rs",
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ fdimf128
|
|||
fdimf16
|
||||
floor
|
||||
floorf
|
||||
floorf128
|
||||
floorf16
|
||||
fma
|
||||
fmaf
|
||||
fmax
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
#![allow(unreachable_code)]
|
||||
use core::f64;
|
||||
|
||||
const TOINT: f64 = 1. / f64::EPSILON;
|
||||
|
||||
/// Floor (f64)
|
||||
///
|
||||
/// Finds the nearest integer less than or equal to `x`.
|
||||
|
|
@ -15,39 +10,5 @@ pub fn floor(x: f64) -> f64 {
|
|||
args: x,
|
||||
}
|
||||
|
||||
let ui = x.to_bits();
|
||||
let e = ((ui >> 52) & 0x7ff) as i32;
|
||||
|
||||
if (e >= 0x3ff + 52) || (x == 0.) {
|
||||
return x;
|
||||
}
|
||||
/* y = int(x) - x, where int(x) is an integer neighbor of x */
|
||||
let y = if (ui >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x };
|
||||
/* special case because of non-nearest rounding modes */
|
||||
if e < 0x3ff {
|
||||
force_eval!(y);
|
||||
return if (ui >> 63) != 0 { -1. } else { 0. };
|
||||
}
|
||||
if y > 0. { x + y - 1. } else { x + y }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sanity_check() {
|
||||
assert_eq!(floor(1.1), 1.0);
|
||||
assert_eq!(floor(2.9), 2.0);
|
||||
}
|
||||
|
||||
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor
|
||||
#[test]
|
||||
fn spec_tests() {
|
||||
// Not Asserted: that the current rounding mode has no effect.
|
||||
assert!(floor(f64::NAN).is_nan());
|
||||
for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() {
|
||||
assert_eq!(floor(f), f);
|
||||
}
|
||||
}
|
||||
return super::generic::floor(x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use core::f32;
|
||||
|
||||
/// Floor (f32)
|
||||
///
|
||||
/// Finds the nearest integer less than or equal to `x`.
|
||||
|
|
@ -11,53 +9,5 @@ pub fn floorf(x: f32) -> f32 {
|
|||
args: x,
|
||||
}
|
||||
|
||||
let mut ui = x.to_bits();
|
||||
let e = (((ui >> 23) as i32) & 0xff) - 0x7f;
|
||||
|
||||
if e >= 23 {
|
||||
return x;
|
||||
}
|
||||
if e >= 0 {
|
||||
let m: u32 = 0x007fffff >> e;
|
||||
if (ui & m) == 0 {
|
||||
return x;
|
||||
}
|
||||
force_eval!(x + f32::from_bits(0x7b800000));
|
||||
if ui >> 31 != 0 {
|
||||
ui += m;
|
||||
}
|
||||
ui &= !m;
|
||||
} else {
|
||||
force_eval!(x + f32::from_bits(0x7b800000));
|
||||
if ui >> 31 == 0 {
|
||||
ui = 0;
|
||||
} else if ui << 1 != 0 {
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
f32::from_bits(ui)
|
||||
}
|
||||
|
||||
// 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::*;
|
||||
|
||||
#[test]
|
||||
fn sanity_check() {
|
||||
assert_eq!(floorf(0.5), 0.0);
|
||||
assert_eq!(floorf(1.1), 1.0);
|
||||
assert_eq!(floorf(2.9), 2.0);
|
||||
}
|
||||
|
||||
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor
|
||||
#[test]
|
||||
fn spec_tests() {
|
||||
// Not Asserted: that the current rounding mode has no effect.
|
||||
assert!(floorf(f32::NAN).is_nan());
|
||||
for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() {
|
||||
assert_eq!(floorf(f), f);
|
||||
}
|
||||
}
|
||||
return super::generic::floor(x);
|
||||
}
|
||||
|
|
|
|||
7
library/compiler-builtins/libm/src/math/floorf128.rs
Normal file
7
library/compiler-builtins/libm/src/math/floorf128.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/// Floor (f128)
|
||||
///
|
||||
/// Finds the nearest integer less than or equal to `x`.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn floorf128(x: f128) -> f128 {
|
||||
return super::generic::floor(x);
|
||||
}
|
||||
7
library/compiler-builtins/libm/src/math/floorf16.rs
Normal file
7
library/compiler-builtins/libm/src/math/floorf16.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/// Floor (f16)
|
||||
///
|
||||
/// Finds the nearest integer less than or equal to `x`.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn floorf16(x: f16) -> f16 {
|
||||
return super::generic::floor(x);
|
||||
}
|
||||
|
|
@ -31,24 +31,28 @@ pub fn ceil<F: Float>(x: F) -> F {
|
|||
|
||||
// Otherwise, raise an inexact exception.
|
||||
force_eval!(x + F::MAX);
|
||||
|
||||
if x.is_sign_positive() {
|
||||
ix += m;
|
||||
}
|
||||
|
||||
ix &= !m;
|
||||
F::from_bits(ix)
|
||||
} else {
|
||||
// |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0).
|
||||
force_eval!(x + F::MAX);
|
||||
|
||||
if x.is_sign_negative() {
|
||||
// -1.0 < x <= -0.0; rounding up goes toward -0.0.
|
||||
return F::NEG_ZERO;
|
||||
F::NEG_ZERO
|
||||
} else if ix << 1 != zero {
|
||||
// 0.0 < x < 1.0; rounding up goes toward +1.0.
|
||||
return F::ONE;
|
||||
F::ONE
|
||||
} else {
|
||||
// +0.0 remains unchanged
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
F::from_bits(ix)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
106
library/compiler-builtins/libm/src/math/generic/floor.rs
Normal file
106
library/compiler-builtins/libm/src/math/generic/floor.rs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* SPDX-License-Identifier: MIT
|
||||
* origin: musl src/math/floor.c */
|
||||
|
||||
//! Generic `floor` algorithm.
|
||||
//!
|
||||
//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because
|
||||
//! performance seems to be better (based on icount) and it does not seem to experience rounding
|
||||
//! errors on i386.
|
||||
|
||||
use super::super::{Float, Int, IntTy, MinInt};
|
||||
|
||||
pub fn floor<F: Float>(x: F) -> F {
|
||||
let zero = IntTy::<F>::ZERO;
|
||||
|
||||
let mut ix = x.to_bits();
|
||||
let e = x.exp_unbiased();
|
||||
|
||||
// If the represented value has no fractional part, no truncation is needed.
|
||||
if e >= F::SIG_BITS as i32 {
|
||||
return x;
|
||||
}
|
||||
|
||||
if e >= 0 {
|
||||
// |x| >= 1.0
|
||||
|
||||
let m = F::SIG_MASK >> e.unsigned();
|
||||
if ix & m == zero {
|
||||
// Portion to be masked is already zero; no adjustment needed.
|
||||
return x;
|
||||
}
|
||||
|
||||
// Otherwise, raise an inexact exception.
|
||||
force_eval!(x + F::MAX);
|
||||
|
||||
if x.is_sign_negative() {
|
||||
ix += m;
|
||||
}
|
||||
|
||||
ix &= !m;
|
||||
F::from_bits(ix)
|
||||
} else {
|
||||
// |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0).
|
||||
force_eval!(x + F::MAX);
|
||||
|
||||
if x.is_sign_positive() {
|
||||
// 0.0 <= x < 1.0; rounding down goes toward +0.0.
|
||||
F::ZERO
|
||||
} else if ix << 1 != zero {
|
||||
// -1.0 < x < 0.0; rounding down goes toward -1.0.
|
||||
F::NEG_ONE
|
||||
} else {
|
||||
// -0.0 remains unchanged
|
||||
x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Test against https://en.cppreference.com/w/cpp/numeric/math/floor
|
||||
fn spec_test<F: Float>() {
|
||||
// Not Asserted: that the current rounding mode has no effect.
|
||||
for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() {
|
||||
assert_biteq!(floor(f), f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */
|
||||
|
||||
#[test]
|
||||
#[cfg(f16_enabled)]
|
||||
fn spec_tests_f16() {
|
||||
spec_test::<f16>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_f32() {
|
||||
assert_eq!(floor(0.5f32), 0.0);
|
||||
assert_eq!(floor(1.1f32), 1.0);
|
||||
assert_eq!(floor(2.9f32), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spec_tests_f32() {
|
||||
spec_test::<f32>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_f64() {
|
||||
assert_eq!(floor(1.1f64), 1.0);
|
||||
assert_eq!(floor(2.9f64), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spec_tests_f64() {
|
||||
spec_test::<f64>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(f128_enabled)]
|
||||
fn spec_tests_f128() {
|
||||
spec_test::<f128>();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ mod ceil;
|
|||
mod copysign;
|
||||
mod fabs;
|
||||
mod fdim;
|
||||
mod floor;
|
||||
mod sqrt;
|
||||
mod trunc;
|
||||
|
||||
|
|
@ -9,5 +10,6 @@ pub use ceil::ceil;
|
|||
pub use copysign::copysign;
|
||||
pub use fabs::fabs;
|
||||
pub use fdim::fdim;
|
||||
pub use floor::floor;
|
||||
pub use sqrt::sqrt;
|
||||
pub use trunc::trunc;
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ cfg_if! {
|
|||
mod copysignf16;
|
||||
mod fabsf16;
|
||||
mod fdimf16;
|
||||
mod floorf16;
|
||||
mod sqrtf16;
|
||||
mod truncf16;
|
||||
|
||||
|
|
@ -352,6 +353,7 @@ cfg_if! {
|
|||
pub use self::copysignf16::copysignf16;
|
||||
pub use self::fabsf16::fabsf16;
|
||||
pub use self::fdimf16::fdimf16;
|
||||
pub use self::floorf16::floorf16;
|
||||
pub use self::sqrtf16::sqrtf16;
|
||||
pub use self::truncf16::truncf16;
|
||||
}
|
||||
|
|
@ -363,6 +365,7 @@ cfg_if! {
|
|||
mod copysignf128;
|
||||
mod fabsf128;
|
||||
mod fdimf128;
|
||||
mod floorf128;
|
||||
mod sqrtf128;
|
||||
mod truncf128;
|
||||
|
||||
|
|
@ -370,6 +373,7 @@ cfg_if! {
|
|||
pub use self::copysignf128::copysignf128;
|
||||
pub use self::fabsf128::fabsf128;
|
||||
pub use self::fdimf128::fdimf128;
|
||||
pub use self::floorf128::floorf128;
|
||||
pub use self::sqrtf128::sqrtf128;
|
||||
pub use self::truncf128::truncf128;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue