about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2025-08-08 19:16:48 +0200
committerJakub Beránek <berykubik@gmail.com>2025-08-08 19:16:48 +0200
commit8fcfbcd8686c1e47778724229a25cd0417e42824 (patch)
treebef03be2d387f08ab3b63416d5318baf994ce333
parent2886b36df4a646dd8d82fb65bf0c9d8d96c1f71a (diff)
downloadrust-8fcfbcd8686c1e47778724229a25cd0417e42824.tar.gz
rust-8fcfbcd8686c1e47778724229a25cd0417e42824.zip
Revert "Rollup merge of #143906 - LorrensP-2158466:miri-float-nondet-foreign-items, r=RalfJung"
This reverts commit 71f04692c32e181ab566c01942f1418dec8662d4, reversing
changes made to 995ca3e532b48b689567533e6b736675e38b741e.
-rw-r--r--library/core/src/num/f32.rs6
-rw-r--r--library/std/src/num/f32.rs40
-rw-r--r--library/std/src/num/f64.rs10
-rw-r--r--library/std/tests/floats/f32.rs14
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs196
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/math.rs256
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs217
-rw-r--r--src/tools/miri/tests/pass/float.rs154
9 files changed, 347 insertions, 548 deletions
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 6c7ba491971..f8344da79ad 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1936,8 +1936,8 @@ pub mod math {
     /// let abs_difference_x = (f32::math::abs_sub(x, 1.0) - 2.0).abs();
     /// let abs_difference_y = (f32::math::abs_sub(y, 1.0) - 0.0).abs();
     ///
-    /// assert!(abs_difference_x <= 1e-6);
-    /// assert!(abs_difference_y <= 1e-6);
+    /// assert!(abs_difference_x <= f32::EPSILON);
+    /// assert!(abs_difference_y <= f32::EPSILON);
     /// ```
     ///
     /// _This standalone function is for testing only.
@@ -1982,7 +1982,7 @@ pub mod math {
     /// // x^(1/3) - 2 == 0
     /// let abs_difference = (f32::math::cbrt(x) - 2.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     ///
     /// _This standalone function is for testing only.
diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs
index d16028c0543..5dee68ad909 100644
--- a/library/std/src/num/f32.rs
+++ b/library/std/src/num/f32.rs
@@ -582,8 +582,8 @@ impl f32 {
     /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
     /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
     ///
-    /// assert!(abs_difference_x <= 1e-6);
-    /// assert!(abs_difference_y <= 1e-6);
+    /// assert!(abs_difference_x <= f32::EPSILON);
+    /// assert!(abs_difference_y <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -621,7 +621,7 @@ impl f32 {
     /// // x^(1/3) - 2 == 0
     /// let abs_difference = (x.cbrt() - 2.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -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 <= 1e-5);
+    /// assert!(abs_difference <= 1e-6);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -725,7 +725,7 @@ impl f32 {
     /// let x = std::f32::consts::FRAC_PI_4;
     /// let abs_difference = (x.tan() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -749,12 +749,12 @@ impl f32 {
     /// # Examples
     ///
     /// ```
-    /// let f = std::f32::consts::FRAC_PI_4;
+    /// let f = std::f32::consts::FRAC_PI_2;
     ///
     /// // asin(sin(pi/2))
-    /// let abs_difference = (f.sin().asin() - f).abs();
+    /// let abs_difference = (f.sin().asin() - std::f32::consts::FRAC_PI_2).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= 1e-3);
     /// ```
     #[doc(alias = "arcsin")]
     #[rustc_allow_incoherent_impl]
@@ -813,7 +813,7 @@ impl f32 {
     /// // atan(tan(1))
     /// let abs_difference = (f.tan().atan() - 1.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[doc(alias = "arctan")]
     #[rustc_allow_incoherent_impl]
@@ -854,8 +854,8 @@ impl f32 {
     /// let abs_difference_1 = (y1.atan2(x1) - (-std::f32::consts::FRAC_PI_4)).abs();
     /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f32::consts::FRAC_PI_4)).abs();
     ///
-    /// assert!(abs_difference_1 <= 1e-5);
-    /// assert!(abs_difference_2 <= 1e-5);
+    /// assert!(abs_difference_1 <= f32::EPSILON);
+    /// assert!(abs_difference_2 <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -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 <= 1e-4);
-    /// assert!(abs_difference_1 <= 1e-4);
+    /// assert!(abs_difference_0 <= 1e-6);
+    /// assert!(abs_difference_1 <= 1e-6);
     /// ```
     #[doc(alias = "sincos")]
     #[rustc_allow_incoherent_impl]
@@ -982,7 +982,7 @@ impl f32 {
     /// let g = ((e * e) - 1.0) / (2.0 * e);
     /// let abs_difference = (f - g).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1012,7 +1012,7 @@ impl f32 {
     /// let abs_difference = (f - g).abs();
     ///
     /// // Same result
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1042,7 +1042,7 @@ impl f32 {
     /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2));
     /// let abs_difference = (f - g).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1067,7 +1067,7 @@ impl f32 {
     ///
     /// let abs_difference = (f - x).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= 1e-7);
     /// ```
     #[doc(alias = "arcsinh")]
     #[rustc_allow_incoherent_impl]
@@ -1125,7 +1125,7 @@ impl f32 {
     ///
     /// let abs_difference = (f - e).abs();
     ///
-    /// assert!(abs_difference <= 1e-4);
+    /// assert!(abs_difference <= 1e-5);
     /// ```
     #[doc(alias = "arctanh")]
     #[rustc_allow_incoherent_impl]
@@ -1153,7 +1153,7 @@ impl f32 {
     ///
     /// let abs_difference = (x.gamma() - 24.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-4);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1248,7 +1248,7 @@ impl f32 {
     /// let one = x.erf() + x.erfc();
     /// let abs_difference = (one - 1.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-6);
+    /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs
index 91e8f161c51..3ec80f68bdb 100644
--- a/library/std/src/num/f64.rs
+++ b/library/std/src/num/f64.rs
@@ -749,12 +749,12 @@ impl f64 {
     /// # Examples
     ///
     /// ```
-    /// let f = std::f64::consts::FRAC_PI_4;
+    /// let f = std::f64::consts::FRAC_PI_2;
     ///
     /// // asin(sin(pi/2))
-    /// let abs_difference = (f.sin().asin() - f).abs();
+    /// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs();
     ///
-    /// assert!(abs_difference < 1e-14);
+    /// assert!(abs_difference < 1e-7);
     /// ```
     #[doc(alias = "arcsin")]
     #[rustc_allow_incoherent_impl]
@@ -1153,7 +1153,7 @@ impl f64 {
     ///
     /// let abs_difference = (x.gamma() - 24.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-10);
+    /// assert!(abs_difference <= f64::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -1248,7 +1248,7 @@ impl f64 {
     /// let one = x.erf() + x.erfc();
     /// let abs_difference = (one - 1.0).abs();
     ///
-    /// assert!(abs_difference <= 1e-10);
+    /// assert!(abs_difference <= f64::EPSILON);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs
index bea9e8282a6..38c906c1d87 100644
--- a/library/std/tests/floats/f32.rs
+++ b/library/std/tests/floats/f32.rs
@@ -79,7 +79,7 @@ fn test_log() {
     let nan: f32 = f32::NAN;
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
-    assert_approx_eq!(10.0f32.log(10.0), 1.0, APPROX_DELTA);
+    assert_approx_eq!(10.0f32.log(10.0), 1.0);
     assert_approx_eq!(2.3f32.log(3.5), 0.664858);
     assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA);
     assert!(1.0f32.log(1.0).is_nan());
@@ -140,10 +140,10 @@ fn test_asinh() {
     assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
     assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
     // regression test for the catastrophic cancellation fixed in 72486
-    assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32, APPROX_DELTA);
+    assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
 
     // test for low accuracy from issue 104548
-    assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh(), APPROX_DELTA);
+    assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh());
     // mul needed for approximate comparison to be meaningful
     assert_approx_eq!(1.0f32, 1e-15f32.sinh().asinh() * 1e15f32);
 }
@@ -196,10 +196,10 @@ fn test_gamma() {
     assert_approx_eq!(1.0f32.gamma(), 1.0f32);
     assert_approx_eq!(2.0f32.gamma(), 1.0f32);
     assert_approx_eq!(3.0f32.gamma(), 2.0f32);
-    assert_approx_eq!(4.0f32.gamma(), 6.0f32, APPROX_DELTA);
-    assert_approx_eq!(5.0f32.gamma(), 24.0f32, APPROX_DELTA);
+    assert_approx_eq!(4.0f32.gamma(), 6.0f32);
+    assert_approx_eq!(5.0f32.gamma(), 24.0f32);
     assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt());
-    assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt(), APPROX_DELTA);
+    assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt());
     assert_eq!(0.0f32.gamma(), f32::INFINITY);
     assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY);
     assert!((-1.0f32).gamma().is_nan());
@@ -218,7 +218,7 @@ fn test_ln_gamma() {
     assert_eq!(2.0f32.ln_gamma().1, 1);
     assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln());
     assert_eq!(3.0f32.ln_gamma().1, 1);
-    assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), APPROX_DELTA);
+    assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln());
     assert_eq!((-0.5f32).ln_gamma().1, -1);
 }
 
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index e0e09ac6835..b5e81460773 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -3,16 +3,20 @@
 mod atomic;
 mod simd;
 
