#[cfg(feature = "integer")]
use crate::Integer;
#[cfg(feature = "rational")]
use crate::Rational;
use crate::{
ext::xmpfr::{self, ordering1},
float::{
big::{IExpIncomplete, UExpIncomplete},
Special,
},
Float,
};
use az::Az;
use core::cmp::Ordering;
use gmp_mpfr_sys::mpfr;
impl PartialEq for Float {
#[inline]
fn eq(&self, other: &Float) -> bool {
unsafe { mpfr::equal_p(self.as_raw(), other.as_raw()) != 0 }
}
}
impl PartialOrd for Float {
#[inline]
fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
unsafe {
match mpfr::unordered_p(self.as_raw(), other.as_raw()) {
0 => Some(ordering1(mpfr::cmp(self.as_raw(), other.as_raw()))),
_ => None,
}
}
}
#[inline]
fn lt(&self, other: &Float) -> bool {
unsafe { mpfr::less_p(self.as_raw(), other.as_raw()) != 0 }
}
#[inline]
fn le(&self, other: &Float) -> bool {
unsafe { mpfr::lessequal_p(self.as_raw(), other.as_raw()) != 0 }
}
#[inline]
fn gt(&self, other: &Float) -> bool {
unsafe { mpfr::greater_p(self.as_raw(), other.as_raw()) != 0 }
}
#[inline]
fn ge(&self, other: &Float) -> bool {
unsafe { mpfr::greaterequal_p(self.as_raw(), other.as_raw()) != 0 }
}
}
macro_rules! cmp {
($T:ty) => {
impl PartialEq<$T> for Float {
#[inline]
fn eq(&self, other: &$T) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl PartialEq<Float> for $T {
#[inline]
fn eq(&self, other: &Float) -> bool {
other.partial_cmp(self) == Some(Ordering::Equal)
}
}
impl PartialOrd<Float> for $T {
#[inline]
fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
};
}
macro_rules! cmp_i {
($T:ty, $eval:expr) => {
cmp! { $T }
impl PartialOrd<$T> for Float {
#[inline]
fn partial_cmp(&self, other: &$T) -> Option<Ordering> {
if self.is_nan() {
None
} else {
Some(ordering1($eval(self.as_raw(), other)))
}
}
}
};
}
macro_rules! cmp_f {
($T:ty, $eval:expr) => {
cmp! { $T }
impl PartialOrd<$T> for Float {
#[inline]
fn partial_cmp(&self, other: &$T) -> Option<Ordering> {
if self.is_nan() || other.is_nan() {
None
} else {
Some(ordering1($eval(self.as_raw(), other)))
}
}
}
};
}
#[cfg(feature = "integer")]
cmp_i! { Integer, |f, t: &Integer| unsafe { mpfr::cmp_z(f, t.as_raw()) } }
#[cfg(feature = "rational")]
cmp_i! { Rational, |f, t: &Rational| unsafe { mpfr::cmp_q(f, t.as_raw()) } }
cmp_i! { i8, |f, &t: &i8| unsafe { mpfr::cmp_si(f, t.into()) } }
cmp_i! { i16, |f, &t: &i16| unsafe { mpfr::cmp_si(f, t.into()) } }
cmp_i! { i32, |f, &t: &i32| unsafe { mpfr::cmp_si(f, t.into()) } }
cmp_i! { i64, |f, &t: &i64| unsafe { xmpfr::cmp_i64(f, t) } }
cmp_i! { i128, |f, &t: &i128| unsafe { xmpfr::cmp_i128(f, t) } }
#[cfg(target_pointer_width = "32")]
cmp_i! { isize, |f, &t: &isize| unsafe { mpfr::cmp_si(f, t.az()) } }
#[cfg(target_pointer_width = "64")]
cmp_i! { isize, |f, &t: &isize| unsafe { xmpfr::cmp_i64(f, t.az()) } }
cmp_i! { u8, |f, &t: &u8| unsafe { mpfr::cmp_ui(f, t.into()) } }
cmp_i! { u16, |f, &t: &u16| unsafe { mpfr::cmp_ui(f, t.into()) } }
cmp_i! { u32, |f, &t: &u32| unsafe { mpfr::cmp_ui(f, t.into()) } }
cmp_i! { u64, |f, &t: &u64| unsafe { xmpfr::cmp_u64(f, t) } }
cmp_i! { u128, |f, &t: &u128| unsafe { xmpfr::cmp_u128(f, t) } }
#[cfg(target_pointer_width = "32")]
cmp_i! { usize, |f, &t: &usize| unsafe { mpfr::cmp_ui(f, t.az()) } }
#[cfg(target_pointer_width = "64")]
cmp_i! { usize, |f, &t: &usize| unsafe { xmpfr::cmp_u64(f, t.az()) } }
cmp_f! { f32, |f, &t: &f32| unsafe { mpfr::cmp_d(f, t.into()) } }
cmp_f! { f64, |f, &t: &f64| unsafe { mpfr::cmp_d(f, t) } }
cmp! { Special }
impl PartialOrd<Special> for Float {
#[inline]
fn partial_cmp(&self, other: &Special) -> Option<Ordering> {
if self.is_nan() {
return None;
}
match *other {
Special::Zero | Special::NegZero => self.cmp0(),
Special::Infinity => {
if self.is_sign_positive() && self.is_infinite() {
Some(Ordering::Equal)
} else {
Some(Ordering::Less)
}
}
Special::NegInfinity => {
if self.is_sign_negative() && self.is_infinite() {
Some(Ordering::Equal)
} else {
Some(Ordering::Greater)
}
}
Special::Nan => None,
_ => unreachable!(),
}
}
}
cmp! { UExpIncomplete }
cmp! { IExpIncomplete }
#[cfg(test)]
mod tests {
#[cfg(feature = "rational")]
use crate::Rational;
use crate::{
float::{self, FreeCache, Special},
Assign, Float,
};
use core::cmp::Ordering;
#[cfg(feature = "integer")]
use {crate::Integer, core::str::FromStr};
fn check_cmp_prim<T>(s: &[T], against: &[Float])
where
Float: Assign<T> + PartialEq<T> + PartialOrd<T>,
T: Copy + PartialEq<Float> + PartialOrd<Float>,
{
for op in s {
let fop = Float::with_val(150, *op);
for b in against {
assert_eq!(b.eq(op), PartialEq::<Float>::eq(b, &fop));
assert_eq!(op.eq(b), PartialEq::<Float>::eq(&fop, b));
assert_eq!(b.eq(op), op.eq(b));
assert_eq!(b.partial_cmp(op), PartialOrd::<Float>::partial_cmp(b, &fop));
assert_eq!(op.partial_cmp(b), PartialOrd::<Float>::partial_cmp(&fop, b));
assert_eq!(b.partial_cmp(op), op.partial_cmp(b).map(Ordering::reverse));
}
}
}
#[cfg(feature = "integer")]
fn check_cmp_big<'a, T>(s: &'a [T], against: &[Float])
where
Float: Assign<&'a T> + PartialEq<T> + PartialOrd<T>,
T: PartialEq<Float> + PartialOrd<Float>,
{
for op in s {
let fop = Float::with_val(150, op);
for b in against {
assert_eq!(b.eq(op), PartialEq::<Float>::eq(b, &fop));
assert_eq!(op.eq(b), PartialEq::<Float>::eq(&fop, b));
assert_eq!(b.eq(op), op.eq(b));
assert_eq!(b.partial_cmp(op), PartialOrd::<Float>::partial_cmp(b, &fop));
assert_eq!(op.partial_cmp(b), PartialOrd::<Float>::partial_cmp(&fop, b));
assert_eq!(b.partial_cmp(op), op.partial_cmp(b).map(Ordering::reverse));
}
}
}
#[test]
fn check_cmp_others() {
use crate::tests::{F32, F64, I128, I32, I64, U128, U32, U64};
let large = [
Float::with_val(20, Special::Zero),
Float::with_val(20, Special::NegZero),
Float::with_val(20, Special::Infinity),
Float::with_val(20, Special::NegInfinity),
Float::with_val(20, Special::Nan),
Float::with_val(20, 1),
Float::with_val(20, -1),
Float::with_val(20, 999_999e100),
Float::with_val(20, 999_999e-100),
Float::with_val(20, -999_999e100),
Float::with_val(20, -999_999e-100),
];
#[cfg(feature = "integer")]
let z = &[
Integer::from(0),
Integer::from(1),
Integer::from(-1),
Integer::from_str("-1000000000000").unwrap(),
Integer::from_str("1000000000000").unwrap(),
];
#[cfg(feature = "rational")]
let q = &[
Rational::from(0),
Rational::from(1),
Rational::from(-1),
Rational::from_str("-1000000000000/33333333333").unwrap(),
Rational::from_str("1000000000000/33333333333").unwrap(),
];
let against = large
.iter()
.cloned()
.chain(U32.iter().map(|&x| Float::with_val(20, x)))
.chain(I32.iter().map(|&x| Float::with_val(20, x)))
.chain(U64.iter().map(|&x| Float::with_val(20, x)))
.chain(I64.iter().map(|&x| Float::with_val(20, x)))
.chain(U128.iter().map(|&x| Float::with_val(20, x)))
.chain(I128.iter().map(|&x| Float::with_val(20, x)))
.chain(F32.iter().map(|&x| Float::with_val(20, x)))
.chain(F64.iter().map(|&x| Float::with_val(20, x)))
.collect::<Vec<Float>>();
#[cfg(feature = "integer")]
let mut against = against;
#[cfg(feature = "integer")]
against.extend(z.iter().map(|x| Float::with_val(20, x)));
#[cfg(feature = "rational")]
against.extend(q.iter().map(|x| Float::with_val(20, x)));
check_cmp_prim(U32, &against);
check_cmp_prim(I32, &against);
check_cmp_prim(U64, &against);
check_cmp_prim(I64, &against);
check_cmp_prim(U128, &against);
check_cmp_prim(I128, &against);
check_cmp_prim(F32, &against);
check_cmp_prim(F64, &against);
#[cfg(feature = "integer")]
check_cmp_big(z, &against);
#[cfg(feature = "rational")]
check_cmp_big(q, &against);
float::free_cache(FreeCache::All);
}
}