float_next_after/
lib.rs

1#![no_std]
2
3/// Returns the next representable float value in the direction of y
4///
5/// This function is strict and will step to the very next representable floating point,
6/// even if that value is subnormal.
7///
8/// Base assumptions:
9///
10/// self == y -> return y
11///
12/// self >= positive infinity -> return positive infinity
13///
14/// self <= negative infinity -> return negative infinity
15///
16/// self == NaN -> return NaN
17///
18/// self == -0.0 and y == 0.0 -> return positive 0.0
19///
20/// self == -0.0 and y == positive infinity -> 5e-324
21///
22/// # Examples
23///
24/// ```
25/// use float_next_after::NextAfter;
26///
27/// // Large numbers
28/// let big_num = 16237485966.00000437586943_f64;
29/// let next = big_num.next_after(std::f64::INFINITY);
30/// assert_eq!(next, 16237485966.000006_f64);
31///
32/// // Expected handling of 1.0
33/// let one = 1_f64;
34/// let next = one.next_after(std::f64::INFINITY);
35/// assert_eq!(next, 1_f64 + std::f64::EPSILON);
36///
37/// // Tiny (negative) numbers
38/// let zero = 0_f32;
39/// let next = zero.next_after(std::f32::NEG_INFINITY);
40/// assert_eq!(next, -0.000000000000000000000000000000000000000000001_f32);
41///
42/// // Equal source/dest (even -0 == 0)
43/// let zero = 0_f64;
44/// let next = zero.next_after(-0_f64);
45/// assert_eq!(next, -0_f64);
46/// ```
47///
48/// # Safety
49///
50/// This trait uses the ToBits and FromBits functions from f32 and f64.
51/// Those both use unsafe { mem::transmute(self) } / unsafe { mem::transmute(v) }
52/// to convert a f32/f64 to u32/u64.  The docs for those functions claim they are safe
53/// and that "the safety issues with sNaN were overblown!"
54///
55pub trait NextAfter {
56    #[must_use]
57    fn next_after(self, y: Self) -> Self;
58}
59
60macro_rules! impl_next_after {
61    ($float_type:ty, $module:ident, $minimum_non_zero:literal) => {
62        use super::NextAfter;
63
64        impl NextAfter for $float_type {
65            fn next_after(self, y: Self) -> Self {
66                // Check first if the input matches a fixed set of values
67                // that receive a pre-calculated response in line with the
68                // stated rules.
69                if let Some(out) = short_circuit_operands(self, y) {
70                    return out;
71                }
72
73                // To get the next float, use trick fXX -> uXX +- 1 -> fXX
74                // increment or decrement depending on same sign.
75                let return_value = if (y > self) == (self > 0.0) {
76                    <$float_type>::from_bits(self.to_bits() + 1)
77                } else {
78                    <$float_type>::from_bits(self.to_bits() - 1)
79                };
80
81                // Note that following the IEEE standard both 0.0 and -0.0 are equal in rust
82                if return_value != 0.0 {
83                    return return_value;
84                }
85
86                // At this point the return number must be zero
87                // so make sure it returns with the input's original sign.
88                copy_sign(return_value, self)
89            }
90        }
91
92        #[inline]
93        fn short_circuit_operands(x: $float_type, y: $float_type) -> Option<$float_type> {
94            // If x and y are equal (also -0.0 == 0.0 in the IEEE standard and rust),
95            // there is nothing further to do
96            if y == x {
97                // The policy is to return y in cases of equality,
98                // this only matters when x = 0.0 and y = -0.0 (or the reverse)
99                return Some(y);
100            }
101
102            // If x or y is NaN return NaN
103            if x.is_nan() || y.is_nan() {
104                return Some(core::$module::NAN);
105            }
106
107            if x.is_infinite() {
108                return Some(x);
109            }
110
111            // If x is (+/-)0 and y is not 0 (see first condition),
112            // return the hard coded value closest to zero and use
113            // positive/negative sign to move it in the proper direction
114            if x == 0.0 {
115                return Some(copy_sign($minimum_non_zero, y));
116            }
117
118            None
119        }
120
121        #[inline]
122        fn copy_sign(x: $float_type, y: $float_type) -> $float_type {
123            if x.is_sign_positive() == y.is_sign_positive() {
124                x
125            } else {
126                -x
127            }
128        }
129    };
130}
131
132macro_rules! tests {
133    ($float_type:ty, $module:ident, $smallest_pos:expr, $largest_neg:expr, $next_before_one:expr, $sequential_large_numbers:expr) => {
134        #[cfg(test)]
135        mod tests {
136            use super::{copy_sign, NextAfter};
137
138            const POS_INFINITY: $float_type = core::$module::INFINITY;
139            const NEG_INFINITY: $float_type = core::$module::NEG_INFINITY;
140            const POS_ZERO: $float_type = 0.0;
141            const NEG_ZERO: $float_type = -0.0;
142
143            // Note: Not the same as fXX::MIN_POSITIVE, because that is only the min *normal* number.
144            const SMALLEST_POS: $float_type = $smallest_pos;
145            const LARGEST_NEG: $float_type = $largest_neg;
146            const LARGEST_POS: $float_type = core::$module::MAX;
147            const SMALLEST_NEG: $float_type = core::$module::MIN;
148
149            const POS_ONE: $float_type = 1.0;
150            const NEG_ONE: $float_type = -1.0;
151            const NEXT_LARGER_THAN_ONE: $float_type = 1.0 + core::$module::EPSILON;
152            const NEXT_SMALLER_THAN_ONE: $float_type = $next_before_one;
153
154            const SEQUENTIAL_LARGE_NUMBERS: ($float_type, $float_type) = $sequential_large_numbers;
155
156            const NAN: $float_type = core::$module::NAN;
157
158            fn is_positive_zero(x: $float_type) -> bool {
159                x.to_bits() == POS_ZERO.to_bits()
160            }
161
162            fn is_negative_zero(x: $float_type) -> bool {
163                x.to_bits() == NEG_ZERO.to_bits()
164            }
165
166            #[test]
167            fn test_copy_sign() {
168                assert_eq!(copy_sign(POS_ONE, POS_ZERO), POS_ONE);
169                assert_eq!(copy_sign(NEG_ONE, POS_ZERO), POS_ONE);
170                assert_eq!(copy_sign(POS_ONE, NEG_ZERO), NEG_ONE);
171                assert_eq!(copy_sign(NEG_ONE, NEG_ZERO), NEG_ONE);
172            }
173
174            #[test]
175            fn verify_constants() {
176                assert_ne!(POS_ZERO.to_bits(), NEG_ZERO.to_bits());
177                assert!(SMALLEST_POS > POS_ZERO);
178                assert!(LARGEST_NEG < NEG_ZERO);
179                assert!(!SMALLEST_POS.is_normal());
180                assert!(!LARGEST_NEG.is_normal());
181            }
182
183            #[test]
184            fn next_larger_than_0() {
185                assert_eq!(POS_ZERO.next_after(POS_INFINITY), SMALLEST_POS);
186                assert_eq!(NEG_ZERO.next_after(POS_INFINITY), SMALLEST_POS);
187            }
188
189            #[test]
190            fn next_smaller_than_0() {
191                assert_eq!(POS_ZERO.next_after(NEG_INFINITY), LARGEST_NEG);
192                assert_eq!(NEG_ZERO.next_after(NEG_INFINITY), LARGEST_NEG);
193            }
194
195            #[test]
196            fn step_towards_zero() {
197                // For steps towards zero, the sign of the zero reflects the direction
198                // from where zero was approached.
199                assert!(is_positive_zero(SMALLEST_POS.next_after(POS_ZERO)));
200                assert!(is_positive_zero(SMALLEST_POS.next_after(NEG_ZERO)));
201                assert!(is_positive_zero(SMALLEST_POS.next_after(NEG_INFINITY)));
202                assert!(is_negative_zero(LARGEST_NEG.next_after(NEG_ZERO)));
203                assert!(is_negative_zero(LARGEST_NEG.next_after(POS_ZERO)));
204                assert!(is_negative_zero(LARGEST_NEG.next_after(POS_INFINITY)));
205            }
206
207            #[test]
208            fn special_case_signed_zeros() {
209                // For a non-zero dest, stepping away from either POS_ZERO or NEG_ZERO
210                // has a non-zero result. Only if the destination itself points to the
211                // "other zero", the next_after call performs a zero sign switch.
212                assert!(is_negative_zero(POS_ZERO.next_after(NEG_ZERO)));
213                assert!(is_positive_zero(NEG_ZERO.next_after(POS_ZERO)));
214            }
215
216            #[test]
217            fn nextafter_around_one() {
218                assert_eq!(POS_ONE.next_after(POS_INFINITY), NEXT_LARGER_THAN_ONE);
219                assert_eq!(POS_ONE.next_after(NEG_INFINITY), NEXT_SMALLER_THAN_ONE);
220                assert_eq!(NEG_ONE.next_after(NEG_INFINITY), -NEXT_LARGER_THAN_ONE);
221                assert_eq!(NEG_ONE.next_after(POS_INFINITY), -NEXT_SMALLER_THAN_ONE);
222            }
223
224            #[test]
225            fn nextafter_for_big_positive_number() {
226                let (lo, hi) = SEQUENTIAL_LARGE_NUMBERS;
227                assert_eq!(lo.next_after(POS_INFINITY), hi);
228                assert_eq!(hi.next_after(NEG_INFINITY), lo);
229                assert_eq!(lo.next_after(hi), hi);
230                assert_eq!(hi.next_after(lo), lo);
231            }
232
233            #[test]
234            fn nextafter_for_small_negative_number() {
235                let (lo, hi) = SEQUENTIAL_LARGE_NUMBERS;
236                let (lo, hi) = (-lo, -hi);
237                assert_eq!(lo.next_after(NEG_INFINITY), hi);
238                assert_eq!(hi.next_after(POS_INFINITY), lo);
239                assert_eq!(lo.next_after(hi), hi);
240                assert_eq!(hi.next_after(lo), lo);
241            }
242
243            #[test]
244            fn step_to_largest_is_possible() {
245                let smaller = LARGEST_POS.next_after(NEG_INFINITY);
246                assert_eq!(smaller.next_after(POS_INFINITY), LARGEST_POS);
247                let smaller = SMALLEST_NEG.next_after(POS_INFINITY);
248                assert_eq!(smaller.next_after(NEG_INFINITY), SMALLEST_NEG);
249            }
250
251            #[test]
252            fn jump_to_infinity() {
253                // Incrementing the max representable number has to go to infinity.
254                assert_eq!(LARGEST_POS.next_after(POS_INFINITY), POS_INFINITY);
255                assert_eq!(SMALLEST_NEG.next_after(NEG_INFINITY), NEG_INFINITY);
256            }
257
258            #[test]
259            fn stays_at_infinity() {
260                // Once infinity is reached, there is not going back to normal numbers
261                assert_eq!(POS_INFINITY.next_after(NEG_INFINITY), POS_INFINITY);
262                assert_eq!(NEG_INFINITY.next_after(POS_INFINITY), NEG_INFINITY);
263            }
264
265            #[test]
266            fn returns_nan_for_any_nan_involved() {
267                assert!(NAN.next_after(POS_ONE).is_nan());
268                assert!(POS_ONE.next_after(NAN).is_nan());
269                assert!(NAN.next_after(NAN).is_nan());
270            }
271
272            #[test]
273            fn returns_identity_for_equal_dest() {
274                let values = [
275                    POS_ZERO,
276                    NEG_ZERO,
277                    POS_ONE,
278                    NEG_ONE,
279                    SEQUENTIAL_LARGE_NUMBERS.0,
280                    SEQUENTIAL_LARGE_NUMBERS.1,
281                    POS_INFINITY,
282                    NEG_INFINITY,
283                    SMALLEST_POS,
284                    LARGEST_NEG,
285                    LARGEST_POS,
286                    SMALLEST_NEG,
287                ];
288                for x in values.iter() {
289                    assert_eq!(x.next_after(*x), *x);
290                }
291            }
292
293            #[test]
294            fn can_successfully_roundtrip() {
295                let values = [
296                    POS_ONE,
297                    NEG_ONE,
298                    SEQUENTIAL_LARGE_NUMBERS.0,
299                    SEQUENTIAL_LARGE_NUMBERS.1,
300                    SMALLEST_POS,
301                    LARGEST_NEG,
302                ];
303                for orig in values.to_vec() {
304                    assert_eq!(orig.next_after(POS_INFINITY).next_after(NEG_INFINITY), orig);
305                    assert_eq!(orig.next_after(NEG_INFINITY).next_after(POS_INFINITY), orig);
306
307                    let upper = orig.next_after(POS_INFINITY);
308                    let lower = orig.next_after(NEG_INFINITY);
309
310                    assert_eq!(orig.next_after(upper).next_after(lower), orig);
311                    assert_eq!(orig.next_after(lower).next_after(upper), orig);
312                }
313            }
314        }
315    };
316}
317
318mod f64 {
319    impl_next_after!(f64, f64, 5e-324);
320
321    tests!(
322        f64,
323        f64,
324        5e-324,
325        -5e-324,
326        0.999_999_999_999_999_9,
327        (16_237_485_966.000_004, 16_237_485_966.000_006)
328    );
329}
330
331mod f32 {
332    impl_next_after!(f32, f32, 1e-45);
333
334    tests!(
335        f32,
336        f32,
337        1e-45,
338        -1e-45,
339        0.999_999_94,
340        (1.230_000_1e34, 1.230_000_3e34)
341    );
342}