#![no_std]
pub trait NextAfter {
#[must_use]
fn next_after(self, y: Self) -> Self;
}
macro_rules! impl_next_after {
($float_type:ty, $module:ident, $minimum_non_zero:literal) => {
use super::NextAfter;
impl NextAfter for $float_type {
#[inline]
fn next_after(self, y: Self) -> Self {
if let Some(out) = short_circuit_operands(self, y) {
return out;
}
let return_value = if (y > self) == (self > 0.0) {
<$float_type>::from_bits(self.to_bits() + 1)
} else {
<$float_type>::from_bits(self.to_bits() - 1)
};
if return_value != 0.0 {
return return_value;
}
copy_sign(return_value, self)
}
}
#[inline]
fn short_circuit_operands(x: $float_type, y: $float_type) -> Option<$float_type> {
if y == x {
return Some(y);
}
if x.is_nan() || y.is_nan() {
return Some(<$module>::NAN);
}
if x == 0.0 {
return Some(copy_sign($minimum_non_zero, y));
}
None
}
#[inline]
fn copy_sign(x: $float_type, y: $float_type) -> $float_type {
if x.is_sign_positive() == y.is_sign_positive() {
x
} else {
-x
}
}
};
}
macro_rules! tests {
($float_type:ty, $module:ident, $smallest_pos:expr, $largest_neg:expr, $next_before_one:expr, $sequential_large_numbers:expr, $largest_subnormal:expr, $second_smallest_pos:expr, $second_largest_neg:expr) => {
#[cfg(test)]
mod tests {
use super::{copy_sign, NextAfter};
const POS_INFINITY: $float_type = core::$module::INFINITY;
const NEG_INFINITY: $float_type = core::$module::NEG_INFINITY;
const POS_ZERO: $float_type = 0.0;
const NEG_ZERO: $float_type = -0.0;
const SMALLEST_POS: $float_type = $smallest_pos;
const LARGEST_NEG: $float_type = $largest_neg;
const LARGEST_POS: $float_type = core::$module::MAX;
const SMALLEST_NEG: $float_type = core::$module::MIN;
const POS_ONE: $float_type = 1.0;
const NEG_ONE: $float_type = -1.0;
const NEXT_LARGER_THAN_ONE: $float_type = 1.0 + core::$module::EPSILON;
const NEXT_SMALLER_THAN_ONE: $float_type = $next_before_one;
const SEQUENTIAL_LARGE_NUMBERS: ($float_type, $float_type) = $sequential_large_numbers;
const NAN: $float_type = core::$module::NAN;
fn is_positive_zero(x: $float_type) -> bool {
x.to_bits() == POS_ZERO.to_bits()
}
fn is_negative_zero(x: $float_type) -> bool {
x.to_bits() == NEG_ZERO.to_bits()
}
#[test]
fn test_copy_sign() {
assert_eq!(copy_sign(POS_ONE, POS_ZERO), POS_ONE);
assert_eq!(copy_sign(NEG_ONE, POS_ZERO), POS_ONE);
assert_eq!(copy_sign(POS_ONE, NEG_ZERO), NEG_ONE);
assert_eq!(copy_sign(NEG_ONE, NEG_ZERO), NEG_ONE);
}
#[test]
fn verify_constants() {
assert_ne!(POS_ZERO.to_bits(), NEG_ZERO.to_bits());
assert!(SMALLEST_POS > POS_ZERO);
assert!(LARGEST_NEG < NEG_ZERO);
assert!(!SMALLEST_POS.is_normal());
assert!(!LARGEST_NEG.is_normal());
}
#[test]
fn next_larger_than_0() {
assert_eq!(POS_ZERO.next_after(POS_INFINITY), SMALLEST_POS);
assert_eq!(NEG_ZERO.next_after(POS_INFINITY), SMALLEST_POS);
}
#[test]
fn next_smaller_than_0() {
assert_eq!(POS_ZERO.next_after(NEG_INFINITY), LARGEST_NEG);
assert_eq!(NEG_ZERO.next_after(NEG_INFINITY), LARGEST_NEG);
}
#[test]
fn step_towards_zero() {
assert!(is_positive_zero(SMALLEST_POS.next_after(POS_ZERO)));
assert!(is_positive_zero(SMALLEST_POS.next_after(NEG_ZERO)));
assert!(is_positive_zero(SMALLEST_POS.next_after(NEG_INFINITY)));
assert!(is_negative_zero(LARGEST_NEG.next_after(NEG_ZERO)));
assert!(is_negative_zero(LARGEST_NEG.next_after(POS_ZERO)));
assert!(is_negative_zero(LARGEST_NEG.next_after(POS_INFINITY)));
}
#[test]
fn special_case_signed_zeros() {
assert!(is_negative_zero(POS_ZERO.next_after(NEG_ZERO)));
assert!(is_positive_zero(NEG_ZERO.next_after(POS_ZERO)));
}
#[test]
fn nextafter_around_one() {
assert_eq!(POS_ONE.next_after(POS_INFINITY), NEXT_LARGER_THAN_ONE);
assert_eq!(POS_ONE.next_after(NEG_INFINITY), NEXT_SMALLER_THAN_ONE);
assert_eq!(NEG_ONE.next_after(NEG_INFINITY), -NEXT_LARGER_THAN_ONE);
assert_eq!(NEG_ONE.next_after(POS_INFINITY), -NEXT_SMALLER_THAN_ONE);
}
#[test]
fn nextafter_for_big_positive_number() {
let (lo, hi) = SEQUENTIAL_LARGE_NUMBERS;
assert_eq!(lo.next_after(POS_INFINITY), hi);
assert_eq!(hi.next_after(NEG_INFINITY), lo);
assert_eq!(lo.next_after(hi), hi);
assert_eq!(hi.next_after(lo), lo);
}
#[test]
fn nextafter_for_small_negative_number() {
let (lo, hi) = SEQUENTIAL_LARGE_NUMBERS;
let (lo, hi) = (-lo, -hi);
assert_eq!(lo.next_after(NEG_INFINITY), hi);
assert_eq!(hi.next_after(POS_INFINITY), lo);
assert_eq!(lo.next_after(hi), hi);
assert_eq!(hi.next_after(lo), lo);
}
#[test]
fn step_to_largest_is_possible() {
let smaller = LARGEST_POS.next_after(NEG_INFINITY);
assert_eq!(smaller.next_after(POS_INFINITY), LARGEST_POS);
let smaller = SMALLEST_NEG.next_after(POS_INFINITY);
assert_eq!(smaller.next_after(NEG_INFINITY), SMALLEST_NEG);
}
#[test]
fn jump_to_infinity() {
assert_eq!(LARGEST_POS.next_after(POS_INFINITY), POS_INFINITY);
assert_eq!(SMALLEST_NEG.next_after(NEG_INFINITY), NEG_INFINITY);
}
#[test]
fn step_away_from_infinity() {
assert_eq!(POS_INFINITY.next_after(NEG_INFINITY), LARGEST_POS);
assert_eq!(NEG_INFINITY.next_after(POS_INFINITY), SMALLEST_NEG);
assert_eq!(POS_INFINITY.next_after(POS_INFINITY), POS_INFINITY);
assert_eq!(NEG_INFINITY.next_after(NEG_INFINITY), NEG_INFINITY);
}
#[test]
fn returns_nan_for_any_nan_involved() {
assert!(NAN.next_after(POS_ONE).is_nan());
assert!(POS_ONE.next_after(NAN).is_nan());
assert!(NAN.next_after(NAN).is_nan());
}
#[test]
fn returns_identity_for_equal_dest() {
let values = [
POS_ZERO,
NEG_ZERO,
POS_ONE,
NEG_ONE,
SEQUENTIAL_LARGE_NUMBERS.0,
SEQUENTIAL_LARGE_NUMBERS.1,
POS_INFINITY,
NEG_INFINITY,
SMALLEST_POS,
LARGEST_NEG,
LARGEST_POS,
SMALLEST_NEG,
];
for x in values.iter() {
assert_eq!(x.next_after(*x), *x);
}
}
#[test]
fn can_successfully_roundtrip() {
let values = [
POS_ONE,
NEG_ONE,
SEQUENTIAL_LARGE_NUMBERS.0,
SEQUENTIAL_LARGE_NUMBERS.1,
SMALLEST_POS,
LARGEST_NEG,
];
for orig in values.to_vec() {
assert_eq!(orig.next_after(POS_INFINITY).next_after(NEG_INFINITY), orig);
assert_eq!(orig.next_after(NEG_INFINITY).next_after(POS_INFINITY), orig);
let upper = orig.next_after(POS_INFINITY);
let lower = orig.next_after(NEG_INFINITY);
assert_eq!(orig.next_after(upper).next_after(lower), orig);
assert_eq!(orig.next_after(lower).next_after(upper), orig);
}
}
#[test]
fn zero_with_finite_target() {
assert_eq!(POS_ZERO.next_after(POS_ONE), SMALLEST_POS);
assert_eq!(POS_ZERO.next_after(NEG_ONE), LARGEST_NEG);
assert_eq!(NEG_ZERO.next_after(POS_ONE), SMALLEST_POS);
assert_eq!(NEG_ZERO.next_after(NEG_ONE), LARGEST_NEG);
}
#[test]
fn infinity_with_finite_target() {
assert_eq!(POS_INFINITY.next_after(POS_ONE), LARGEST_POS);
assert_eq!(POS_INFINITY.next_after(NEG_ONE), LARGEST_POS);
assert_eq!(POS_INFINITY.next_after(POS_ZERO), LARGEST_POS);
assert_eq!(NEG_INFINITY.next_after(POS_ONE), SMALLEST_NEG);
assert_eq!(NEG_INFINITY.next_after(NEG_ONE), SMALLEST_NEG);
assert_eq!(NEG_INFINITY.next_after(NEG_ZERO), SMALLEST_NEG);
}
#[test]
fn normal_subnormal_transition() {
const MIN_POSITIVE_NORMAL: $float_type = core::$module::MIN_POSITIVE;
const LARGEST_SUBNORMAL: $float_type = $largest_subnormal;
assert!(MIN_POSITIVE_NORMAL.is_normal());
assert!(!LARGEST_SUBNORMAL.is_normal());
assert_eq!(
LARGEST_SUBNORMAL.to_bits() + 1,
MIN_POSITIVE_NORMAL.to_bits(),
"LARGEST_SUBNORMAL should be exactly one bit below MIN_POSITIVE_NORMAL"
);
assert_eq!(
MIN_POSITIVE_NORMAL.next_after(NEG_INFINITY),
LARGEST_SUBNORMAL
);
assert_eq!(
LARGEST_SUBNORMAL.next_after(POS_INFINITY),
MIN_POSITIVE_NORMAL
);
assert_eq!(
(-MIN_POSITIVE_NORMAL).next_after(POS_INFINITY),
-LARGEST_SUBNORMAL
);
assert_eq!(
(-LARGEST_SUBNORMAL).next_after(NEG_INFINITY),
-MIN_POSITIVE_NORMAL
);
}
#[test]
fn second_smallest_value() {
const SECOND_SMALLEST_POS: $float_type = $second_smallest_pos;
const SECOND_LARGEST_NEG: $float_type = $second_largest_neg;
assert_eq!(
SMALLEST_POS.to_bits() + 1,
SECOND_SMALLEST_POS.to_bits(),
"SECOND_SMALLEST_POS should be exactly one bit above SMALLEST_POS"
);
assert_eq!(
LARGEST_NEG.to_bits() + 1,
SECOND_LARGEST_NEG.to_bits(),
"SECOND_LARGEST_NEG should be exactly one bit above LARGEST_NEG"
);
assert_eq!(SMALLEST_POS.next_after(POS_INFINITY), SECOND_SMALLEST_POS);
assert_eq!(SECOND_SMALLEST_POS.next_after(NEG_INFINITY), SMALLEST_POS);
assert_eq!(LARGEST_NEG.next_after(NEG_INFINITY), SECOND_LARGEST_NEG);
assert_eq!(SECOND_LARGEST_NEG.next_after(POS_INFINITY), LARGEST_NEG);
}
}
};
}
mod f64 {
impl_next_after!(f64, f64, 5e-324);
tests!(
f64,
f64,
5e-324, -5e-324, 0.999_999_999_999_999_9, (16_237_485_966.000_004, 16_237_485_966.000_006), f64::from_bits(0x000F_FFFF_FFFF_FFFF), f64::from_bits(0x0000_0000_0000_0002), f64::from_bits(0x8000_0000_0000_0002) );
}
mod f32 {
impl_next_after!(f32, f32, 1e-45);
tests!(
f32,
f32,
1e-45, -1e-45, 0.999_999_94, (1.230_000_1e34, 1.230_000_3e34), f32::from_bits(0x007F_FFFF), f32::from_bits(0x0000_0002), f32::from_bits(0x8000_0002) );
}