about summary refs log tree commit diff
path: root/library/std
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-06-09 21:21:58 +0000
committerbors <bors@rust-lang.org>2025-06-09 21:21:58 +0000
commitc6768de2d63de7a41124a0fb8fc78f9e26111c01 (patch)
tree0353ff7cc2d97021a526887a4be635d48a0eab5c /library/std
parentd13a431a6cc69cd65efe7c3eb7808251d6fd7a46 (diff)
parent00452bd783a2c91b85cfb37e650628674c64b006 (diff)
downloadrust-c6768de2d63de7a41124a0fb8fc78f9e26111c01.tar.gz
rust-c6768de2d63de7a41124a0fb8fc78f9e26111c01.zip
Auto merge of #138062 - LorrensP-2158466:miri-enable-float-nondet, r=RalfJung
Enable Non-determinism of float operations in Miri and change std tests

Links to [#4208](https://github.com/rust-lang/miri/issues/4208) and [#3555](https://github.com/rust-lang/miri/issues/3555) in Miri.

Non-determinism of floating point operations was disabled in rust-lang/rust#137594 because it breaks the tests and doc-tests in core/coretests and std. This PR enables some of them.

This pr includes the following changes:

- Enables the float non-determinism but with a lower relative error of 4ULP instead of 16ULP
- These operations now have a fixed output based on the C23 standard, except the pow operations, this is tracked in [#4286](https://github.com/rust-lang/miri/issues/4286#issue-3010677983)
- Changes tests that made incorrect assumptions about the operations, not to make that assumption anymore (from `assert_eq!` to `assert_approx_eq!`.
- Changed the doctests of the stdlib of these operations to compare against fixed constants instead of `f*::EPSILON`, which now succeed with Miri and `-Zmiri-many-seeds`
- Added a constant `APPROX_DELTA` in `std/tests/floats/f32.rs` which is used for approximation tests, but with a different value when run in Miri. This is to make these tests succeed.
- Added tests in the float tests of Miri to test the C23 behaviour.

Fixes https://github.com/rust-lang/miri/issues/4208
Diffstat (limited to 'library/std')
-rw-r--r--library/std/src/num/f32.rs34
-rw-r--r--library/std/src/num/f64.rs6
-rw-r--r--library/std/tests/floats/f32.rs33
-rw-r--r--library/std/tests/floats/f64.rs8
4 files changed, 43 insertions, 38 deletions
diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs
index b7f6529ac40..e79ec2ae966 100644
--- a/library/std/src/num/f32.rs
+++ b/library/std/src/num/f32.rs
@@ -304,7 +304,7 @@ impl f32 {
     /// ```
     /// let x = 2.0_f32;
     /// let abs_difference = (x.powi(2) - (x * x)).abs();
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-5);
     ///
     /// assert_eq!(f32::powi(f32::NAN, 0), 1.0);
     /// ```
@@ -328,7 +328,7 @@ impl f32 {
     /// ```
     /// let x = 2.0_f32;
     /// let abs_difference = (x.powf(2.0) - (x * x)).abs();
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-5);
     ///
     /// assert_eq!(f32::powf(1.0, f32::NAN), 1.0);
     /// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0);
@@ -388,7 +388,7 @@ impl f32 {
     /// // ln(e) - 1 == 0
     /// let abs_difference = (e.ln() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -413,7 +413,7 @@ impl f32 {
     /// // 2^2 - 4 == 0
     /// let abs_difference = (f.exp2() - 4.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-5);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -442,7 +442,7 @@ impl f32 {
     /// // ln(e) - 1 == 0
     /// let abs_difference = (e.ln() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     ///
     /// Non-positive values:
@@ -479,7 +479,7 @@ impl f32 {
     /// // log5(5) - 1 == 0
     /// let abs_difference = (five.log(5.0) - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     ///
     /// Non-positive values:
@@ -512,7 +512,7 @@ impl f32 {
     /// // log2(2) - 1 == 0
     /// let abs_difference = (two.log2() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     ///
     /// Non-positive values:
@@ -545,7 +545,7 @@ impl f32 {
     /// // log10(10) - 1 == 0
     /// let abs_difference = (ten.log10() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     ///
     /// Non-positive values:
@@ -652,7 +652,7 @@ impl f32 {
     /// // sqrt(x^2 + y^2)
     /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -676,7 +676,7 @@ impl f32 {
     ///
     /// let abs_difference = (x.sin() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -700,7 +700,7 @@ impl f32 {
     ///
     /// let abs_difference = (x.cos() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -754,7 +754,7 @@ impl f32 {
     /// // asin(sin(pi/2))
     /// let abs_difference = (f.sin().asin() - std::f32::consts::FRAC_PI_2).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-3);
     /// ```
     #[doc(alias = "arcsin")]
     #[rustc_allow_incoherent_impl]
@@ -784,7 +784,7 @@ impl f32 {
     /// // acos(cos(pi/4))
     /// let abs_difference = (f.cos().acos() - std::f32::consts::FRAC_PI_4).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[doc(alias = "arccos")]
     #[rustc_allow_incoherent_impl]
@@ -884,8 +884,8 @@ impl f32 {
     /// let abs_difference_0 = (f.0 - x.sin()).abs();
     /// let abs_difference_1 = (f.1 - x.cos()).abs();
     ///
-    /// assert!(abs_difference_0 <= f32::EPSILON);
-    /// assert!(abs_difference_1 <= f32::EPSILON);
+    /// assert!(abs_difference_0 <= 1e-6);
+    /// assert!(abs_difference_1 <= 1e-6);
     /// ```
     #[doc(alias = "sincos")]
     #[rustc_allow_incoherent_impl]
@@ -1067,7 +1067,7 @@ impl f32 {
     ///
     /// let abs_difference = (f - x).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-7);
     /// ```
     #[doc(alias = "arcsinh")]
     #[rustc_allow_incoherent_impl]
@@ -1095,7 +1095,7 @@ impl f32 {
     ///
     /// let abs_difference = (f - x).abs();
     ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[doc(alias = "arccosh")]
     #[rustc_allow_incoherent_impl]
diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs
index 75e35a8db33..853417825f9 100644
--- a/library/std/src/num/f64.rs
+++ b/library/std/src/num/f64.rs
@@ -304,7 +304,7 @@ impl f64 {
     /// ```
     /// let x = 2.0_f64;
     /// let abs_difference = (x.powi(2) - (x * x)).abs();
-    /// assert!(abs_difference <= f64::EPSILON);
+    /// assert!(abs_difference <= 1e-14);
     ///
     /// assert_eq!(f64::powi(f64::NAN, 0), 1.0);
     /// ```
@@ -328,7 +328,7 @@ impl f64 {
     /// ```
     /// let x = 2.0_f64;
     /// let abs_difference = (x.powf(2.0) - (x * x)).abs();
-    /// assert!(abs_difference <= f64::EPSILON);
+    /// assert!(abs_difference <= 1e-14);
     ///
     /// assert_eq!(f64::powf(1.0, f64::NAN), 1.0);
     /// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0);
@@ -754,7 +754,7 @@ impl f64 {
     /// // asin(sin(pi/2))
     /// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs();
     ///
-    /// assert!(abs_difference < 1e-10);
+    /// assert!(abs_difference < 1e-7);
     /// ```
     #[doc(alias = "arcsin")]
     #[rustc_allow_incoherent_impl]
diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs
index e54f227bb77..38c906c1d87 100644
--- a/library/std/tests/floats/f32.rs
+++ b/library/std/tests/floats/f32.rs
@@ -1,5 +1,10 @@
 use std::f32::consts;
 
+/// Miri adds some extra errors to float functions; make sure the tests still pass.
+/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides.
+/// They serve as a way to get an idea of the real precision of floating point operations on different platforms.
+const APPROX_DELTA: f32 = if cfg!(miri) { 1e-3 } else { 1e-6 };
+
 #[allow(unused_macros)]
 macro_rules! assert_f32_biteq {
     ($left : expr, $right : expr) => {
@@ -17,9 +22,9 @@ fn test_powf() {
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
     assert_eq!(1.0f32.powf(1.0), 1.0);
-    assert_approx_eq!(3.4f32.powf(4.5), 246.408218);
+    assert_approx_eq!(3.4f32.powf(4.5), 246.408218, APPROX_DELTA);
     assert_approx_eq!(2.7f32.powf(-3.2), 0.041652);
-    assert_approx_eq!((-3.1f32).powf(2.0), 9.61);
+    assert_approx_eq!((-3.1f32).powf(2.0), 9.61, APPROX_DELTA);
     assert_approx_eq!(5.9f32.powf(-2.0), 0.028727);
     assert_eq!(8.3f32.powf(0.0), 1.0);
     assert!(nan.powf(2.0).is_nan());
@@ -30,8 +35,8 @@ fn test_powf() {
 #[test]
 fn test_exp() {
     assert_eq!(1.0, 0.0f32.exp());
-    assert_approx_eq!(2.718282, 1.0f32.exp());
-    assert_approx_eq!(148.413162, 5.0f32.exp());
+    assert_approx_eq!(2.718282, 1.0f32.exp(), APPROX_DELTA);
+    assert_approx_eq!(148.413162, 5.0f32.exp(), APPROX_DELTA);
 
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
@@ -43,7 +48,7 @@ fn test_exp() {
 
 #[test]
 fn test_exp2() {
-    assert_eq!(32.0, 5.0f32.exp2());
+    assert_approx_eq!(32.0, 5.0f32.exp2(), APPROX_DELTA);
     assert_eq!(1.0, 0.0f32.exp2());
 
     let inf: f32 = f32::INFINITY;
@@ -66,7 +71,7 @@ fn test_ln() {
     assert!((-2.3f32).ln().is_nan());
     assert_eq!((-0.0f32).ln(), neg_inf);
     assert_eq!(0.0f32.ln(), neg_inf);
-    assert_approx_eq!(4.0f32.ln(), 1.386294);
+    assert_approx_eq!(4.0f32.ln(), 1.386294, APPROX_DELTA);
 }
 
 #[test]
@@ -74,9 +79,9 @@ fn test_log() {
     let nan: f32 = f32::NAN;
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
-    assert_eq!(10.0f32.log(10.0), 1.0);
+    assert_approx_eq!(10.0f32.log(10.0), 1.0);
     assert_approx_eq!(2.3f32.log(3.5), 0.664858);
-    assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0);
+    assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA);
     assert!(1.0f32.log(1.0).is_nan());
     assert!(1.0f32.log(-13.9).is_nan());
     assert!(nan.log(2.3).is_nan());
@@ -92,9 +97,9 @@ fn test_log2() {
     let nan: f32 = f32::NAN;
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
-    assert_approx_eq!(10.0f32.log2(), 3.321928);
+    assert_approx_eq!(10.0f32.log2(), 3.321928, APPROX_DELTA);
     assert_approx_eq!(2.3f32.log2(), 1.201634);
-    assert_approx_eq!(1.0f32.exp().log2(), 1.442695);
+    assert_approx_eq!(1.0f32.exp().log2(), 1.442695, APPROX_DELTA);
     assert!(nan.log2().is_nan());
     assert_eq!(inf.log2(), inf);
     assert!(neg_inf.log2().is_nan());
@@ -108,7 +113,7 @@ fn test_log10() {
     let nan: f32 = f32::NAN;
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
-    assert_eq!(10.0f32.log10(), 1.0);
+    assert_approx_eq!(10.0f32.log10(), 1.0);
     assert_approx_eq!(2.3f32.log10(), 0.361728);
     assert_approx_eq!(1.0f32.exp().log10(), 0.434294);
     assert_eq!(1.0f32.log10(), 0.0);
@@ -158,7 +163,7 @@ fn test_acosh() {
     assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
 
     // test for low accuracy from issue 104548
-    assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh());
+    assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh(), APPROX_DELTA);
 }
 
 #[test]
@@ -237,7 +242,7 @@ fn test_real_consts() {
     let ln_10: f32 = consts::LN_10;
 
     assert_approx_eq!(frac_pi_2, pi / 2f32);
-    assert_approx_eq!(frac_pi_3, pi / 3f32);
+    assert_approx_eq!(frac_pi_3, pi / 3f32, APPROX_DELTA);
     assert_approx_eq!(frac_pi_4, pi / 4f32);
     assert_approx_eq!(frac_pi_6, pi / 6f32);
     assert_approx_eq!(frac_pi_8, pi / 8f32);
@@ -249,5 +254,5 @@ fn test_real_consts() {
     assert_approx_eq!(log2_e, e.log2());
     assert_approx_eq!(log10_e, e.log10());
     assert_approx_eq!(ln_2, 2f32.ln());
-    assert_approx_eq!(ln_10, 10f32.ln());
+    assert_approx_eq!(ln_10, 10f32.ln(), APPROX_DELTA);
 }
diff --git a/library/std/tests/floats/f64.rs b/library/std/tests/floats/f64.rs
index 2d8dd1cf091..fccf2009727 100644
--- a/library/std/tests/floats/f64.rs
+++ b/library/std/tests/floats/f64.rs
@@ -43,7 +43,7 @@ fn test_exp() {
 
 #[test]
 fn test_exp2() {
-    assert_eq!(32.0, 5.0f64.exp2());
+    assert_approx_eq!(32.0, 5.0f64.exp2());
     assert_eq!(1.0, 0.0f64.exp2());
 
     let inf: f64 = f64::INFINITY;
@@ -74,9 +74,9 @@ fn test_log() {
     let nan: f64 = f64::NAN;
     let inf: f64 = f64::INFINITY;
     let neg_inf: f64 = f64::NEG_INFINITY;
-    assert_eq!(10.0f64.log(10.0), 1.0);
+    assert_approx_eq!(10.0f64.log(10.0), 1.0);
     assert_approx_eq!(2.3f64.log(3.5), 0.664858);
-    assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
+    assert_approx_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
     assert!(1.0f64.log(1.0).is_nan());
     assert!(1.0f64.log(-13.9).is_nan());
     assert!(nan.log(2.3).is_nan());
@@ -108,7 +108,7 @@ fn test_log10() {
     let nan: f64 = f64::NAN;
     let inf: f64 = f64::INFINITY;
     let neg_inf: f64 = f64::NEG_INFINITY;
-    assert_eq!(10.0f64.log10(), 1.0);
+    assert_approx_eq!(10.0f64.log10(), 1.0);
     assert_approx_eq!(2.3f64.log10(), 0.361728);
     assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
     assert_eq!(1.0f64.log10(), 0.0);