1 | use core::f32; |
2 | |
3 | /// Floor (f32) |
4 | /// |
5 | /// Finds the nearest integer less than or equal to `x`. |
6 | #[cfg_attr (all(test, assert_no_panic), no_panic::no_panic)] |
7 | pub fn floorf(x: f32) -> f32 { |
8 | // On wasm32 we know that LLVM's intrinsic will compile to an optimized |
9 | // `f32.floor` native instruction, so we can leverage this for both code size |
10 | // and speed. |
11 | llvm_intrinsically_optimized! { |
12 | #[cfg(target_arch = "wasm32" )] { |
13 | return unsafe { ::core::intrinsics::floorf32(x) } |
14 | } |
15 | } |
16 | let mut ui = x.to_bits(); |
17 | let e = (((ui >> 23) as i32) & 0xff) - 0x7f; |
18 | |
19 | if e >= 23 { |
20 | return x; |
21 | } |
22 | if e >= 0 { |
23 | let m: u32 = 0x007fffff >> e; |
24 | if (ui & m) == 0 { |
25 | return x; |
26 | } |
27 | force_eval!(x + f32::from_bits(0x7b800000)); |
28 | if ui >> 31 != 0 { |
29 | ui += m; |
30 | } |
31 | ui &= !m; |
32 | } else { |
33 | force_eval!(x + f32::from_bits(0x7b800000)); |
34 | if ui >> 31 == 0 { |
35 | ui = 0; |
36 | } else if ui << 1 != 0 { |
37 | return -1.0; |
38 | } |
39 | } |
40 | f32::from_bits(ui) |
41 | } |
42 | |
43 | // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 |
44 | #[cfg (not(target_arch = "powerpc64" ))] |
45 | #[cfg (test)] |
46 | mod tests { |
47 | use super::*; |
48 | use core::f32::*; |
49 | |
50 | #[test ] |
51 | fn sanity_check() { |
52 | assert_eq!(floorf(0.5), 0.0); |
53 | assert_eq!(floorf(1.1), 1.0); |
54 | assert_eq!(floorf(2.9), 2.0); |
55 | } |
56 | |
57 | /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor |
58 | #[test ] |
59 | fn spec_tests() { |
60 | // Not Asserted: that the current rounding mode has no effect. |
61 | assert!(floorf(NAN).is_nan()); |
62 | for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { |
63 | assert_eq!(floorf(f), f); |
64 | } |
65 | } |
66 | } |
67 | |