use std::cmp::Ordering;
use std::num::{FpCategory};
use super::{Ulps, ApproxEqUlps};
#[deprecated(since = "0.5.0", note="types that can implement this can implement PartialOrd")]
pub trait ApproxOrdUlps: ApproxEqUlps {
fn approx_cmp_ulps(&self, other: &Self, ulps: <<Self as ApproxEqUlps>::Flt as Ulps>::U)
-> Ordering;
#[inline]
fn approx_lt_ulps(&self, other: &Self, ulps: <<Self as ApproxEqUlps>::Flt as Ulps>::U)
-> bool
{
match self.approx_cmp_ulps(other, ulps) {
Ordering::Less => true,
_ => false,
}
}
#[inline]
fn approx_le_ulps(&self, other: &Self, ulps: <<Self as ApproxEqUlps>::Flt as Ulps>::U)
-> bool
{
match self.approx_cmp_ulps(other, ulps) {
Ordering::Less | Ordering::Equal => true,
_ => false,
}
}
#[inline]
fn approx_gt_ulps(&self, other: &Self, ulps: <<Self as ApproxEqUlps>::Flt as Ulps>::U)
-> bool
{
match self.approx_cmp_ulps(other, ulps) {
Ordering::Greater => true,
_ => false,
}
}
#[inline]
fn approx_ge_ulps(&self, other: &Self, ulps: <<Self as ApproxEqUlps>::Flt as Ulps>::U)
-> bool
{
match self.approx_cmp_ulps(other, ulps) {
Ordering::Greater | Ordering::Equal => true,
_ => false,
}
}
}
#[allow(deprecated)]
impl ApproxOrdUlps for f32 {
fn approx_cmp_ulps(&self, other: &f32, ulps: <<Self as ApproxEqUlps>::Flt as Ulps>::U)
-> Ordering
{
let selfclass = self.classify();
let otherclass = other.classify();
if selfclass==FpCategory::Zero && otherclass==FpCategory::Zero {
return Ordering::Equal;
}
let self_pos = self.is_sign_positive();
let other_pos = other.is_sign_positive();
let udiff: i32 = match (self_pos, other_pos) {
(true, false) => return Ordering::Greater,
(false, true) => return Ordering::Less,
(true, true) => self.ulps(other),
(false, false) => other.ulps(self),
};
match udiff {
x if x < -ulps => Ordering::Less,
x if x >= -ulps && x <= ulps => Ordering::Equal,
x if x > ulps => Ordering::Greater,
_ => unreachable!()
}
}
}
#[test]
#[allow(deprecated)]
fn f32_approx_cmp_test1() {
let f: f32 = 0.1_f32;
let mut sum: f32 = 0.0_f32;
for _ in 0_isize..10_isize { sum += f; }
let product: f32 = f * 10.0_f32;
assert!(sum != product);
println!("Ulps Difference: {}",sum.ulps(&product));
assert!(sum.approx_cmp_ulps(&product,1) == Ordering::Equal);
assert!(sum.approx_cmp_ulps(&product,0) != Ordering::Equal);
assert!(product.approx_cmp_ulps(&sum,0) != Ordering::Equal);
}
#[test]
#[allow(deprecated)]
fn f32_approx_cmp_test2() {
let x: f32 = 1000000_f32;
let y: f32 = 1000000.1_f32;
assert!(x != y);
println!("Ulps Difference: {}",x.ulps(&y));
assert!(x.approx_cmp_ulps(&y,2) == Ordering::Equal);
assert!(x.approx_cmp_ulps(&y,1) == Ordering::Less);
assert!(y.approx_cmp_ulps(&x,1) == Ordering::Greater);
}
#[test]
#[allow(deprecated)]
fn f32_approx_cmp_negatives() {
let x: f32 = -1.0;
let y: f32 = -2.0;
assert!(x.approx_cmp_ulps(&y, 2) == Ordering::Greater);
}
#[test]
#[allow(deprecated)]
fn f32_approx_cmp_vs_partial_cmp() {
let testcases: [u32; 20] = [
0,
0x80000000,
0x00000101,
0x80000101,
0x00001101,
0x80001101,
0x01000101,
0x81000101,
0x01001101,
0x81001101,
0x7F800000,
0xFF800000,
0x7F801101,
0xFF801101,
0x7FC01101,
0xFFC01101,
0x7F801110,
0xFF801110,
0x7FC01110,
0xFFC01110,
];
let mut xf: f32;
let mut yf: f32;
for xbits in testcases.iter() {
for ybits in testcases.iter() {
xf = <f32>::from_bits(*xbits);
yf = <f32>::from_bits(*ybits);
if let Some(ordering) = xf.partial_cmp(&yf) {
if ordering != xf.approx_cmp_ulps(&yf, 0) {
panic!("{} ({:x}) vs {} ({:x}): partial_cmp gives {:?} \
approx_cmp_ulps gives {:?}",
xf, xbits, yf, ybits, ordering , xf.approx_cmp_ulps(&yf, 0));
}
}
}
print!(".");
}
}
#[allow(deprecated)]
impl ApproxOrdUlps for f64 {
fn approx_cmp_ulps(&self, other: &f64, ulps: <<Self as ApproxEqUlps>::Flt as Ulps>::U)
-> Ordering
{
let selfclass = self.classify();
let otherclass = other.classify();
if selfclass==FpCategory::Zero && otherclass==FpCategory::Zero {
return Ordering::Equal;
}
let self_pos = self.is_sign_positive();
let other_pos = other.is_sign_positive();
let udiff: i64 = match (self_pos, other_pos) {
(true, false) => return Ordering::Greater,
(false, true) => return Ordering::Less,
(true, true) => self.ulps(other),
(false, false) => other.ulps(self),
};
match udiff {
x if x < -ulps => Ordering::Less,
x if x >= -ulps && x <= ulps => Ordering::Equal,
x if x > ulps => Ordering::Greater,
_ => unreachable!()
}
}
}
#[test]
#[allow(deprecated)]
fn f64_approx_cmp_ulps_test1() {
let f: f64 = 0.000000001_f64;
let mut sum: f64 = 0.0_f64;
for _ in 0_isize..10_isize { sum += f; }
let product: f64 = f * 10.0_f64;
assert!(sum != product);
println!("Ulps Difference: {}",sum.ulps(&product));
assert!(sum.approx_cmp_ulps(&product,1) == Ordering::Equal);
assert!(sum.approx_cmp_ulps(&product,0) != Ordering::Equal);
assert!(product.approx_cmp_ulps(&sum,0) != Ordering::Equal);
}
#[test]
#[allow(deprecated)]
fn f64_approx_cmp_ulps_test2() {
let x: f64 = 1000000_f64;
let y: f64 = 1000000.0000000003_f64;
assert!(x != y);
println!("Ulps Difference: {}",x.ulps(&y));
assert!(x.approx_cmp_ulps(&y,3) == Ordering::Equal);
assert!(x.approx_cmp_ulps(&y,2) == Ordering::Less);
assert!(y.approx_cmp_ulps(&x,2) == Ordering::Greater);
}
#[test]
#[allow(deprecated)]
fn f64_approx_cmp_ulps_negatives() {
let x: f64 = -1.0;
let y: f64 = -2.0;
assert!(x.approx_cmp_ulps(&y, 2) == Ordering::Greater);
}
#[test]
#[allow(deprecated)]
fn f64_approx_cmp_ulps_vs_partial_cmp() {
let testcases: [u64; 20] = [
0,
0x80000000_00000000,
0x00000010_10000000,
0x80000010_10000000,
0x00000110_10000000,
0x80000110_10000000,
0x01000101_00100100,
0x81000101_00100100,
0x01001101_00100100,
0x81001101_00100100,
0x7FF00000_00000000,
0xFFF00000_00000000,
0x7FF01101_00100100,
0xFFF01101_00100100,
0x7FF81101_00100100,
0xFFF81101_00100100,
0x7FF01110_00100100,
0xFFF01110_00100100,
0x7FF81110_00100100,
0xFFF81110_00100100,
];
let mut xf: f64;
let mut yf: f64;
for xbits in testcases.iter() {
for ybits in testcases.iter() {
xf = <f64>::from_bits(*xbits);
yf = <f64>::from_bits(*ybits);
if let Some(ordering) = xf.partial_cmp(&yf) {
if ordering != xf.approx_cmp_ulps(&yf, 0) {
panic!("{} ({:x}) vs {} ({:x}): partial_cmp gives {:?} \
approx_cmp_ulps gives {:?}",
xf, xbits, yf, ybits, ordering , xf.approx_cmp_ulps(&yf, 0));
}
}
}
print!(".");
}
}