+use std::ops::Neg;
+
 use rand::Rng;
 use rustc_abi::Size;
+use rustc_apfloat::ieee::{IeeeFloat, Semantics};
 use rustc_apfloat::{self, Float, Round};
 use rustc_middle::mir;
-use rustc_middle::ty::{self, FloatTy};
+use rustc_middle::ty::{self, FloatTy, ScalarInt};
 use rustc_span::{Symbol, sym};
 
 use self::atomic::EvalContextExt as _;
 use self::helpers::{ToHost, ToSoft};
 use self::simd::EvalContextExt as _;
+use crate::math::{IeeeExt, apply_random_float_error_ulp};
 use crate::*;
 
 /// Check that the number of args is what we expect.
@@ -205,7 +209,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f] = check_intrinsic_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
 
-                let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
+                let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, these operations do not have
                     // guaranteed precision).
                     let host = f.to_host();
@@ -223,7 +227,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    let res = math::apply_random_float_error_ulp(
+                    let res = apply_random_float_error_ulp(
                         this,
                         res,
                         2, // log2(4)
@@ -231,7 +235,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                     // Clamp the result to the guaranteed range of this function according to the C standard,
                     // if any.
-                    math::clamp_float_value(intrinsic_name, res)
+                    clamp_float_value(intrinsic_name, res)
                 });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
@@ -249,7 +253,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f] = check_intrinsic_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
 
-                let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
+                let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, these operations do not have
                     // guaranteed precision).
                     let host = f.to_host();
@@ -267,7 +271,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    let res = math::apply_random_float_error_ulp(
+                    let res = apply_random_float_error_ulp(
                         this,
                         res,
                         2, // log2(4)
@@ -275,7 +279,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                     // Clamp the result to the guaranteed range of this function according to the C standard,
                     // if any.
-                    math::clamp_float_value(intrinsic_name, res)
+                    clamp_float_value(intrinsic_name, res)
                 });
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
@@ -326,17 +330,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f1 = this.read_scalar(f1)?.to_f32()?;
                 let f2 = this.read_scalar(f2)?.to_f32()?;
 
-                let res =
-                    math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
-                        // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                        let res = f1.to_host().powf(f2.to_host()).to_soft();
+                let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+                    // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                    let res = f1.to_host().powf(f2.to_host()).to_soft();
 
-                        // Apply a relative error of 4ULP to introduce some non-determinism
-                        // simulating imprecise implementations and optimizations.
-                        math::apply_random_float_error_ulp(
-                            this, res, 2, // log2(4)
-                        )
-                    });
+                    // Apply a relative error of 4ULP to introduce some non-determinism
+                    // simulating imprecise implementations and optimizations.
+                    apply_random_float_error_ulp(
+                        this, res, 2, // log2(4)
+                    )
+                });
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -345,17 +348,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f1 = this.read_scalar(f1)?.to_f64()?;
                 let f2 = this.read_scalar(f2)?.to_f64()?;
 
-                let res =
-                    math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
-                        // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                        let res = f1.to_host().powf(f2.to_host()).to_soft();
+                let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+                    // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                    let res = f1.to_host().powf(f2.to_host()).to_soft();
 
-                        // Apply a relative error of 4ULP to introduce some non-determinism
-                        // simulating imprecise implementations and optimizations.
-                        math::apply_random_float_error_ulp(
-                            this, res, 2, // log2(4)
-                        )
-                    });
+                    // Apply a relative error of 4ULP to introduce some non-determinism
+                    // simulating imprecise implementations and optimizations.
+                    apply_random_float_error_ulp(
+                        this, res, 2, // log2(4)
+                    )
+                });
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -365,13 +367,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f = this.read_scalar(f)?.to_f32()?;
                 let i = this.read_scalar(i)?.to_i32()?;
 
-                let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| {
+                let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f.to_host().powi(i).to_soft();
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    math::apply_random_float_error_ulp(
+                    apply_random_float_error_ulp(
                         this, res, 2, // log2(4)
                     )
                 });
@@ -383,13 +385,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f = this.read_scalar(f)?.to_f64()?;
                 let i = this.read_scalar(i)?.to_i32()?;
 
