use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
#[derive(Default, Debug, Copy, Clone)]
pub struct TotalF32(pub f32);
impl TotalF32 {
fn normalise(&self) -> i32 {
let val = self.0.to_bits() as i32;
val ^ (((val >> 31) as u32) >> 1) as i32
}
}
impl From<TotalF32> for f32 {
fn from(TotalF32(f): TotalF32) -> Self {
f
}
}
impl From<f32> for TotalF32 {
fn from(f: f32) -> Self {
TotalF32(f.into())
}
}
impl PartialEq for TotalF32 {
fn eq(&self, other: &Self) -> bool {
self.normalise() == other.normalise()
}
}
impl Eq for TotalF32 {}
impl PartialOrd for TotalF32 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for TotalF32 {
fn cmp(&self, other: &Self) -> Ordering {
self.normalise().cmp(&other.normalise())
}
}
impl Hash for TotalF32 {
fn hash<H: Hasher>(&self, state: &mut H) {
self.normalise().hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
impl core::ops::Neg for TotalF32 {
type Output = Self;
fn neg(self: Self) -> Self {
let Self(f) = self;
Self(f.neg())
}
}
#[test]
fn test_f32_from_total_f32() {
let f: f32 = 5.0;
let v = TotalF32(f);
let v_f: f32 = v.into();
assert_eq!(v_f, f);
}
#[test]
fn test_total_f32_from_f32() {
let f: f32 = 5.0;
let v: TotalF32 = f.into();
assert_eq!(v, TotalF32(f));
}
#[test]
fn test_total_f32_cmp() {
use core::cmp::Ordering;
fn quiet_bit_mask() -> u32 {
1 << (f32::MANTISSA_DIGITS - 2)
}
fn min_subnorm() -> TotalF32 {
TotalF32(f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0))
}
fn max_subnorm() -> TotalF32 {
TotalF32(f32::MIN_POSITIVE - min_subnorm().0)
}
fn q_nan() -> TotalF32 {
TotalF32(f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()))
}
fn s_nan() -> TotalF32 {
TotalF32(f32::from_bits(
(f32::NAN.to_bits() & !quiet_bit_mask()) + 42,
))
}
assert_eq!(Ordering::Equal, (-q_nan()).cmp(&-q_nan()));
assert_eq!(Ordering::Equal, (-s_nan()).cmp(&-s_nan()));
assert_eq!(
Ordering::Equal,
(TotalF32(-f32::INFINITY)).cmp(&TotalF32(-f32::INFINITY))
);
assert_eq!(
Ordering::Equal,
(TotalF32(-f32::MAX)).cmp(&TotalF32(-f32::MAX))
);
assert_eq!(Ordering::Equal, (TotalF32(-2.5_f32)).cmp(&TotalF32(-2.5)));
assert_eq!(Ordering::Equal, (TotalF32(-1.0_f32)).cmp(&TotalF32(-1.0)));
assert_eq!(Ordering::Equal, (TotalF32(-1.5_f32)).cmp(&TotalF32(-1.5)));
assert_eq!(Ordering::Equal, (TotalF32(-0.5_f32)).cmp(&TotalF32(-0.5)));
assert_eq!(
Ordering::Equal,
(TotalF32(-f32::MIN_POSITIVE)).cmp(&TotalF32(-f32::MIN_POSITIVE))
);
assert_eq!(Ordering::Equal, (-max_subnorm()).cmp(&-max_subnorm()));
assert_eq!(Ordering::Equal, (-min_subnorm()).cmp(&-min_subnorm()));
assert_eq!(Ordering::Equal, (TotalF32(-0.0_f32)).cmp(&TotalF32(-0.0)));
assert_eq!(Ordering::Equal, TotalF32(0.0_f32).cmp(&TotalF32(0.0)));
assert_eq!(Ordering::Equal, min_subnorm().cmp(&min_subnorm()));
assert_eq!(Ordering::Equal, max_subnorm().cmp(&max_subnorm()));
assert_eq!(
Ordering::Equal,
TotalF32(f32::MIN_POSITIVE).cmp(&TotalF32(f32::MIN_POSITIVE))
);
assert_eq!(Ordering::Equal, TotalF32(0.5_f32).cmp(&TotalF32(0.5)));
assert_eq!(Ordering::Equal, TotalF32(1.0_f32).cmp(&TotalF32(1.0)));
assert_eq!(Ordering::Equal, TotalF32(1.5_f32).cmp(&TotalF32(1.5)));
assert_eq!(Ordering::Equal, TotalF32(2.5_f32).cmp(&TotalF32(2.5)));
assert_eq!(Ordering::Equal, TotalF32(f32::MAX).cmp(&TotalF32(f32::MAX)));
assert_eq!(
Ordering::Equal,
TotalF32(f32::INFINITY).cmp(&TotalF32(f32::INFINITY))
);
assert_eq!(Ordering::Equal, s_nan().cmp(&s_nan()));
assert_eq!(Ordering::Equal, q_nan().cmp(&q_nan()));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-f32::INFINITY)));
assert_eq!(
Ordering::Less,
(TotalF32(-f32::INFINITY)).cmp(&TotalF32(-f32::MAX))
);
assert_eq!(Ordering::Less, (TotalF32(-f32::MAX)).cmp(&TotalF32(-2.5)));
assert_eq!(Ordering::Less, (TotalF32(-2.5_f32)).cmp(&TotalF32(-1.5)));
assert_eq!(Ordering::Less, (TotalF32(-1.5_f32)).cmp(&TotalF32(-1.0)));
assert_eq!(Ordering::Less, (TotalF32(-1.0_f32)).cmp(&TotalF32(-0.5)));
assert_eq!(
Ordering::Less,
(TotalF32(-0.5_f32)).cmp(&TotalF32(-f32::MIN_POSITIVE))
);
assert_eq!(
Ordering::Less,
(TotalF32(-f32::MIN_POSITIVE)).cmp(&-max_subnorm())
);
assert_eq!(Ordering::Less, (-max_subnorm()).cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-min_subnorm()).cmp(&TotalF32(-0.0)));
assert_eq!(Ordering::Less, (TotalF32(-0.0_f32)).cmp(&TotalF32(0.0)));
assert_eq!(Ordering::Less, TotalF32(0.0_f32).cmp(&min_subnorm()));
assert_eq!(Ordering::Less, min_subnorm().cmp(&max_subnorm()));
assert_eq!(
Ordering::Less,
max_subnorm().cmp(&TotalF32(f32::MIN_POSITIVE))
);
assert_eq!(
Ordering::Less,
TotalF32(f32::MIN_POSITIVE).cmp(&TotalF32(0.5))
);
assert_eq!(Ordering::Less, TotalF32(0.5_f32).cmp(&TotalF32(1.0)));
assert_eq!(Ordering::Less, TotalF32(1.0_f32).cmp(&TotalF32(1.5)));
assert_eq!(Ordering::Less, TotalF32(1.5_f32).cmp(&TotalF32(2.5)));
assert_eq!(Ordering::Less, TotalF32(2.5_f32).cmp(&TotalF32(f32::MAX)));
assert_eq!(
Ordering::Less,
TotalF32(f32::MAX).cmp(&TotalF32(f32::INFINITY))
);
assert_eq!(Ordering::Less, TotalF32(f32::INFINITY).cmp(&s_nan()));
assert_eq!(Ordering::Less, s_nan().cmp(&q_nan()));
assert_eq!(Ordering::Greater, (-s_nan()).cmp(&-q_nan()));
assert_eq!(Ordering::Greater, (TotalF32(-f32::INFINITY)).cmp(&-s_nan()));
assert_eq!(
Ordering::Greater,
(TotalF32(-f32::MAX)).cmp(&TotalF32(-f32::INFINITY))
);
assert_eq!(
Ordering::Greater,
(TotalF32(-2.5_f32)).cmp(&TotalF32(-f32::MAX))
);
assert_eq!(Ordering::Greater, (TotalF32(-1.5_f32)).cmp(&TotalF32(-2.5)));
assert_eq!(Ordering::Greater, (TotalF32(-1.0_f32)).cmp(&TotalF32(-1.5)));
assert_eq!(Ordering::Greater, (TotalF32(-0.5_f32)).cmp(&TotalF32(-1.0)));
assert_eq!(
Ordering::Greater,
(TotalF32(-f32::MIN_POSITIVE)).cmp(&TotalF32(-0.5))
);
assert_eq!(
Ordering::Greater,
(-max_subnorm()).cmp(&TotalF32(-f32::MIN_POSITIVE))
);
assert_eq!(Ordering::Greater, (-min_subnorm()).cmp(&-max_subnorm()));
assert_eq!(Ordering::Greater, (TotalF32(-0.0_f32)).cmp(&-min_subnorm()));
assert_eq!(Ordering::Greater, TotalF32(0.0_f32).cmp(&TotalF32(-0.0)));
assert_eq!(Ordering::Greater, min_subnorm().cmp(&TotalF32(0.0)));
assert_eq!(Ordering::Greater, max_subnorm().cmp(&min_subnorm()));
assert_eq!(
Ordering::Greater,
TotalF32(f32::MIN_POSITIVE).cmp(&max_subnorm())
);
assert_eq!(
Ordering::Greater,
TotalF32(0.5_f32).cmp(&TotalF32(f32::MIN_POSITIVE))
);
assert_eq!(Ordering::Greater, TotalF32(1.0_f32).cmp(&TotalF32(0.5)));
assert_eq!(Ordering::Greater, TotalF32(1.5_f32).cmp(&TotalF32(1.0)));
assert_eq!(Ordering::Greater, TotalF32(2.5_f32).cmp(&TotalF32(1.5)));
assert_eq!(Ordering::Greater, TotalF32(f32::MAX).cmp(&TotalF32(2.5)));
assert_eq!(
Ordering::Greater,
TotalF32(f32::INFINITY).cmp(&TotalF32(f32::MAX))
);
assert_eq!(Ordering::Greater, s_nan().cmp(&TotalF32(f32::INFINITY)));
assert_eq!(Ordering::Greater, q_nan().cmp(&s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(-f32::INFINITY)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(-f32::MAX)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(-2.5)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(-1.5)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(-1.0)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(-0.5)));
assert_eq!(
Ordering::Less,
(-q_nan()).cmp(&TotalF32(-f32::MIN_POSITIVE))
);
assert_eq!(Ordering::Less, (-q_nan()).cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(-0.0)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(0.0)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(f32::MIN_POSITIVE)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(0.5)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(1.0)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(1.5)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(2.5)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(f32::MAX)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&TotalF32(f32::INFINITY)));
assert_eq!(Ordering::Less, (-q_nan()).cmp(&s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-f32::INFINITY)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-f32::MAX)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-2.5)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-1.5)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-1.0)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-0.5)));
assert_eq!(
Ordering::Less,
(-s_nan()).cmp(&TotalF32(-f32::MIN_POSITIVE))
);
assert_eq!(Ordering::Less, (-s_nan()).cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(-0.0)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(0.0)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(f32::MIN_POSITIVE)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(0.5)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(1.0)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(1.5)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(2.5)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(f32::MAX)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&TotalF32(f32::INFINITY)));
assert_eq!(Ordering::Less, (-s_nan()).cmp(&s_nan()));
}
}