You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: tests/pass/float.rs
+27-111
Original file line number
Diff line number
Diff line change
@@ -13,78 +13,27 @@ use std::fmt::{Debug, Display, LowerHex};
13
13
use std::hint::black_box;
14
14
use std::{f32, f64};
15
15
16
-
/// Another way of checking if 2 floating-point numbers are almost equal to eachother.
17
-
/// Using `a` and `b` as floating-point numbers:
16
+
/// Compare the two floats, allowing for $ulp many ULPs of error.
18
17
///
19
-
/// Instead of performing a simple EPSILON check (which we used at first):
20
-
/// The absolute difference between 'a' and 'b' must not be greater than some E (10^-6, ...)
21
-
///
22
-
/// We will now use ULP: `Units in the Last Place` or `Units of Least Precision`,
23
-
/// more specific, the difference in ULP of `a` and `b`.
24
-
/// First: The ULP of a float 'a' is the smallest possible change at 'a', so the ULP difference represents how
25
-
/// many discrete floating-point steps are needed to reach 'b' from 'a'.
26
-
///
27
-
/// ULP(a) is the distance between the 2 closest floating-point numbers `x` and `y` around `a`, satisfying x < a < y, x != y.
28
-
/// To use this to calculate the ULP difference we have to halve it (we need it at `a`, but we just went "up" and "down", halving it gives us this ULP).
29
-
/// Then take the difference of `b` and `a` and divide it by that ULP and finally round it.
30
-
/// We know now how many floating-point changes we have to apply to `a` to get to `b`.
31
-
///
32
-
/// So if this ULP difference is less than or equal to our chosen upper bound
33
-
/// we can say that `a` and `b` are approximately equal, because they lie "close" enough to each other to be considered equal.
34
-
///
35
-
/// Note: We can see that checking `a` and `b` with different signs has no meaning, but we should not forget
36
-
/// -0.0 and +0.0.
18
+
/// ULP means "Units in the Last Place" or "Units of Least Precision".
19
+
/// The ULP of a float `a`` is the smallest possible change at `a`, so the ULP difference represents how
20
+
/// many discrete floating-point steps are needed to reach the actual value from the expected value.
37
21
///
38
22
/// Essentially ULP can be seen as a distance metric of floating-point numbers, but with
39
23
/// the same amount of "spacing" between all consecutive representable values. So even though 2 very large floating point numbers
40
24
/// have a large value difference, their ULP can still be 1, so they are still "approximatly equal",
41
25
/// but the EPSILON check would have failed.
42
-
///
43
-
fnapprox_eq_check<F:Float>(
44
-
actual:F,
45
-
expected:F,
46
-
allowed_ulp:F::Int,
47
-
) -> Result<(),NotApproxEq<F>>
48
-
where
49
-
F::Int:PartialOrd,
50
-
{
51
-
let actual_signum = actual.signum();
52
-
let expected_signum = expected.signum();
53
-
54
-
if actual_signum != expected_signum {
55
-
// Floats with different signs must both be 0.
56
-
if actual != expected {
57
-
returnErr(NotApproxEq::SignsDiffer);
58
-
}
59
-
}else{
60
-
let ulp = (expected.next_up() - expected.next_down()).halve();
61
-
let ulp_diff = ((actual - expected) / ulp).round().as_int();
62
-
63
-
if ulp_diff > allowed_ulp {
64
-
returnErr(NotApproxEq::UlpFail(ulp_diff));
65
-
}
66
-
}
67
-
Ok(())
68
-
}
69
-
70
-
/// Give more context to execution and result of [`approx_eq_check`].
71
-
enumNotApproxEq<F:Float>{
72
-
SignsDiffer,
73
-
74
-
/// Contains the actual ulp value calculated.
75
-
UlpFail(F::Int),
76
-
}
77
-
78
26
macro_rules! assert_approx_eq {
79
27
($a:expr, $b:expr, $ulp:expr) => {{
80
-
let(a, b) = ($a, $b);
81
-
let allowed_ulp = $ulp;
82
-
match approx_eq_check(a, b, allowed_ulp){
83
-
Err(NotApproxEq::SignsDiffer) =>
84
-
panic!("{a:?} is not approximately equal to {b:?}: signs differ"),
85
-
Err(NotApproxEq::UlpFail(actual_ulp)) =>
86
-
panic!("{a:?} is not approximately equal to {b:?}\nulp diff: {actual_ulp} > {allowed_ulp}"),
87
-
Ok(_) => {}
28
+
let(actual, expected) = ($a, $b);
29
+
let allowed_ulp_diff = $ulp;
30
+
let _force_same_type = actual == expected;
31
+
// Approximate the ULP by taking half the distance between the number one place "up"
32
+
// and the number one place "down".
33
+
let ulp = (expected.next_up() - expected.next_down()) / 2.0;
34
+
let ulp_diff = ((actual - expected) / ulp).round().abs()asi32;
35
+
if ulp_diff > allowed_ulp_diff {
36
+
panic!("{actual:?} is not approximately equal to {expected:?}\ndifference in ULP: {ulp_diff} > {allowed_ulp_diff}");
88
37
};
89
38
}};
90
39
@@ -101,23 +50,16 @@ fn main() {
101
50
ops();
102
51
nan_casts();
103
52
rounding();
104
-
libm();
105
53
mul_add();
54
+
libm();
106
55
test_fast();
107
56
test_algebraic();
108
57
test_fmuladd();
109
58
test_min_max_nondet();
110
59
test_non_determinism();
111
60
}
112
61
113
-
traitFloat:
114
-
Copy
115
-
+ PartialEq
116
-
+ Debug
117
-
+ std::ops::Sub<Output = Self>
118
-
+ std::cmp::PartialOrd
119
-
+ std::ops::Div<Output = Self>
120
-
{
62
+
traitFloat:Copy + PartialEq + Debug{
121
63
/// The unsigned integer with the same bit width as this float
0 commit comments