From 2a0b1ce3796f3cf380277ceeffb6f6b07eb58428 Mon Sep 17 00:00:00 2001 From: ILyoan Date: Tue, 7 May 2013 13:22:23 +0900 Subject: [PATCH 1/2] Add RelativeEq trait --- src/libcore/cmp.rs | 7 +++++++ src/libcore/num/f32.rs | 25 +++++++++++++++++++++++++ src/libcore/num/f64.rs | 25 +++++++++++++++++++++++++ src/libcore/num/float.rs | 26 ++++++++++++++++++++++++++ src/libcore/num/num.rs | 5 +++-- src/libcore/prelude.rs | 3 ++- 6 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 80f1f05961a5d..fffe7ae5aaaa8 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -73,6 +73,13 @@ pub trait ApproxEq { fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool; } +/// Trait for testing relatively equality +pub trait RelativeEq { + fn relative_epsilon() -> Eps; + fn relative_eq(&self, other: &Self) -> bool; + fn relative_eq_eps(&self, other: &Self, relative_epsilon: &Eps) -> bool; +} + #[deriving(Clone, Eq)] pub enum Ordering { Less = -1, Equal = 0, Greater = 1 } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 7c13f136a80f2..52fe016a27532 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -226,6 +226,22 @@ impl ApproxEq for f32 { } } +#[cfg(notest)] +impl RelativeEq for f32 { + #[inline(always)] + fn relative_epsilon() -> f32 { 1.0e-6 } + + #[inline(always)] + fn relative_eq(&self, other: &f32) -> bool { + self.relative_eq_eps(other, &RelativeEq::relative_epsilon::()) + } + + #[inline(always)] + fn relative_eq_eps(&self, other: &f32, relative_epsilon: &f32) -> bool { + (*self - *other).abs() < fmax(self.abs(), other.abs()) * (*relative_epsilon) + } +} + #[cfg(notest)] impl Ord for f32 { #[inline(always)] @@ -990,6 +1006,15 @@ mod tests { assert!(!1.0000001f32.approx_eq_eps(&1f32, &1.0e-7)); } + #[test] + fn test_relative_eq() { + assert!(1.0e8f32.relative_eq(&1.0e8f32)); + assert!(0.9999999e8f32.relative_eq(&1.0e8f32)); + assert!(1.00001e8f32.relative_eq_eps(&1.0e8f32, &1.0e-5)); + assert!(1.000001e8f32.relative_eq_eps(&1.0e8f32, &1.0e-6)); + assert!(!1.000001e8f32.relative_eq_eps(&1.0e8f32, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index e5f10c23ecd87..cd4cc6a41ff10 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -249,6 +249,22 @@ impl ApproxEq for f64 { } } +#[cfg(notest)] +impl RelativeEq for f64 { + #[inline(always)] + fn relative_epsilon() -> f64 { 1.0e-6 } + + #[inline(always)] + fn relative_eq(&self, other: &f64) -> bool { + self.relative_eq_eps(other, &RelativeEq::relative_epsilon::()) + } + + #[inline(always)] + fn relative_eq_eps(&self, other: &f64, relative_epsilon: &f64) -> bool { + (*self - *other).abs() < fmax(self.abs(), other.abs()) * (*relative_epsilon) + } +} + #[cfg(notest)] impl Ord for f64 { #[inline(always)] @@ -1037,6 +1053,15 @@ mod tests { assert!(!1.0000001f64.approx_eq_eps(&1f64, &1.0e-7)); } + #[test] + fn test_relative_eq() { + assert!(1.0e8f64.relative_eq(&1.0e8f64)); + assert!(0.9999999e8f64.relative_eq(&1.0e8f64)); + assert!(1.00001e8f64.relative_eq_eps(&1.0e8f64, &1.0e-5)); + assert!(1.000001e8f64.relative_eq_eps(&1.0e8f64, &1.0e-6)); + assert!(!1.000001e8f64.relative_eq_eps(&1.0e8f64, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index a548165326396..d0a3f391f4f2d 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -387,6 +387,23 @@ impl ApproxEq for float { } } +#[cfg(notest)] +impl RelativeEq for float { + #[inline(always)] + fn relative_epsilon() -> float { 1.0e-6 } + + #[inline(always)] + fn relative_eq(&self, other: &float) -> bool { + self.relative_eq_eps(other, &RelativeEq::relative_epsilon::()) + } + + #[inline(always)] + fn relative_eq_eps(&self, other: &float, relative_epsilon: &float) -> bool { + (*self - *other).abs() < + fmax(self.abs() as f64, other.abs() as f64) as float * (*relative_epsilon) + } +} + #[cfg(notest)] impl Ord for float { #[inline(always)] @@ -1001,6 +1018,15 @@ mod tests { assert!(!1.0000001f.approx_eq_eps(&1f, &1.0e-7)); } + #[test] + fn test_relative_eq() { + assert!(1.0e8f.relative_eq(&1.0e8f)); + assert!(0.9999999e8f.relative_eq(&1.0e8f)); + assert!(1.00001e8f.relative_eq_eps(&1.0e8f, &1.0e-5)); + assert!(1.000001e8f.relative_eq_eps(&1.0e8f, &1.0e-6)); + assert!(!1.000001e8f.relative_eq_eps(&1.0e8f, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index caa14ea802f6c..574e7737f56d4 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -9,7 +9,7 @@ // except according to those terms. //! An interface for numeric types -use cmp::{Eq, ApproxEq, Ord}; +use cmp::{Eq, ApproxEq, RelativeEq, Ord}; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; @@ -241,7 +241,8 @@ pub trait Int: Integer pub trait Float: Real + Signed + Primitive - + ApproxEq { + + ApproxEq + + RelativeEq { // FIXME (#5527): These should be associated constants fn NaN() -> Self; fn infinity() -> Self; diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 10b36d38d43ae..6b02418437db1 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -28,7 +28,8 @@ pub use io::{print, println}; /* Reexported types and traits */ pub use clone::Clone; -pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; +pub use cmp::{Eq, ApproxEq, RelativeEq, Ord, TotalEq, TotalOrd, Ordering}; +pub use cmp::{Less, Equal, Greater, Equiv}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; From 49524cd598191facedea1dd2d21239812972f747 Mon Sep 17 00:00:00 2001 From: ILyoan Date: Tue, 7 May 2013 14:50:57 +0900 Subject: [PATCH 2/2] Add tests for RelativeEq --- src/test/run-pass/issue-5316.rs | 19 +++++++++++++++++++ src/test/run-pass/trait-inheritance-num.rs | 2 +- src/test/run-pass/trait-inheritance-num2.rs | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/issue-5316.rs diff --git a/src/test/run-pass/issue-5316.rs b/src/test/run-pass/issue-5316.rs new file mode 100644 index 0000000000000..33f12716c63d1 --- /dev/null +++ b/src/test/run-pass/issue-5316.rs @@ -0,0 +1,19 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that merely having lifetime parameters is not +// enough for trans to consider this as non-monomorphic, +// which led to various assertions and failures in turn. + +pub fn main() { + let a = 1e20f32 * (1f32/11f32) * 3f32; + let b = 1e20f32 * (3f32/11f32); + assert!(a.relative_eq(&b)); +} diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs index 5179d13813cea..2f74437c1b055 100644 --- a/src/test/run-pass/trait-inheritance-num.rs +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -17,7 +17,7 @@ use core::num::NumCast::from; pub trait NumExt: Num + NumCast + Eq + Ord {} -pub trait FloatExt: NumExt + ApproxEq {} +pub trait FloatExt: NumExt + ApproxEq + RelativeEq {} fn greater_than_one(n: &T) -> bool { *n > from(1) } fn greater_than_one_float(n: &T) -> bool { *n > from(1) } diff --git a/src/test/run-pass/trait-inheritance-num2.rs b/src/test/run-pass/trait-inheritance-num2.rs index f7edd2855a4cd..d14052a4ee1cb 100644 --- a/src/test/run-pass/trait-inheritance-num2.rs +++ b/src/test/run-pass/trait-inheritance-num2.rs @@ -93,7 +93,7 @@ impl IntegerExt for i64 {} impl IntegerExt for int {} -pub trait FloatExt: NumExt + ApproxEq {} +pub trait FloatExt: NumExt + ApproxEq + RelativeEq {} impl FloatExt for f32 {} impl FloatExt for f64 {}