Merge pull request rust-lang/libm#427 from tgross35/generic-trunc
Add `truncf16` and `truncf128`
This commit is contained in:
commit
9b835374fc
16 changed files with 120 additions and 56 deletions
|
|
@ -157,6 +157,8 @@ no_mangle! {
|
|||
tgammaf(x: f32) -> f32;
|
||||
trunc(x: f64) -> f64;
|
||||
truncf(x: f32) -> f32;
|
||||
truncf128(x: f128) -> f128;
|
||||
truncf16(x: f16) -> f16;
|
||||
y0(x: f64) -> f64;
|
||||
y0f(x: f32) -> f32;
|
||||
y1(x: 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,
|
||||
&["fabsf16"],
|
||||
&["fabsf16", "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,
|
||||
&["fabsf128"],
|
||||
&["fabsf128", "truncf128"],
|
||||
),
|
||||
(
|
||||
// `(f16, f16) -> f16`
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ libm_macros::for_each_function! {
|
|||
exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)),
|
||||
|
||||
// Musl does not provide `f16` and `f128` functions
|
||||
copysignf16 | copysignf128 | fabsf16 | fabsf128 => (false, None),
|
||||
copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => (false, None),
|
||||
|
||||
// By default we never skip (false) and always have a musl function available
|
||||
_ => (false, Some(musl_math_sys::MACRO_FN_NAME))
|
||||
|
|
|
|||
|
|
@ -199,3 +199,13 @@ impl HasDomain<f16> for crate::op::fabsf16::Routine {
|
|||
impl HasDomain<f128> for crate::op::fabsf128::Routine {
|
||||
const DOMAIN: Domain<f128> = Domain::<f128>::UNBOUNDED;
|
||||
}
|
||||
|
||||
#[cfg(f16_enabled)]
|
||||
impl HasDomain<f16> for crate::op::truncf16::Routine {
|
||||
const DOMAIN: Domain<f16> = Domain::<f16>::UNBOUNDED;
|
||||
}
|
||||
|
||||
#[cfg(f128_enabled)]
|
||||
impl HasDomain<f128> for crate::op::truncf128::Routine {
|
||||
const DOMAIN: Domain<f128> = Domain::<f128>::UNBOUNDED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ libm_macros::for_each_function! {
|
|||
lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf,
|
||||
remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf,
|
||||
copysignf16, copysignf128, fabsf16, fabsf128,
|
||||
truncf16, truncf128,
|
||||
],
|
||||
fn_extra: match MACRO_FN_NAME {
|
||||
// Remap function names that are different between mpfr and libm
|
||||
|
|
@ -202,11 +203,13 @@ impl_no_round! {
|
|||
#[cfg(f16_enabled)]
|
||||
impl_no_round! {
|
||||
fabsf16 => abs_mut;
|
||||
truncf16 => trunc_mut;
|
||||
}
|
||||
|
||||
#[cfg(f128_enabled)]
|
||||
impl_no_round! {
|
||||
fabsf128 => abs_mut;
|
||||
truncf128 => trunc_mut;
|
||||
}
|
||||
|
||||
/// Some functions are difficult to do in a generic way. Implement them here.
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ where
|
|||
libm_macros::for_each_function! {
|
||||
callback: musl_rand_tests,
|
||||
// Musl does not support `f16` and `f128` on all platforms.
|
||||
skip: [copysignf16, copysignf128, fabsf16, fabsf128],
|
||||
skip: [copysignf16, copysignf128, fabsf16, fabsf128, truncf16, truncf128],
|
||||
attributes: [
|
||||
#[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586
|
||||
[exp10, exp10f, exp2, exp2f, rint]
|
||||
|
|
@ -146,5 +146,7 @@ libm_macros::for_each_function! {
|
|||
// Not provided by musl
|
||||
fabsf16,
|
||||
fabsf128,
|
||||
truncf16,
|
||||
truncf128,
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
|
|||
emit_types: [CFn, RustFn, RustArgs],
|
||||
extra: (basis, op, inputs),
|
||||
fn_extra: match MACRO_FN_NAME {
|
||||
copysignf16 | copysignf128 | fabsf16 | fabsf128 => None,
|
||||
copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => None,
|
||||
_ => Some(musl_math_sys::MACRO_FN_NAME)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -743,6 +743,7 @@
|
|||
"sources": [
|
||||
"src/libm_helper.rs",
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/generic/trunc.rs",
|
||||
"src/math/trunc.rs"
|
||||
],
|
||||
"type": "f64"
|
||||
|
|
@ -750,10 +751,25 @@
|
|||
"truncf": {
|
||||
"sources": [
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/generic/trunc.rs",
|
||||
"src/math/truncf.rs"
|
||||
],
|
||||
"type": "f32"
|
||||
},
|
||||
"truncf128": {
|
||||
"sources": [
|
||||
"src/math/generic/trunc.rs",
|
||||
"src/math/truncf128.rs"
|
||||
],
|
||||
"type": "f128"
|
||||
},
|
||||
"truncf16": {
|
||||
"sources": [
|
||||
"src/math/generic/trunc.rs",
|
||||
"src/math/truncf16.rs"
|
||||
],
|
||||
"type": "f16"
|
||||
},
|
||||
"y0": {
|
||||
"sources": [
|
||||
"src/libm_helper.rs",
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ tgamma
|
|||
tgammaf
|
||||
trunc
|
||||
truncf
|
||||
truncf128
|
||||
truncf16
|
||||
y0
|
||||
y0f
|
||||
y1
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
mod copysign;
|
||||
mod fabs;
|
||||
mod trunc;
|
||||
|
||||
pub use copysign::copysign;
|
||||
pub use fabs::fabs;
|
||||
pub use trunc::trunc;
|
||||
|
|
|
|||
57
library/compiler-builtins/libm/src/math/generic/trunc.rs
Normal file
57
library/compiler-builtins/libm/src/math/generic/trunc.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* SPDX-License-Identifier: MIT
|
||||
* origin: musl src/math/trunc.c */
|
||||
|
||||
use super::super::{Float, Int, IntTy, MinInt};
|
||||
|
||||
pub fn trunc<F: Float>(x: F) -> F {
|
||||
let mut xi: F::Int = x.to_bits();
|
||||
let e: i32 = x.exp_unbiased();
|
||||
|
||||
// C1: The represented value has no fractional part, so no truncation is needed
|
||||
if e >= F::SIG_BITS as i32 {
|
||||
return x;
|
||||
}
|
||||
|
||||
let mask = if e < 0 {
|
||||
// C2: If the exponent is negative, the result will be zero so we mask out everything
|
||||
// except the sign.
|
||||
F::SIGN_MASK
|
||||
} else {
|
||||
// C3: Otherwise, we mask out the last `e` bits of the significand.
|
||||
!(F::SIG_MASK >> e.unsigned())
|
||||
};
|
||||
|
||||
// C4: If the to-be-masked-out portion is already zero, we have an exact result
|
||||
if (xi & !mask) == IntTy::<F>::ZERO {
|
||||
return x;
|
||||
}
|
||||
|
||||
// C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the
|
||||
// result, and return.
|
||||
force_eval!(x + F::MAX);
|
||||
xi &= mask;
|
||||
F::from_bits(xi)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sanity_check() {
|
||||
assert_biteq!(trunc(1.1f32), 1.0);
|
||||
assert_biteq!(trunc(1.1f64), 1.0);
|
||||
|
||||
// C1
|
||||
assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23"));
|
||||
assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52"));
|
||||
assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23"));
|
||||
assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52"));
|
||||
|
||||
// C2
|
||||
assert_biteq!(trunc(hf32!("0x1p-1")), 0.0);
|
||||
assert_biteq!(trunc(hf64!("0x1p-1")), 0.0);
|
||||
assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0);
|
||||
assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0);
|
||||
}
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ use self::rem_pio2::rem_pio2;
|
|||
use self::rem_pio2_large::rem_pio2_large;
|
||||
use self::rem_pio2f::rem_pio2f;
|
||||
#[allow(unused_imports)]
|
||||
use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt};
|
||||
use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, IntTy, MinInt};
|
||||
|
||||
// Public modules
|
||||
mod acos;
|
||||
|
|
@ -343,9 +343,11 @@ cfg_if! {
|
|||
if #[cfg(f16_enabled)] {
|
||||
mod copysignf16;
|
||||
mod fabsf16;
|
||||
mod truncf16;
|
||||
|
||||
pub use self::copysignf16::copysignf16;
|
||||
pub use self::fabsf16::fabsf16;
|
||||
pub use self::truncf16::truncf16;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,9 +355,11 @@ cfg_if! {
|
|||
if #[cfg(f128_enabled)] {
|
||||
mod copysignf128;
|
||||
mod fabsf128;
|
||||
mod truncf128;
|
||||
|
||||
pub use self::copysignf128::copysignf128;
|
||||
pub use self::fabsf128::fabsf128;
|
||||
pub use self::truncf128::truncf128;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use core::f64;
|
||||
|
||||
/// Rounds the number toward 0 to the closest integral value (f64).
|
||||
///
|
||||
/// This effectively removes the decimal part of the number, leaving the integral part.
|
||||
|
|
@ -11,31 +9,5 @@ pub fn trunc(x: f64) -> f64 {
|
|||
args: x,
|
||||
}
|
||||
|
||||
let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120
|
||||
|
||||
let mut i: u64 = x.to_bits();
|
||||
let mut e: i64 = ((i >> 52) & 0x7ff) as i64 - 0x3ff + 12;
|
||||
let m: u64;
|
||||
|
||||
if e >= 52 + 12 {
|
||||
return x;
|
||||
}
|
||||
if e < 12 {
|
||||
e = 1;
|
||||
}
|
||||
m = -1i64 as u64 >> e;
|
||||
if (i & m) == 0 {
|
||||
return x;
|
||||
}
|
||||
force_eval!(x + x1p120);
|
||||
i &= !m;
|
||||
f64::from_bits(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn sanity_check() {
|
||||
assert_eq!(super::trunc(1.1), 1.0);
|
||||
}
|
||||
super::generic::trunc(x)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use core::f32;
|
||||
|
||||
/// Rounds the number toward 0 to the closest integral value (f32).
|
||||
///
|
||||
/// This effectively removes the decimal part of the number, leaving the integral part.
|
||||
|
|
@ -11,25 +9,7 @@ pub fn truncf(x: f32) -> f32 {
|
|||
args: x,
|
||||
}
|
||||
|
||||
let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120
|
||||
|
||||
let mut i: u32 = x.to_bits();
|
||||
let mut e: i32 = ((i >> 23) & 0xff) as i32 - 0x7f + 9;
|
||||
let m: u32;
|
||||
|
||||
if e >= 23 + 9 {
|
||||
return x;
|
||||
}
|
||||
if e < 9 {
|
||||
e = 1;
|
||||
}
|
||||
m = -1i32 as u32 >> e;
|
||||
if (i & m) == 0 {
|
||||
return x;
|
||||
}
|
||||
force_eval!(x + x1p120);
|
||||
i &= !m;
|
||||
f32::from_bits(i)
|
||||
super::generic::trunc(x)
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
|
|
|
|||
7
library/compiler-builtins/libm/src/math/truncf128.rs
Normal file
7
library/compiler-builtins/libm/src/math/truncf128.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/// Rounds the number toward 0 to the closest integral value (f128).
|
||||
///
|
||||
/// This effectively removes the decimal part of the number, leaving the integral part.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn truncf128(x: f128) -> f128 {
|
||||
super::generic::trunc(x)
|
||||
}
|
||||
7
library/compiler-builtins/libm/src/math/truncf16.rs
Normal file
7
library/compiler-builtins/libm/src/math/truncf16.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/// Rounds the number toward 0 to the closest integral value (f16).
|
||||
///
|
||||
/// This effectively removes the decimal part of the number, leaving the integral part.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn truncf16(x: f16) -> f16 {
|
||||
super::generic::trunc(x)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue