const_soft_float/soft_f64/
floor.rs

1use super::{
2    helpers::{eq, gt},
3    SoftF64,
4};
5
6const TOINT: SoftF64 = SoftF64(1.0).div(SoftF64(f64::EPSILON));
7
8/// Floor (f64)
9///
10/// Finds the nearest integer less than or equal to `x`.
11pub const fn floor(x: SoftF64) -> SoftF64 {
12    let ui = x.to_bits();
13    let e = ((ui >> 52) & 0x7ff) as i32;
14
15    if (e >= 0x3ff + 52) || eq(x, SoftF64::ZERO) {
16        return x;
17    }
18    /* y = int(x) - x, where int(x) is an integer neighbor of x */
19    let y = if (ui >> 63) != 0 {
20        x.sub(TOINT).add(TOINT).sub(x)
21    } else {
22        x.add(TOINT).sub(TOINT).sub(x)
23    };
24    /* special case because of non-nearest rounding modes */
25    if e < 0x3ff {
26        return if (ui >> 63) != 0 {
27            SoftF64(-1.0)
28        } else {
29            SoftF64::ZERO
30        };
31    }
32    if gt(y, SoftF64::ZERO) {
33        x.add(y).sub(SoftF64::ONE)
34    } else {
35        x.add(y)
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn sanity_check() {
45        assert_eq!(floor(SoftF64(1.1)).0, 1.0);
46        assert_eq!(floor(SoftF64(2.9)).0, 2.0);
47    }
48
49    /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor
50    #[test]
51    fn spec_tests() {
52        // Not Asserted: that the current rounding mode has no effect.
53        assert!(floor(SoftF64(f64::NAN)).0.is_nan());
54        for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY]
55            .iter()
56            .copied()
57        {
58            assert_eq!(floor(SoftF64(f)).0, f);
59        }
60    }
61}