use core::cmp::Ordering;
use crate::env::{ExcFlags, FloatEnv};
use crate::parts::{unpack, FloatClass};
use crate::types::{
BFloat16, Float128, Float16, Float32, Float64, FloatFormat, FloatX80,
};
pub fn compare<F: FloatFormat>(
a: F,
b: F,
env: &mut FloatEnv,
) -> Option<Ordering> {
let pa = unpack::<F>(a);
let pb = unpack::<F>(b);
if pa.is_nan() || pb.is_nan() {
env.raise(ExcFlags::INVALID);
return None;
}
compare_ordered(&pa, &pb)
}
pub fn compare_quiet<F: FloatFormat>(
a: F,
b: F,
env: &mut FloatEnv,
) -> Option<Ordering> {
let pa = unpack::<F>(a);
let pb = unpack::<F>(b);
if pa.is_nan() || pb.is_nan() {
if pa.cls == FloatClass::SNaN || pb.cls == FloatClass::SNaN {
env.raise(ExcFlags::INVALID);
}
return None;
}
compare_ordered(&pa, &pb)
}
fn compare_ordered(
a: &crate::parts::FloatParts,
b: &crate::parts::FloatParts,
) -> Option<Ordering> {
if a.cls == FloatClass::Zero && b.cls == FloatClass::Zero {
return Some(Ordering::Equal);
}
if a.sign != b.sign {
return if a.sign {
Some(Ordering::Less)
} else {
Some(Ordering::Greater)
};
}
let raw_ord = if a.cls == FloatClass::Inf && b.cls == FloatClass::Inf {
Ordering::Equal
} else if a.cls == FloatClass::Inf {
Ordering::Greater
} else if b.cls == FloatClass::Inf {
Ordering::Less
} else if a.cls == FloatClass::Zero {
Ordering::Less
} else if b.cls == FloatClass::Zero {
Ordering::Greater
} else {
match a.exp.cmp(&b.exp) {
Ordering::Equal => a.frac.cmp(&b.frac),
other => other,
}
};
if a.sign {
Some(raw_ord.reverse())
} else {
Some(raw_ord)
}
}
pub fn eq<F: FloatFormat>(a: F, b: F, env: &mut FloatEnv) -> bool {
compare_quiet::<F>(a, b, env) == Some(Ordering::Equal)
}
pub fn lt<F: FloatFormat>(a: F, b: F, env: &mut FloatEnv) -> bool {
compare::<F>(a, b, env) == Some(Ordering::Less)
}
pub fn le<F: FloatFormat>(a: F, b: F, env: &mut FloatEnv) -> bool {
matches!(
compare::<F>(a, b, env),
Some(Ordering::Less) | Some(Ordering::Equal)
)
}
macro_rules! impl_compare {
($ty:ty) => {
impl $ty {
pub fn compare(
self,
other: Self,
env: &mut FloatEnv,
) -> Option<Ordering> {
compare::<Self>(self, other, env)
}
pub fn compare_quiet(
self,
other: Self,
env: &mut FloatEnv,
) -> Option<Ordering> {
compare_quiet::<Self>(self, other, env)
}
pub fn eq(self, other: Self, env: &mut FloatEnv) -> bool {
eq::<Self>(self, other, env)
}
pub fn lt(self, other: Self, env: &mut FloatEnv) -> bool {
lt::<Self>(self, other, env)
}
pub fn le(self, other: Self, env: &mut FloatEnv) -> bool {
le::<Self>(self, other, env)
}
}
};
}
impl_compare!(Float16);
impl_compare!(BFloat16);
impl_compare!(Float32);
impl_compare!(Float64);
impl_compare!(Float128);
impl_compare!(FloatX80);