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