Add a generic version of trunc
The algorithm is identical for both types, so this is a straightforward routine to port.
This commit is contained in:
parent
dfa694a8e4
commit
6ac06a97e5
5 changed files with 59 additions and 51 deletions
|
|
@ -1,5 +1,7 @@
|
|||
mod copysign;
|
||||
mod fabs;
|
||||
mod trunc;
|
||||
|
||||
pub use copysign::copysign;
|
||||
pub use fabs::fabs;
|
||||
pub use trunc::trunc;
|
||||
|
|
|
|||
54
library/compiler-builtins/libm/src/math/generic/trunc.rs
Normal file
54
library/compiler-builtins/libm/src/math/generic/trunc.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue