summaryrefslogtreecommitdiffstats
path: root/third_party/rust/float-cmp/src/eq.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/float-cmp/src/eq.rs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/float-cmp/src/eq.rs')
-rw-r--r--third_party/rust/float-cmp/src/eq.rs284
1 files changed, 284 insertions, 0 deletions
diff --git a/third_party/rust/float-cmp/src/eq.rs b/third_party/rust/float-cmp/src/eq.rs
new file mode 100644
index 0000000000..d39535c95a
--- /dev/null
+++ b/third_party/rust/float-cmp/src/eq.rs
@@ -0,0 +1,284 @@
+// Copyright 2014-2018 Optimal Computing (NZ) Ltd.
+// Licensed under the MIT license. See LICENSE for details.
+
+use std::{f32,f64};
+use super::Ulps;
+
+/// ApproxEq is a trait for approximate equality comparisons.
+pub trait ApproxEq: Sized {
+ /// The Margin type defines a margin within which two values are to be
+ /// considered approximately equal. It must implement Default so that
+ /// approx_eq() can be called on unknown types.
+ type Margin: Copy + Default;
+
+ /// This method tests for `self` and `other` values to be approximately equal
+ /// within `margin`.
+ fn approx_eq<M: Into<Self::Margin>>(self, other: Self, margin: M) -> bool;
+
+ /// This method tests for `self` and `other` values to be not approximately
+ /// equal within `margin`.
+ fn approx_ne<M: Into<Self::Margin>>(self, other: Self, margin: M) -> bool {
+ !self.approx_eq(other, margin)
+ }
+}
+
+/// This type defines a margin within two f32s might be considered equal
+/// and is intended as the associated type for the `ApproxEq` trait.
+///
+/// Two methods are used to determine approximate equality.
+///
+/// First an epsilon method is used, considering them approximately equal if they
+/// differ by <= `epsilon`. This will only succeed for very small numbers.
+/// Note that it may succeed even if the parameters are of differing signs straddling
+/// zero.
+///
+/// The second method considers how many ULPs (units of least precision, units in
+/// the last place, which is the integer number of floating point representations
+/// that the parameters are separated by) different the parameters are and considers
+/// them approximately equal if this is <= `ulps`. For large floating point numbers,
+/// an ULP can be a rather large gap, but this kind of comparison is necessary
+/// because floating point operations must round to the nearest representable value
+/// and so larger floating point values accumulate larger errors.
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub struct F32Margin {
+ pub epsilon: f32,
+ pub ulps: i32
+}
+impl Default for F32Margin {
+ #[inline]
+ fn default() -> F32Margin {
+ F32Margin {
+ epsilon: f32::EPSILON,
+ ulps: 4
+ }
+ }
+}
+impl F32Margin {
+ #[inline]
+ pub fn zero() -> F32Margin {
+ F32Margin {
+ epsilon: 0.0,
+ ulps: 0
+ }
+ }
+ pub fn epsilon(self, epsilon: f32) -> Self {
+ F32Margin {
+ epsilon: epsilon,
+ ..self
+ }
+ }
+ pub fn ulps(self, ulps: i32) -> Self {
+ F32Margin {
+ ulps: ulps,
+ ..self
+ }
+ }
+}
+impl From<(f32, i32)> for F32Margin {
+ fn from(m: (f32, i32)) -> F32Margin {
+ F32Margin {
+ epsilon: m.0,
+ ulps: m.1
+ }
+ }
+}
+
+impl ApproxEq for f32 {
+ type Margin = F32Margin;
+
+ fn approx_eq<M: Into<Self::Margin>>(self, other: f32, margin: M) -> bool {
+ let margin = margin.into();
+
+ // Check for exact equality first. This is often true, and so we get the
+ // performance benefit of only doing one compare in most cases.
+ self==other ||
+
+ // Perform epsilon comparison next
+ ((self - other).abs() <= margin.epsilon) ||
+
+ {
+ // Perform ulps comparion last
+ let diff: i32 = self.ulps(&other);
+ saturating_abs_i32!(diff) <= margin.ulps
+ }
+ }
+}
+
+#[test]
+fn f32_approx_eq_test1() {
+ let f: f32 = 0.0_f32;
+ let g: f32 = -0.0000000000000005551115123125783_f32;
+ assert!(f != g); // Should not be directly equal
+ assert!(f.approx_eq(g, (f32::EPSILON, 0)) == true);
+}
+#[test]
+fn f32_approx_eq_test2() {
+ let f: f32 = 0.0_f32;
+ let g: f32 = -0.0_f32;
+ assert!(f.approx_eq(g, (f32::EPSILON, 0)) == true);
+}
+#[test]
+fn f32_approx_eq_test3() {
+ let f: f32 = 0.0_f32;
+ let g: f32 = 0.00000000000000001_f32;
+ assert!(f.approx_eq(g, (f32::EPSILON, 0)) == true);
+}
+#[test]
+fn f32_approx_eq_test4() {
+ let f: f32 = 0.00001_f32;
+ let g: f32 = 0.00000000000000001_f32;
+ assert!(f.approx_eq(g, (f32::EPSILON, 0)) == false);
+}
+#[test]
+fn f32_approx_eq_test5() {
+ 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); // Should not be directly equal:
+ println!("Ulps Difference: {}",sum.ulps(&product));
+ assert!(sum.approx_eq(product, (f32::EPSILON, 1)) == true);
+ assert!(sum.approx_eq(product, F32Margin::zero()) == false);
+}
+#[test]
+fn f32_approx_eq_test6() {
+ let x: f32 = 1000000_f32;
+ let y: f32 = 1000000.1_f32;
+ assert!(x != y); // Should not be directly equal
+ assert!(x.approx_eq(y, (0.0, 2)) == true); // 2 ulps does it
+ // epsilon method no good here:
+ assert!(x.approx_eq(y, (1000.0 * f32::EPSILON, 0)) == false);
+}
+
+/// This type defines a margin within two f32s might be considered equal
+/// and is intended as the associated type for the `ApproxEq` trait.
+///
+/// Two methods are used to determine approximate equality.
+///
+/// First an epsilon method is used, considering them approximately equal if they
+/// differ by <= `epsilon`. This will only succeed for very small numbers.
+/// Note that it may succeed even if the parameters are of differing signs straddling
+/// zero.
+///
+/// The second method considers how many ULPs (units of least precision, units in
+/// the last place, which is the integer number of floating point representations
+/// that the parameters are separated by) different the parameters are and considers
+/// them approximately equal if this <= `ulps`. For large floating point numbers,
+/// an ULP can be a rather large gap, but this kind of comparison is necessary
+/// because floating point operations must round to the nearest representable value
+/// and so larger floating point values accumulate larger errors.
+#[derive(Debug, Clone, Copy)]
+pub struct F64Margin {
+ pub epsilon: f64,
+ pub ulps: i64
+}
+impl Default for F64Margin {
+ #[inline]
+ fn default() -> F64Margin {
+ F64Margin {
+ epsilon: f64::EPSILON,
+ ulps: 4
+ }
+ }
+}
+impl F64Margin {
+ #[inline]
+ pub fn zero() -> F64Margin {
+ F64Margin {
+ epsilon: 0.0,
+ ulps: 0
+ }
+ }
+ pub fn epsilon(self, epsilon: f64) -> Self {
+ F64Margin {
+ epsilon: epsilon,
+ ..self
+ }
+ }
+ pub fn ulps(self, ulps: i64) -> Self {
+ F64Margin {
+ ulps: ulps,
+ ..self
+ }
+ }
+}
+impl From<(f64, i64)> for F64Margin {
+ fn from(m: (f64, i64)) -> F64Margin {
+ F64Margin {
+ epsilon: m.0,
+ ulps: m.1
+ }
+ }
+}
+
+impl ApproxEq for f64 {
+ type Margin = F64Margin;
+
+ fn approx_eq<M: Into<Self::Margin>>(self, other: f64, margin: M) -> bool {
+ let margin = margin.into();
+
+ // Check for exact equality first. This is often true, and so we get the
+ // performance benefit of only doing one compare in most cases.
+ self==other ||
+
+ // Perform epsilon comparison next
+ ((self - other).abs() <= margin.epsilon) ||
+
+ {
+ // Perform ulps comparion last
+ let diff: i64 = self.ulps(&other);
+ saturating_abs_i64!(diff) <= margin.ulps
+ }
+ }
+}
+
+#[test]
+fn f64_approx_eq_test1() {
+ let f: f64 = 0.0_f64;
+ let g: f64 = -0.0000000000000005551115123125783_f64;
+ assert!(f != g); // Should not be directly equal
+ assert!(f.approx_eq(g, (3.0 * f64::EPSILON, 0)) == true); // 3e is enough
+ // ulps test wont ever call these equal
+}
+#[test]
+fn f64_approx_eq_test2() {
+ let f: f64 = 0.0_f64;
+ let g: f64 = -0.0_f64;
+ assert!(f.approx_eq(g, (f64::EPSILON, 0)) == true);
+}
+#[test]
+fn f64_approx_eq_test3() {
+ let f: f64 = 0.0_f64;
+ let g: f64 = 1e-17_f64;
+ assert!(f.approx_eq(g, (f64::EPSILON, 0)) == true);
+}
+#[test]
+fn f64_approx_eq_test4() {
+ let f: f64 = 0.00001_f64;
+ let g: f64 = 0.00000000000000001_f64;
+ assert!(f.approx_eq(g, (f64::EPSILON, 0)) == false);
+}
+#[test]
+fn f64_approx_eq_test5() {
+ let f: f64 = 0.1_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); // Should not be directly equal:
+ println!("Ulps Difference: {}",sum.ulps(&product));
+ assert!(sum.approx_eq(product, (f64::EPSILON, 0)) == true);
+ assert!(sum.approx_eq(product, (0.0, 1)) == true);
+}
+#[test]
+fn f64_approx_eq_test6() {
+ let x: f64 = 1000000_f64;
+ let y: f64 = 1000000.0000000003_f64;
+ assert!(x != y); // Should not be directly equal
+ println!("Ulps Difference: {}",x.ulps(&y));
+ assert!(x.approx_eq(y, (0.0, 3)) == true);
+}
+#[test]
+fn f64_code_triggering_issue_20() {
+ assert_eq!((-25.0f64).approx_eq(25.0, (0.00390625, 1)), false);
+}