]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | use core::f64; |
2 | ||
3 | const TOINT: f64 = 1. / f64::EPSILON; | |
4 | ||
dc9dc135 XL |
5 | /// Floor (f64) |
6 | /// | |
7 | /// Finds the nearest integer less than or equal to `x`. | |
48663c56 | 8 | #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] |
8faf50e0 | 9 | pub fn floor(x: f64) -> f64 { |
a1dfa0c6 XL |
10 | // On wasm32 we know that LLVM's intrinsic will compile to an optimized |
11 | // `f64.floor` native instruction, so we can leverage this for both code size | |
12 | // and speed. | |
13 | llvm_intrinsically_optimized! { | |
14 | #[cfg(target_arch = "wasm32")] { | |
15 | return unsafe { ::core::intrinsics::floorf64(x) } | |
16 | } | |
17 | } | |
8faf50e0 XL |
18 | let ui = x.to_bits(); |
19 | let e = ((ui >> 52) & 0x7ff) as i32; | |
20 | ||
21 | if (e >= 0x3ff + 52) || (x == 0.) { | |
22 | return x; | |
23 | } | |
24 | /* y = int(x) - x, where int(x) is an integer neighbor of x */ | |
25 | let y = if (ui >> 63) != 0 { | |
26 | x - TOINT + TOINT - x | |
27 | } else { | |
28 | x + TOINT - TOINT - x | |
29 | }; | |
30 | /* special case because of non-nearest rounding modes */ | |
48663c56 | 31 | if e < 0x3ff { |
8faf50e0 XL |
32 | force_eval!(y); |
33 | return if (ui >> 63) != 0 { -1. } else { 0. }; | |
34 | } | |
35 | if y > 0. { | |
36 | x + y - 1. | |
37 | } else { | |
38 | x + y | |
39 | } | |
40 | } | |
60c5eb7d XL |
41 | |
42 | #[cfg(test)] | |
43 | mod tests { | |
44 | use super::*; | |
45 | use core::f64::*; | |
46 | ||
47 | #[test] | |
48 | fn sanity_check() { | |
49 | assert_eq!(floor(1.1), 1.0); | |
50 | assert_eq!(floor(2.9), 2.0); | |
51 | } | |
52 | ||
53 | /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor | |
54 | #[test] | |
55 | fn spec_tests() { | |
56 | // Not Asserted: that the current rounding mode has no effect. | |
57 | assert!(floor(NAN).is_nan()); | |
58 | for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { | |
59 | assert_eq!(floor(f), f); | |
60 | } | |
61 | } | |
62 | } |