1 | use core::f32; |
2 | |
3 | /// Ceil (f32) |
4 | /// |
5 | /// Finds the nearest integer greater than or equal to `x`. |
6 | #[cfg_attr (all(test, assert_no_panic), no_panic::no_panic)] |
7 | pub fn ceilf(x: f32) -> f32 { |
8 | // On wasm32 we know that LLVM's intrinsic will compile to an optimized |
9 | // `f32.ceil` 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::ceilf32(x) } |
14 | } |
15 | } |
16 | let mut ui = x.to_bits(); |
17 | let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; |
18 | |
19 | if e >= 23 { |
20 | return x; |
21 | } |
22 | if e >= 0 { |
23 | let m = 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 | return -0.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!(ceilf(1.1), 2.0); |
53 | assert_eq!(ceilf(2.9), 3.0); |
54 | } |
55 | |
56 | /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil |
57 | #[test ] |
58 | fn spec_tests() { |
59 | // Not Asserted: that the current rounding mode has no effect. |
60 | assert!(ceilf(NAN).is_nan()); |
61 | for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { |
62 | assert_eq!(ceilf(f), f); |
63 | } |
64 | } |
65 | } |
66 | |