use super::{
helpers::{eq, gt},
F64,
};
const TOINT: F64 = f64!(1.0).div(f64!(f64::EPSILON));
pub const fn floor(x: F64) -> F64 {
let ui = x.to_bits();
let e = ((ui >> 52) & 0x7ff) as i32;
if (e >= 0x3ff + 52) || eq(x, F64::ZERO) {
return x;
}
let y = if (ui >> 63) != 0 {
x.sub(TOINT).add(TOINT).sub(x)
} else {
x.add(TOINT).sub(TOINT).sub(x)
};
if e < 0x3ff {
return if (ui >> 63) != 0 {
f64!(-1.0)
} else {
F64::ZERO
};
}
if gt(y, F64::ZERO) {
x.add(y).sub(F64::ONE)
} else {
x.add(y)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_check() {
assert_eq!(floor(f64!(1.1)), f64!(1.0));
assert_eq!(floor(f64!(2.9)), f64!(2.0));
}
#[test]
fn spec_tests() {
assert!(floor(f64!(f64::NAN)).to_native_f64().is_nan());
for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY]
.iter()
.copied()
{
assert_eq!(floor(F64::from_native_f64(f)).to_native_f64(), f);
}
}
}