-                let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| {
+                let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f.to_host().powi(i).to_soft();
 
                     // Apply a relative error of 4ULP to introduce some non-determinism
                     // simulating imprecise implementations and optimizations.
-                    math::apply_random_float_error_ulp(
+                    apply_random_float_error_ulp(
                         this, res, 2, // log2(4)
                     )
                 });
@@ -446,7 +448,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
                 // Apply a relative error of 4ULP to simulate non-deterministic precision loss
                 // due to optimizations.
-                let res = math::apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?;
+                let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?;
                 this.write_immediate(*res, dest)?;
             }
 
@@ -483,3 +485,133 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
+
+/// Applies a random ULP floating point error to `val` and returns the new value.
+/// So if you want an X ULP error, `ulp_exponent` should be log2(X).
+///
+/// Will fail if `val` is not a floating point number.
+fn apply_random_float_error_to_imm<'tcx>(
+    ecx: &mut MiriInterpCx<'tcx>,
+    val: ImmTy<'tcx>,
+    ulp_exponent: u32,
+) -> InterpResult<'tcx, ImmTy<'tcx>> {
+    let scalar = val.to_scalar_int()?;
+    let res: ScalarInt = match val.layout.ty.kind() {
+        ty::Float(FloatTy::F16) =>
+            apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(),
+        ty::Float(FloatTy::F32) =>
+            apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(),
+        ty::Float(FloatTy::F64) =>
+            apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(),
+        ty::Float(FloatTy::F128) =>
+            apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(),
+        _ => bug!("intrinsic called with non-float input type"),
+    };
+
+    interp_ok(ImmTy::from_scalar_int(res, val.layout))
+}
+
+/// For the intrinsics:
+/// - sinf32, sinf64
+/// - cosf32, cosf64
+/// - expf32, expf64, exp2f32, exp2f64
+/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
+/// - powf32, powf64
+///
+/// # Return
+///
+/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
+/// (specifically, C23 annex F.10)  when given `args` as arguments. Outputs that are unaffected by a relative error
+/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
+/// implementation. Returns `None` if no specific value is guaranteed.
+///
+/// # Note
+///
+/// For `powf*` operations of the form:
+///
+/// - `(SNaN)^(±0)`
+/// - `1^(SNaN)`
+///
+/// The result is implementation-defined:
+/// - musl returns for both `1.0`
+/// - glibc returns for both `NaN`
+///
+/// This discrepancy exists because SNaN handling is not consistently defined across platforms,
+/// and the C standard leaves behavior for SNaNs unspecified.
+///
+/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
+fn fixed_float_value<S: Semantics>(
+    ecx: &mut MiriInterpCx<'_>,
+    intrinsic_name: &str,
+    args: &[IeeeFloat<S>],
+) -> Option<IeeeFloat<S>> {
+    let one = IeeeFloat::<S>::one();
+    Some(match (intrinsic_name, args) {
+        // cos(+- 0) = 1
+        ("cosf32" | "cosf64", [input]) if input.is_zero() => one,
+
+        // e^0 = 1
+        ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
+
+        // (-1)^(±INF) = 1
+        ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
+
+        // 1^y = 1 for any y, even a NaN
+        ("powf32" | "powf64", [base, exp]) if *base == one => {
+            let rng = ecx.machine.rng.get_mut();
+            // SNaN exponents get special treatment: they might return 1, or a NaN.
+            let return_nan = exp.is_signaling() && ecx.machine.float_nondet && rng.random();
+            // Handle both the musl and glibc cases non-deterministically.
+            if return_nan { ecx.generate_nan(args) } else { one }
+        }
+
+        // x^(±0) = 1 for any x, even a NaN
+        ("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
+            let rng = ecx.machine.rng.get_mut();
+            // SNaN bases get special treatment: they might return 1, or a NaN.
+            let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random();
+            // Handle both the musl and glibc cases non-deterministically.
+            if return_nan { ecx.generate_nan(args) } else { one }
+        }
+
+        // There are a lot of cases for fixed outputs according to the C Standard, but these are
+        // mainly INF or zero which are not affected by the applied error.
+        _ => return None,
+    })
+}
+
+/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
+/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
+fn fixed_powi_float_value<S: Semantics>(
+    ecx: &mut MiriInterpCx<'_>,
+    base: IeeeFloat<S>,
+    exp: i32,
+) -> Option<IeeeFloat<S>> {
+    Some(match exp {
+        0 => {
+            let one = IeeeFloat::<S>::one();
+            let rng = ecx.machine.rng.get_mut();
+            let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
+            // For SNaN treatment, we are consistent with `powf`above.
+            // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
+            // but for now we are maximally conservative.)
+            if return_nan { ecx.generate_nan(&[base]) } else { one }
+        }
+
+        _ => return None,
+    })
+}
+
+/// Given an floating-point operation and a floating-point value, clamps the result to the output
+/// range of the given operation.
+fn clamp_float_value<S: Semantics>(intrinsic_name: &str, val: IeeeFloat<S>) -> IeeeFloat<S> {
+    match intrinsic_name {
+        // sin and cos: [-1, 1]
+        "sinf32" | "cosf32" | "sinf64" | "cosf64" =>
+            val.clamp(IeeeFloat::<S>::one().neg(), IeeeFloat::<S>::one()),
+        // exp: [0, +INF]
+        "expf32" | "exp2f32" | "expf64" | "exp2f64" =>
+            IeeeFloat::<S>::maximum(val, IeeeFloat::<S>::ZERO),
+        _ => val,
+    }
+}
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 9272cd29788..5ed6d6b346c 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -18,8 +18,6 @@
 #![feature(derive_coerce_pointee)]
 #![feature(arbitrary_self_types)]
 #![feature(iter_advance_by)]
-#![feature(f16)]
-#![feature(f128)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs
index 3eee6b82e8c..e9e5a1070c9 100644
--- a/src/tools/miri/src/math.rs
+++ b/src/tools/miri/src/math.rs
@@ -1,9 +1,6 @@
-use std::ops::Neg;
-use std::{f16, f32, f64, f128};
-
 use rand::Rng as _;
 use rustc_apfloat::Float as _;
-use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, Semantics, SingleS};
+use rustc_apfloat::ieee::IeeeFloat;
 use rustc_middle::ty::{self, FloatTy, ScalarInt};
 
 use crate::*;
@@ -53,236 +50,29 @@ pub(crate) fn apply_random_float_error_ulp<F: rustc_apfloat::Float>(
     apply_random_float_error(ecx, val, err_scale)
 }
 
