use std::cmp::Ordering;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use derive_new::new;
#[derive(new, Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub struct f64eq(f64);
impl fmt::Display for f64eq {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::LowerExp for f64eq {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerExp::fmt(&self.0, f)
}
}
impl PartialEq for f64eq {
fn eq(&self, other: &f64eq) -> bool {
if self.0.is_nan() {
return other.0.is_nan();
} else if other.0.is_nan() {
return false;
}
if (self.0 == 0f64 || self.0 == -0f64) || (other.0 == 0f64 || other.0 == -0f64) {
return true;
}
self.0.partial_cmp(&other.0).unwrap() == Ordering::Equal
}
}
impl Eq for f64eq {}
impl Hash for f64eq {
fn hash<H: Hasher>(&self, hasher: &mut H) {
if self.0 == -0. {
(0f64).to_bits().hash(hasher);
return;
}
self.0.to_bits().hash(hasher);
}
}
impl From<f64> for f64eq {
fn from(v: f64) -> Self {
f64eq(v)
}
}
#[cfg(test)]
mod tests {
use std::collections::hash_map::RandomState;
use std::f64::consts::PI;
use std::f64::{INFINITY, NAN, NEG_INFINITY};
use std::hash::{BuildHasher, Hash, Hasher};
use lazy_static::lazy_static;
use super::f64eq;
#[test]
fn test_eq() {
assert_eq!(f64eq::new(42.), f64eq::new(42.));
assert_eq!(f64eq::new(PI), f64eq::new(PI));
assert_ne!(f64eq::new(42.), f64eq::new(-42.));
assert_eq!(f64eq::new(0.), f64eq::new(-0.));
assert_eq!(f64eq::new(INFINITY), f64eq::new(INFINITY));
assert_ne!(f64eq::new(INFINITY), f64eq::new(NEG_INFINITY));
assert_ne!(f64eq::new(42.), f64eq::new(NAN));
assert_ne!(f64eq::new(NAN), f64eq::new(42.));
assert_eq!(f64eq::new(NAN), f64eq::new(NAN));
}
lazy_static! {
static ref RANDOM: RandomState = RandomState::new();
}
fn get_hash(x: f64eq) -> u64 {
let mut hasher = RANDOM.build_hasher();
x.hash(&mut hasher);
hasher.finish()
}
#[test]
fn test_hash() {
assert_eq!(get_hash(f64eq::new(42.)), get_hash(f64eq::new(42.)));
assert_eq!(get_hash(f64eq::new(PI)), get_hash(f64eq::new(PI)));
assert_ne!(get_hash(f64eq::new(42.)), get_hash(f64eq::new(-42.)));
assert_eq!(get_hash(f64eq::new(0.)), get_hash(f64eq::new(-0.)));
assert_eq!(get_hash(f64eq::new(INFINITY)), get_hash(f64eq::new(INFINITY)));
assert_ne!(get_hash(f64eq::new(INFINITY)), get_hash(f64eq::new(NEG_INFINITY)));
assert_ne!(get_hash(f64eq::new(42.)), get_hash(f64eq::new(NAN)));
assert_ne!(get_hash(f64eq::new(NAN)), get_hash(f64eq::new(42.)));
assert_eq!(get_hash(f64eq::new(NAN)), get_hash(f64eq::new(NAN)));
}
}