trig_const/
floor.rs

1/* SPDX-License-Identifier: MIT
2 * origin: musl src/math/floor.c */
3
4//! Generic `floor` algorithm.
5//!
6//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because
7//! performance seems to be better (based on icount) and it does not seem to experience rounding
8//! errors on i386.
9
10const SIG_BITS: u32 = 52;
11const BITS: u32 = 64;
12const EXP_BITS: u32 = BITS - SIG_BITS - 1;
13const EXP_SAT: u32 = (1 << EXP_BITS) - 1;
14const EXP_BIAS: u32 = EXP_SAT >> 1;
15const SIG_MASK: u64 = 4503599627370495;
16
17pub const fn floor(x: f64) -> f64 {
18    let zero = 0;
19
20    let mut ix = x.to_bits();
21    let e = exp_unbiased(x);
22
23    // If the represented value has no fractional part, no truncation is needed.
24    if e >= SIG_BITS as i32 {
25        return x;
26    }
27
28    if e >= 0 {
29        // |x| >= 1.0
30        let m = SIG_MASK >> unsigned(e);
31        if ix & m == zero {
32            // Portion to be masked is already zero; no adjustment needed.
33            return x;
34        }
35
36        if x.is_sign_negative() {
37            ix += m;
38        }
39
40        ix &= !m;
41        f64::from_bits(ix)
42    } else if x.is_sign_positive() {
43        // 0.0 <= x < 1.0; rounding down goes toward +0.0.
44        0.0
45    } else if ix << 1 != zero {
46        // -1.0 < x < 0.0; rounding down goes toward -1.0.
47        -1.0
48    } else {
49        // -0.0 remains unchanged
50        x
51    }
52}
53
54const fn ex(x: f64) -> u32 {
55    (x.to_bits() >> SIG_BITS) as u32 & EXP_SAT
56}
57
58const fn signed(x: u32) -> i32 {
59    x as i32
60}
61
62const fn unsigned(x: i32) -> u32 {
63    x as u32
64}
65
66const fn exp_unbiased(x: f64) -> i32 {
67    signed(ex(x)) - EXP_BIAS as i32
68}