-/// Applies a random ULP floating point error to `val` and returns the new value.
-/// So if you want an X ULP error, `ulp_exponent` should be log2(X).
-///
+/// Applies a random 16ULP floating point error to `val` and returns the new value.
 /// Will fail if `val` is not a floating point number.
 pub(crate) fn apply_random_float_error_to_imm<'tcx>(
     ecx: &mut MiriInterpCx<'tcx>,
     val: ImmTy<'tcx>,
     ulp_exponent: u32,
 ) -> InterpResult<'tcx, ImmTy<'tcx>> {
-    let this = ecx.eval_context_mut();
     let scalar = val.to_scalar_int()?;
     let res: ScalarInt = match val.layout.ty.kind() {
         ty::Float(FloatTy::F16) =>
-            apply_random_float_error_ulp(this, scalar.to_f16(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(),
         ty::Float(FloatTy::F32) =>
-            apply_random_float_error_ulp(this, scalar.to_f32(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(),
         ty::Float(FloatTy::F64) =>
-            apply_random_float_error_ulp(this, scalar.to_f64(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(),
         ty::Float(FloatTy::F128) =>
-            apply_random_float_error_ulp(this, scalar.to_f128(), ulp_exponent).into(),
+            apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(),
         _ => bug!("intrinsic called with non-float input type"),
     };
 
     interp_ok(ImmTy::from_scalar_int(res, val.layout))
 }
 
-/// Given a floating-point operation and a floating-point value, clamps the result to the output
-/// range of the given operation according to the C standard, if any.
-pub(crate) fn clamp_float_value<S: Semantics>(
-    intrinsic_name: &str,
-    val: IeeeFloat<S>,
-) -> IeeeFloat<S>
-where
-    IeeeFloat<S>: IeeeExt,
-{
-    let zero = IeeeFloat::<S>::ZERO;
-    let one = IeeeFloat::<S>::one();
-    let two = IeeeFloat::<S>::two();
-    let pi = IeeeFloat::<S>::pi();
-    let pi_over_2 = (pi / two).value;
-
-    match intrinsic_name {
-        // sin, cos, tanh: [-1, 1]
-        #[rustfmt::skip]
-        | "sinf32"
-        | "sinf64"
-        | "cosf32"
-        | "cosf64"
-        | "tanhf"
-        | "tanh"
-         => val.clamp(one.neg(), one),
-
-        // exp: [0, +INF)
-        "expf32" | "exp2f32" | "expf64" | "exp2f64" => val.maximum(zero),
-
-        // cosh: [1, +INF)
-        "coshf" | "cosh" => val.maximum(one),
-
-        // acos: [0, π]
-        "acosf" | "acos" => val.clamp(zero, pi),
-
-        // asin: [-π, +π]
-        "asinf" | "asin" => val.clamp(pi.neg(), pi),
-
-        // atan: (-π/2, +π/2)
-        "atanf" | "atan" => val.clamp(pi_over_2.neg(), pi_over_2),
-
-        // erfc: (-1, 1)
-        "erff" | "erf" => val.clamp(one.neg(), one),
-
-        // erfc: (0, 2)
-        "erfcf" | "erfc" => val.clamp(zero, two),
-
-        // atan2(y, x): arctan(y/x) in [−π, +π]
-        "atan2f" | "atan2" => val.clamp(pi.neg(), pi),
-
-        _ => val,
-    }
-}
-
-/// For the intrinsics:
-/// - sinf32, sinf64, sinhf, sinh
-/// - cosf32, cosf64, coshf, cosh
-/// - tanhf, tanh, atanf, atan, atan2f, atan2
-/// - expf32, expf64, exp2f32, exp2f64
-/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
-/// - powf32, powf64
-/// - erff, erf, erfcf, erfc
-/// - hypotf, hypot
-///
-/// # Return
-///
-/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
-/// (specifically, C23 annex F.10)  when given `args` as arguments. Outputs that are unaffected by a relative error
-/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
-/// implementation. Returns `None` if no specific value is guaranteed.
-///
-/// # Note
-///
-/// For `powf*` operations of the form:
-///
-/// - `(SNaN)^(±0)`
-/// - `1^(SNaN)`
-///
-/// The result is implementation-defined:
-/// - musl returns for both `1.0`
-/// - glibc returns for both `NaN`
-///
-/// This discrepancy exists because SNaN handling is not consistently defined across platforms,
-/// and the C standard leaves behavior for SNaNs unspecified.
-///
-/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
-pub(crate) fn fixed_float_value<S: Semantics>(
-    ecx: &mut MiriInterpCx<'_>,
-    intrinsic_name: &str,
-    args: &[IeeeFloat<S>],
-) -> Option<IeeeFloat<S>>
-where
-    IeeeFloat<S>: IeeeExt,
-{
-    let this = ecx.eval_context_mut();
-    let one = IeeeFloat::<S>::one();
-    let two = IeeeFloat::<S>::two();
-    let three = IeeeFloat::<S>::three();
-    let pi = IeeeFloat::<S>::pi();
-    let pi_over_2 = (pi / two).value;
-    let pi_over_4 = (pi_over_2 / two).value;
-
-    Some(match (intrinsic_name, args) {
-        // cos(±0) and cosh(±0)= 1
-        ("cosf32" | "cosf64" | "coshf" | "cosh", [input]) if input.is_zero() => one,
-
-        // e^0 = 1
-        ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
-
-        // tanh(±INF) = ±1
-        ("tanhf" | "tanh", [input]) if input.is_infinite() => one.copy_sign(*input),
-
-        // atan(±INF) = ±π/2
-        ("atanf" | "atan", [input]) if input.is_infinite() => pi_over_2.copy_sign(*input),
-
-        // erf(±INF) = ±1
-        ("erff" | "erf", [input]) if input.is_infinite() => one.copy_sign(*input),
-
-        // erfc(-INF) = 2
-        ("erfcf" | "erfc", [input]) if input.is_neg_infinity() => (one + one).value,
-
-        // hypot(x, ±0) = abs(x), if x is not a NaN.
-        ("_hypotf" | "hypotf" | "_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() =>
-            x.abs(),
-
-        // atan2(±0,−0) = ±π.
-        // atan2(±0, y) = ±π for y < 0.
-        // Must check for non NaN because `y.is_negative()` also applies to NaN.
-        ("atan2f" | "atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) =>
-            pi.copy_sign(*x),
-
-        // atan2(±x,−∞) = ±π for finite x > 0.
-        ("atan2f" | "atan2", [x, y])
-            if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() =>
-            pi.copy_sign(*x),
-
-        // atan2(x, ±0) = −π/2 for x < 0.
-        // atan2(x, ±0) =  π/2 for x > 0.
-        ("atan2f" | "atan2", [x, y]) if !x.is_zero() && y.is_zero() => pi_over_2.copy_sign(*x),
-
-        //atan2(±∞, −∞) = ±3π/4
-        ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_neg_infinity() =>
-            (pi_over_4 * three).value.copy_sign(*x),
-
-        //atan2(±∞, +∞) = ±π/4
-        ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() =>
-            pi_over_4.copy_sign(*x),
-
-        // atan2(±∞, y) returns ±π/2 for finite y.
-        ("atan2f" | "atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) =>
-            pi_over_2.copy_sign(*x),
-
-        // (-1)^(±INF) = 1
-        ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
-
-        // 1^y = 1 for any y, even a NaN
-        ("powf32" | "powf64", [base, exp]) if *base == one => {
-            let rng = this.machine.rng.get_mut();
-            // SNaN exponents get special treatment: they might return 1, or a NaN.
-            let return_nan = exp.is_signaling() && this.machine.float_nondet && rng.random();
-            // Handle both the musl and glibc cases non-deterministically.
-            if return_nan { this.generate_nan(args) } else { one }
-        }
-
-        // x^(±0) = 1 for any x, even a NaN
-        ("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
-            let rng = this.machine.rng.get_mut();
-            // SNaN bases get special treatment: they might return 1, or a NaN.
-            let return_nan = base.is_signaling() && this.machine.float_nondet && rng.random();
-            // Handle both the musl and glibc cases non-deterministically.
-            if return_nan { this.generate_nan(args) } else { one }
-        }
-
-        // There are a lot of cases for fixed outputs according to the C Standard, but these are
-        // mainly INF or zero which are not affected by the applied error.
-        _ => return None,
-    })
-}
-
-/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
-/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
-pub(crate) fn fixed_powi_value<S: Semantics>(
-    ecx: &mut MiriInterpCx<'_>,
-    base: IeeeFloat<S>,
-    exp: i32,
-) -> Option<IeeeFloat<S>>
-where
-    IeeeFloat<S>: IeeeExt,
-{
-    match exp {
-        0 => {
-            let one = IeeeFloat::<S>::one();
-            let rng = ecx.machine.rng.get_mut();
-            let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
-            // For SNaN treatment, we are consistent with `powf`above.
-            // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
-            // but for now we are maximally conservative.)
-            Some(if return_nan { ecx.generate_nan(&[base]) } else { one })
-        }
-
-        _ => return None,
-    }
-}
-
 pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFloat<S> {
     match x.category() {
         // preserve zero sign
@@ -365,49 +155,19 @@ pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFl
     }
 }
 
-/// Extend functionality of `rustc_apfloat` softfloats for IEEE float types.
+/// Extend functionality of rustc_apfloat softfloats
 pub trait IeeeExt: rustc_apfloat::Float {
-    // Some values we use:
-
     #[inline]
     fn one() -> Self {
         Self::from_u128(1).value
     }
 
     #[inline]
-    fn two() -> Self {
-        Self::from_u128(2).value
-    }
-
-    #[inline]
-    fn three() -> Self {
-        Self::from_u128(3).value
-    }
-
-    fn pi() -> Self;
-
-    #[inline]
     fn clamp(self, min: Self, max: Self) -> Self {
         self.maximum(min).minimum(max)
     }
 }
-
-macro_rules! impl_ieee_pi {
-    ($float_ty:ident, $semantic:ty) => {
-        impl IeeeExt for IeeeFloat<$semantic> {
-            #[inline]
-            fn pi() -> Self {
-                // We take the value from the standard library as the most reasonable source for an exact π here.
-                Self::from_bits($float_ty::consts::PI.to_bits() as _)
-            }
-        }
-    };
-}
-
-impl_ieee_pi!(f16, HalfS);
-impl_ieee_pi!(f32, SingleS);
-impl_ieee_pi!(f64, DoubleS);
-impl_ieee_pi!(f128, QuadS);
+impl<S: rustc_apfloat::ieee::Semantics> IeeeExt for IeeeFloat<S> {}
 
 #[cfg(test)]
 mod tests {
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index bf4db2de2d7..21545b68029 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -17,7 +17,6 @@ use rustc_target::callconv::FnAbi;
 use self::helpers::{ToHost, ToSoft};
 use super::alloc::EvalContextExt as _;
 use super::backtrace::EvalContextExt as _;
-use crate::helpers::EvalContextExt as _;
 use crate::*;
 
 /// Type of dynamic symbols (for `dlsym` et al)
@@ -780,38 +779,33 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             => {
                 let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
-
-                let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
-                    // Using host floats (but it's fine, these operations do not have
-                    // guaranteed precision).
-                    let f_host = f.to_host();
-                    let res = match link_name.as_str() {
-                        "cbrtf" => f_host.cbrt(),
-                        "coshf" => f_host.cosh(),
-                        "sinhf" => f_host.sinh(),
-                        "tanf" => f_host.tan(),
-                        "tanhf" => f_host.tanh(),
-                        "acosf" => f_host.acos(),
-                        "asinf" => f_host.asin(),
-                        "atanf" => f_host.atan(),
-                        "log1pf" => f_host.ln_1p(),
-                        "expm1f" => f_host.exp_m1(),
-                        "tgammaf" => f_host.gamma(),
-                        "erff" => f_host.erf(),
-                        "erfcf" => f_host.erfc(),
-                        _ => bug!(),
-                    };
-                    let res = res.to_soft();
-                    // Apply a relative error of 4ULP to introduce some non-determinism
-                    // simulating imprecise implementations and optimizations.
-                    let res = math::apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    );
-
-                    // Clamp the result to the guaranteed range of this function according to the C standard,
-                    // if any.
-                    math::clamp_float_value(link_name.as_str(), res)
-                });
+                // Using host floats (but it's fine, these operations do not have guaranteed precision).
+                let f_host = f.to_host();
+                let res = match link_name.as_str() {
+                    "cbrtf" => f_host.cbrt(),
+                    "coshf" => f_host.cosh(),
+                    "sinhf" => f_host.sinh(),
+                    "tanf" => f_host.tan(),
+                    "tanhf" => f_host.tanh(),
+                    "acosf" => f_host.acos(),
+                    "asinf" => f_host.asin(),
+                    "atanf" => f_host.atan(),
+                    "log1pf" => f_host.ln_1p(),
+                    "expm1f" => f_host.exp_m1(),
+                    "tgammaf" => f_host.gamma(),
+                    "erff" => f_host.erf(),
+                    "erfcf" => f_host.erfc(),
+                    _ => bug!(),
+                };
+                let res = res.to_soft();
+                // Apply a relative error of 16ULP to introduce some non-determinism
+                // simulating imprecise implementations and optimizations.
+                // FIXME: temporarily disabled as it breaks std tests.
+                // let res = math::apply_random_float_error_ulp(
+                //     this,
+                //     res,
+                //     4, // log2(16)
+                // );
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
@@ -824,28 +818,24 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f32()?;
                 let f2 = this.read_scalar(f2)?.to_f32()?;
-
-                let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| {
-                    let res = match link_name.as_str() {
-                        // underscore case for windows, here and below
-                        // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
-                        // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                        "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
-                        "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
-                        #[allow(deprecated)]
-                        "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
-                        _ => bug!(),
-                    };
-                    // Apply a relative error of 4ULP to introduce some non-determinism
-                    // simulating imprecise implementations and optimizations.
-                    let res = math::apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    );
-
-                    // Clamp the result to the guaranteed range of this function according to the C standard,
-                    // if any.
-                    math::clamp_float_value(link_name.as_str(), res)
-                });
+                // underscore case for windows, here and below
+                // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
+                // Using host floats (but it's fine, these operations do not have guaranteed precision).
+                let res = match link_name.as_str() {
+                    "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
+                    "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
+                    #[allow(deprecated)]
+                    "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
+                    _ => bug!(),
+                };
+                // Apply a relative error of 16ULP to introduce some non-determinism
+                // simulating imprecise implementations and optimizations.
+                // FIXME: temporarily disabled as it breaks std tests.
+                // let res = math::apply_random_float_error_ulp(
+                //     this,
+                //     res,
+                //     4, // log2(16)
+                // );
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -866,38 +856,33 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             => {
                 let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
-
-                let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
-                    // Using host floats (but it's fine, these operations do not have
-                    // guaranteed precision).
-                    let f_host = f.to_host();
-                    let res = match link_name.as_str() {
-                        "cbrt" => f_host.cbrt(),
-                        "cosh" => f_host.cosh(),
-                        "sinh" => f_host.sinh(),
-                        "tan" => f_host.tan(),
-                        "tanh" => f_host.tanh(),
-                        "acos" => f_host.acos(),
-                        "asin" => f_host.asin(),
-                        "atan" => f_host.atan(),
-                        "log1p" => f_host.ln_1p(),
-                        "expm1" => f_host.exp_m1(),
-                        "tgamma" => f_host.gamma(),
-                        "erf" => f_host.erf(),
-                        "erfc" => f_host.erfc(),
-                        _ => bug!(),
-                    };
-                    let res = res.to_soft();
-                    // Apply a relative error of 4ULP to introduce some non-determinism
-                    // simulating imprecise implementations and optimizations.
-                    let res = math::apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    );
-
-                    // Clamp the result to the guaranteed range of this function according to the C standard,
-                    // if any.
-                    math::clamp_float_value(link_name.as_str(), res)
-                });
+                // Using host floats (but it's fine, these operations do not have guaranteed precision).
+                let f_host = f.to_host();
+                let res = match link_name.as_str() {
+                    "cbrt" => f_host.cbrt(),
+                    "cosh" => f_host.cosh(),
+                    "sinh" => f_host.sinh(),
+                    "tan" => f_host.tan(),
+                    "tanh" => f_host.tanh(),
+                    "acos" => f_host.acos(),
+                    "asin" => f_host.asin(),
+                    "atan" => f_host.atan(),
+                    "log1p" => f_host.ln_1p(),
+                    "expm1" => f_host.exp_m1(),
+                    "tgamma" => f_host.gamma(),
+                    "erf" => f_host.erf(),
+                    "erfc" => f_host.erfc(),
+                    _ => bug!(),
+                };
+                let res = res.to_soft();
+                // Apply a relative error of 16ULP to introduce some non-determinism
+                // simulating imprecise implementations and optimizations.
+                // FIXME: temporarily disabled as it breaks std tests.
+                // let res = math::apply_random_float_error_ulp(
+                //     this,
+                //     res.to_soft(),
+                //     4, // log2(16)
+                // );
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
@@ -910,28 +895,24 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f64()?;
                 let f2 = this.read_scalar(f2)?.to_f64()?;
-
-                let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| {
-                    let res = match link_name.as_str() {
-                        // underscore case for windows, here and below
-                        // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
-                        // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                        "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
-                        "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
-                        #[allow(deprecated)]
-                        "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
-                        _ => bug!(),
-                    };
-                    // Apply a relative error of 4ULP to introduce some non-determinism
-                    // simulating imprecise implementations and optimizations.
-                    let res = math::apply_random_float_error_ulp(
-                        this, res, 2, // log2(4)
-                    );
-
-                    // Clamp the result to the guaranteed range of this function according to the C standard,
-                    // if any.
-                    math::clamp_float_value(link_name.as_str(), res)
-                });
+                // underscore case for windows, here and below
+                // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
+                // Using host floats (but it's fine, these operations do not have guaranteed precision).
+                let res = match link_name.as_str() {
+                    "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
+                    "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
+                    #[allow(deprecated)]
+                    "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
+                    _ => bug!(),
+                };
+                // Apply a relative error of 16ULP to introduce some non-determinism
+                // simulating imprecise implementations and optimizations.
+                // FIXME: temporarily disabled as it breaks std tests.
+                // let res = math::apply_random_float_error_ulp(
+                //     this,
+                //     res,
+                //     4, // log2(16)
+                // );
                 let res = this.adjust_nan(res, &[f1, f2]);
                 this.write_scalar(res, dest)?;
             }
@@ -957,14 +938,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let (res, sign) = x.to_host().ln_gamma();
                 this.write_int(sign, &signp)?;
-
                 let res = res.to_soft();
-                // Apply a relative error of 4ULP to introduce some non-determinism
+                // Apply a relative error of 16ULP to introduce some non-determinism
                 // simulating imprecise implementations and optimizations.
-                let res = math::apply_random_float_error_ulp(this, res, 2 /* log2(4) */);
-                // Clamp the result to the guaranteed range of this function according to the C standard,
-                // if any.
-                let res = math::clamp_float_value(link_name.as_str(), res);
+                // FIXME: temporarily disabled as it breaks std tests.
+                // let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */);
                 let res = this.adjust_nan(res, &[x]);
                 this.write_scalar(res, dest)?;
             }
@@ -976,14 +954,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let (res, sign) = x.to_host().ln_gamma();
                 this.write_int(sign, &signp)?;
-
                 let res = res.to_soft();
-                // Apply a relative error of 4ULP to introduce some non-determinism
+                // Apply a relative error of 16ULP to introduce some non-determinism
                 // simulating imprecise implementations and optimizations.
-                let res = math::apply_random_float_error_ulp(this, res, 2 /* log2(4) */);
-                // Clamp the result to the guaranteed range of this function according to the C standard,
-                // if any.
-                let res = math::clamp_float_value(link_name.as_str(), res);
+                // FIXME: temporarily disabled as it breaks std tests.
+                // let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */);
                 let res = this.adjust_nan(res, &[x]);
                 this.write_scalar(res, dest)?;
             }
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 96590b4bf2b..fe7316c6680 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -1088,8 +1088,6 @@ pub fn libm() {
 
     assert_approx_eq!(1f32.exp_m1(), f32::consts::E - 1.0);
     assert_approx_eq!(1f64.exp_m1(), f64::consts::E - 1.0);
-    assert_approx_eq!(f32::NEG_INFINITY.exp_m1(), -1.0);
-    assert_approx_eq!(f64::NEG_INFINITY.exp_m1(), -1.0);
 
     assert_approx_eq!(10f32.exp2(), 1024f32);
     assert_approx_eq!(50f64.exp2(), 1125899906842624f64);
@@ -1125,7 +1123,6 @@ pub fn libm() {
     assert_eq!(ldexp(0.65f64, 3i32), 5.2f64);
     assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY);
     assert_eq!(ldexp(1.42, -0xFFFF), 0f64);
-    assert_eq!(ldexp(42.0, 0), 42.0);
 
     // Trigonometric functions.
 
@@ -1134,14 +1131,8 @@ pub fn libm() {
     assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64);
     assert_approx_eq!(f32::consts::FRAC_PI_6.sin(), 0.5);
     assert_approx_eq!(f64::consts::FRAC_PI_6.sin(), 0.5);
-    // Increase error tolerance from 12ULP to 16ULP because of the extra operation.
-    assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4, 16);
-    assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4, 16);
-    assert_biteq(0.0f32.asin(), 0.0f32, "asin(+0) = +0");
-    assert_biteq((-0.0f32).asin(), -0.0, "asin(-0) = -0");
-    assert_biteq(0.0f64.asin(), 0.0, "asin(+0) = +0");
-    assert_biteq((-0.0f64).asin(), -0.0, "asin(-0) = -0");
-
+    assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4);
+    assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4);
 
     assert_approx_eq!(1.0f32.sinh(), 1.1752012f32);
     assert_approx_eq!(1.0f64.sinh(), 1.1752011936438014f64);
@@ -1168,18 +1159,11 @@ pub fn libm() {
     assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64);
     assert_approx_eq!(f32::consts::FRAC_PI_3.cos(), 0.5);
     assert_approx_eq!(f64::consts::FRAC_PI_3.cos(), 0.5);
-    // Increase error tolerance from 12ULP to 16ULP because of the extra operation.
-    assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4, 16);
-    assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4, 16);
-    assert_biteq(1.0f32.acos(), 0.0, "acos(1) = 0");
-    assert_biteq(1.0f64.acos(), 0.0, "acos(1) = 0");
+    assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4);
+    assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4);
 
     assert_approx_eq!(1.0f32.cosh(), 1.54308f32);
     assert_approx_eq!(1.0f64.cosh(), 1.5430806348152437f64);
-    assert_eq!(0.0f32.cosh(), 1.0);
-    assert_eq!(0.0f64.cosh(), 1.0);
-    assert_eq!((-0.0f32).cosh(), 1.0);
-    assert_eq!((-0.0f64).cosh(), 1.0);
     assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
     assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
 
@@ -1189,47 +1173,6 @@ pub fn libm() {
     assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan());
     assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32);
     assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32);
-    // C standard defines a bunch of fixed outputs for atan2
-    macro_rules! fixed_atan2_cases{
-        ($float_type:ident) => {{
-            use std::$float_type::consts::{PI, FRAC_PI_2, FRAC_PI_4};
-            use $float_type::{INFINITY, NEG_INFINITY};
-
-            // atan2(±0,−0) = ±π.
-            assert_eq!($float_type::atan2(0.0, -0.0), PI, "atan2(0,−0) = π");
-            assert_eq!($float_type::atan2(-0.0, -0.0), -PI, "atan2(-0,−0) = -π");
-
-            // atan2(±0, y) = ±π for y < 0.
-            assert_eq!($float_type::atan2(0.0, -1.0), PI, "atan2(0, y) = π for y < 0.");
-            assert_eq!($float_type::atan2(-0.0, -1.0), -PI, "atan2(-0, y) = -π for y < 0.");
-
-            // atan2(x, ±0) = −π/2 for x < 0.
-            assert_eq!($float_type::atan2(-1.0, 0.0), -FRAC_PI_2, "atan2(x, 0) = −π/2 for x < 0");
-            assert_eq!($float_type::atan2(-1.0, -0.0), -FRAC_PI_2, "atan2(x, -0) = −π/2 for x < 0");
-
-            // atan2(x, ±0) =  π/2 for x > 0.
-            assert_eq!($float_type::atan2(1.0, 0.0), FRAC_PI_2, "atan2(x, 0) =  π/2 for x > 0.");
-            assert_eq!($float_type::atan2(1.0, -0.0), FRAC_PI_2, "atan2(x, -0) =  π/2 for x > 0.");
-
-            // atan2(±x,−∞) = ±π for finite x > 0.
-            assert_eq!($float_type::atan2(1.0, NEG_INFINITY), PI, "atan2(x, −∞) = π for finite x > 0");
-            assert_eq!($float_type::atan2(-1.0, NEG_INFINITY), -PI, "atan2(-x, −∞) = -π for finite x > 0");
-
-            // atan2(±∞, y) returns ±π/2 for finite y.
-            assert_eq!($float_type::atan2(INFINITY, 1.0), FRAC_PI_2, "atan2(+∞, y) returns π/2 for finite y");
-            assert_eq!($float_type::atan2(NEG_INFINITY, 1.0), -FRAC_PI_2, "atan2(-∞, y) returns -π/2 for finite y");
-
-            // atan2(±∞, −∞) = ±3π/4
-            assert_eq!($float_type::atan2(INFINITY, NEG_INFINITY), 3.0 * FRAC_PI_4, "atan2(+∞, −∞) = 3π/4");
-            assert_eq!($float_type::atan2(NEG_INFINITY, NEG_INFINITY), -3.0 * FRAC_PI_4, "atan2(-∞, −∞) = -3π/4");
-
-            // atan2(±∞, +∞) = ±π/4
-            assert_eq!($float_type::atan2(INFINITY, INFINITY), FRAC_PI_4, "atan2(+∞, +∞) = π/4");
-            assert_eq!($float_type::atan2(NEG_INFINITY, INFINITY), -FRAC_PI_4, "atan2(-∞, +∞) = -π/4");
-        }}
-    }
-    fixed_atan2_cases!(f32);
-    fixed_atan2_cases!(f64);
 
     assert_approx_eq!(
         1.0f32.tanh(),
@@ -1239,11 +1182,6 @@ pub fn libm() {
         1.0f64.tanh(),
         (1.0 - f64::consts::E.powi(-2)) / (1.0 + f64::consts::E.powi(-2))
     );
-    assert_eq!(f32::INFINITY.tanh(), 1.0);
-    assert_eq!(f32::NEG_INFINITY.tanh(), -1.0);
-    assert_eq!(f64::INFINITY.tanh(), 1.0);
-    assert_eq!(f64::NEG_INFINITY.tanh(), -1.0);
-
     assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
     assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
 
@@ -1264,14 +1202,8 @@ pub fn libm() {
 
     assert_approx_eq!(1.0f32.erf(), 0.84270079294971486934122063508260926f32);
     assert_approx_eq!(1.0f64.erf(), 0.84270079294971486934122063508260926f64);
-    assert_eq!(f32::INFINITY.erf(), 1.0);
-    assert_eq!(f64::INFINITY.erf(), 1.0);
     assert_approx_eq!(1.0f32.erfc(), 0.15729920705028513065877936491739074f32);
     assert_approx_eq!(1.0f64.erfc(), 0.15729920705028513065877936491739074f64);
-    assert_eq!(f32::NEG_INFINITY.erfc(), 2.0);
-    assert_eq!(f64::NEG_INFINITY.erfc(), 2.0);
-    assert_eq!(f32::INFINITY.erfc(), 0.0);
-    assert_eq!(f64::INFINITY.erfc(), 0.0);
 }
 
 fn test_fast() {
@@ -1481,6 +1413,7 @@ fn test_non_determinism() {
     }
     pub fn test_operations_f32(a: f32, b: f32) {
         test_operations_f!(a, b);
+        // FIXME: some are temporarily disabled as it breaks std tests.
         ensure_nondet(|| a.powf(b));
         ensure_nondet(|| a.powi(2));
         ensure_nondet(|| a.log(b));
@@ -1489,34 +1422,35 @@ fn test_non_determinism() {
         ensure_nondet(|| f32::consts::E.ln());
         ensure_nondet(|| 10f32.log10());
         ensure_nondet(|| 8f32.log2());
-        ensure_nondet(|| 1f32.ln_1p());
-        ensure_nondet(|| 27.0f32.cbrt());
-        ensure_nondet(|| 3.0f32.hypot(4.0f32));
+        // ensure_nondet(|| 1f32.ln_1p());
+        // ensure_nondet(|| 27.0f32.cbrt());
+        // ensure_nondet(|| 3.0f32.hypot(4.0f32));
         ensure_nondet(|| 1f32.sin());
         ensure_nondet(|| 1f32.cos());
         // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version,
         // which means the little rounding errors Miri introduces are discarded by the cast down to
         // `f32`. Just skip the test for them.
-        if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) {
-            ensure_nondet(|| 1.0f32.tan());
-            ensure_nondet(|| 1.0f32.asin());
-            ensure_nondet(|| 5.0f32.acos());
-            ensure_nondet(|| 1.0f32.atan());
-            ensure_nondet(|| 1.0f32.atan2(2.0f32));
-            ensure_nondet(|| 1.0f32.sinh());
-            ensure_nondet(|| 1.0f32.cosh());
-            ensure_nondet(|| 1.0f32.tanh());
-        }
-        ensure_nondet(|| 1.0f32.asinh());
-        ensure_nondet(|| 2.0f32.acosh());
-        ensure_nondet(|| 0.5f32.atanh());
-        ensure_nondet(|| 5.0f32.gamma());
-        ensure_nondet(|| 5.0f32.ln_gamma());
-        ensure_nondet(|| 5.0f32.erf());
-        ensure_nondet(|| 5.0f32.erfc());
+        // if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) {
+        //     ensure_nondet(|| 1.0f32.tan());
+        //     ensure_nondet(|| 1.0f32.asin());
+        //     ensure_nondet(|| 5.0f32.acos());
+        //     ensure_nondet(|| 1.0f32.atan());
+        //     ensure_nondet(|| 1.0f32.atan2(2.0f32));
+        //     ensure_nondet(|| 1.0f32.sinh());
+        //     ensure_nondet(|| 1.0f32.cosh());
+        //     ensure_nondet(|| 1.0f32.tanh());
+        // }
+        // ensure_nondet(|| 1.0f32.asinh());
+        // ensure_nondet(|| 2.0f32.acosh());
+        // ensure_nondet(|| 0.5f32.atanh());
+        // ensure_nondet(|| 5.0f32.gamma());
+        // ensure_nondet(|| 5.0f32.ln_gamma());
+        // ensure_nondet(|| 5.0f32.erf());
+        // ensure_nondet(|| 5.0f32.erfc());
     }
     pub fn test_operations_f64(a: f64, b: f64) {
         test_operations_f!(a, b);
+        // FIXME: some are temporarily disabled as it breaks std tests.
         ensure_nondet(|| a.powf(b));
         ensure_nondet(|| a.powi(2));
         ensure_nondet(|| a.log(b));
@@ -1525,26 +1459,26 @@ fn test_non_determinism() {
         ensure_nondet(|| 3f64.ln());
         ensure_nondet(|| f64::consts::E.log10());
         ensure_nondet(|| f64::consts::E.log2());
-        ensure_nondet(|| 1f64.ln_1p());
-        ensure_nondet(|| 27.0f64.cbrt());
-        ensure_nondet(|| 3.0f64.hypot(4.0f64));
+        // ensure_nondet(|| 1f64.ln_1p());
+        // ensure_nondet(|| 27.0f64.cbrt());
+        // ensure_nondet(|| 3.0f64.hypot(4.0f64));
         ensure_nondet(|| 1f64.sin());
         ensure_nondet(|| 1f64.cos());
-        ensure_nondet(|| 1.0f64.tan());
-        ensure_nondet(|| 1.0f64.asin());
-        ensure_nondet(|| 5.0f64.acos());
-        ensure_nondet(|| 1.0f64.atan());
-        ensure_nondet(|| 1.0f64.atan2(2.0f64));
-        ensure_nondet(|| 1.0f64.sinh());
-        ensure_nondet(|| 1.0f64.cosh());
-        ensure_nondet(|| 1.0f64.tanh());
-        ensure_nondet(|| 1.0f64.asinh());
-        ensure_nondet(|| 3.0f64.acosh());
-        ensure_nondet(|| 0.5f64.atanh());
-        ensure_nondet(|| 5.0f64.gamma());
-        ensure_nondet(|| 5.0f64.ln_gamma());
-        ensure_nondet(|| 5.0f64.erf());
-        ensure_nondet(|| 5.0f64.erfc());
+        // ensure_nondet(|| 1.0f64.tan());
+        // ensure_nondet(|| 1.0f64.asin());
+        // ensure_nondet(|| 5.0f64.acos());
+        // ensure_nondet(|| 1.0f64.atan());
+        // ensure_nondet(|| 1.0f64.atan2(2.0f64));
+        // ensure_nondet(|| 1.0f64.sinh());
+        // ensure_nondet(|| 1.0f64.cosh());
+        // ensure_nondet(|| 1.0f64.tanh());
+        // ensure_nondet(|| 1.0f64.asinh());
+        // ensure_nondet(|| 3.0f64.acosh());
+        // ensure_nondet(|| 0.5f64.atanh());
+        // ensure_nondet(|| 5.0f64.gamma());
+        // ensure_nondet(|| 5.0f64.ln_gamma());
+        // ensure_nondet(|| 5.0f64.erf());
+        // ensure_nondet(|| 5.0f64.erfc());
     }
     pub fn test_operations_f128(a: f128, b: f128) {
         test_operations_f!(a, b);