Skip to content

Enable Non-determinism of float operations in Miri and change std tests #138062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
69a5eee
add tests to check that the operations behave like the Ieee and C sta…
LorrensP-2158466 Mar 5, 2025
058699e
enable non-determinism but with smaller error, 4ULP; conform to IEEE …
LorrensP-2158466 Mar 5, 2025
072830f
set 2^100 directly in integer decode tests because powf is non-determ…
LorrensP-2158466 Mar 5, 2025
aa357af
assert_approx_eq! now accepts up to 1e-4
LorrensP-2158466 Mar 5, 2025
50f7653
change tests that made wrong assumptions about the Ieee and C standards
LorrensP-2158466 Mar 5, 2025
4d352c5
fix copy/paste mistake
LorrensP-2158466 Mar 6, 2025
8d6de60
apply simple requests from reviewer
LorrensP-2158466 Mar 10, 2025
776c9af
change assert_approx_eq! back to old version and manually set error t…
LorrensP-2158466 Mar 10, 2025
a2b9890
change doc-tests to increase EPSILON to make the tests pass
LorrensP-2158466 Mar 10, 2025
6342266
deduplicate code of pow functions to use a macro instead
LorrensP-2158466 Mar 10, 2025
a9efc0d
extend `fixed_float_value` to accept powf + create fix_float_value fn…
LorrensP-2158466 Mar 11, 2025
362829b
clean up
LorrensP-2158466 Mar 12, 2025
8430fed
apply changes from review + minor doc fixes
LorrensP-2158466 Mar 19, 2025
4ea76ec
approx delta different when running in miri
LorrensP-2158466 Apr 6, 2025
199c92c
2 more crashes fixed
LorrensP-2158466 Apr 7, 2025
802085d
inline FloatExt::one and move this traitimpl for IEEE
LorrensP-2158466 Apr 8, 2025
3cd4fc4
handling of sign nans
LorrensP-2158466 Apr 18, 2025
06d35ce
consistend handling of fixed outputs
LorrensP-2158466 Apr 18, 2025
66311a1
cleanup messy tests and remove duplicates
LorrensP-2158466 Apr 18, 2025
90bbebc
add fixme regarding powi(snan, 0)
LorrensP-2158466 Apr 20, 2025
f770948
fix the fixme comment
LorrensP-2158466 Apr 20, 2025
6913301
update fixmes to inlcude the issue
LorrensP-2158466 Apr 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions library/coretests/tests/num/dec2flt/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use core::num::dec2flt::float::RawFloat;
fn test_f32_integer_decode() {
assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
// Set 2^100 directly instead of using powf, because it doesn't guarentee precision
assert_eq!(1.2676506e30_f32.integer_decode(), (8388608, 77, 1));
assert_eq!(0f32.integer_decode(), (0, -150, 1));
assert_eq!((-0f32).integer_decode(), (0, -150, -1));
assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1));
Expand All @@ -20,7 +21,8 @@ fn test_f32_integer_decode() {
fn test_f64_integer_decode() {
assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
// Set 2^100 directly instead of using powf, because it doesn't guarentee precision
assert_eq!(1.2676506002282294e30_f64.integer_decode(), (4503599627370496, 48, 1));
assert_eq!(0f64.integer_decode(), (0, -1075, 1));
assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1));
Expand Down
32 changes: 16 additions & 16 deletions library/std/src/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,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 <= 8.0 * f32::EPSILON);
///
/// assert_eq!(f32::powi(f32::NAN, 0), 1.0);
/// ```
Expand All @@ -327,7 +327,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 <= 8.0 * f32::EPSILON);
///
/// assert_eq!(f32::powf(1.0, f32::NAN), 1.0);
/// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0);
Expand Down Expand Up @@ -387,7 +387,7 @@ impl f32 {
/// // ln(e) - 1 == 0
/// let abs_difference = (e.ln() - 1.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
Expand All @@ -412,7 +412,7 @@ impl f32 {
/// // 2^2 - 4 == 0
/// let abs_difference = (f.exp2() - 4.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 8.0 * f32::EPSILON);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
Expand Down Expand Up @@ -441,7 +441,7 @@ impl f32 {
/// // ln(e) - 1 == 0
/// let abs_difference = (e.ln() - 1.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
///
/// Non-positive values:
Expand Down Expand Up @@ -478,7 +478,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 <= 4.0 * f32::EPSILON);
/// ```
///
/// Non-positive values:
Expand Down Expand Up @@ -511,7 +511,7 @@ impl f32 {
/// // log2(2) - 1 == 0
/// let abs_difference = (two.log2() - 1.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
///
/// Non-positive values:
Expand Down Expand Up @@ -544,7 +544,7 @@ impl f32 {
/// // log10(10) - 1 == 0
/// let abs_difference = (ten.log10() - 1.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
///
/// Non-positive values:
Expand Down Expand Up @@ -650,7 +650,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 <= 4.0 * f32::EPSILON);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
Expand All @@ -674,7 +674,7 @@ impl f32 {
///
/// let abs_difference = (x.sin() - 1.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
Expand All @@ -698,7 +698,7 @@ impl f32 {
///
/// let abs_difference = (x.cos() - 1.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
Expand Down Expand Up @@ -782,7 +782,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 <= 4.0 * f32::EPSILON);
/// ```
#[doc(alias = "arccos")]
#[rustc_allow_incoherent_impl]
Expand Down Expand Up @@ -882,8 +882,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 <= 4.0 * f32::EPSILON);
/// assert!(abs_difference_1 <= 4.0 * f32::EPSILON);
/// ```
#[doc(alias = "sincos")]
#[rustc_allow_incoherent_impl]
Expand Down Expand Up @@ -1065,7 +1065,7 @@ impl f32 {
///
/// let abs_difference = (f - x).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
#[doc(alias = "arcsinh")]
#[rustc_allow_incoherent_impl]
Expand Down Expand Up @@ -1093,7 +1093,7 @@ impl f32 {
///
/// let abs_difference = (f - x).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 4.0 * f32::EPSILON);
/// ```
#[doc(alias = "arccosh")]
#[rustc_allow_incoherent_impl]
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,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 <= 8.0 * f64::EPSILON);
///
/// assert_eq!(f64::powi(f64::NAN, 0), 1.0);
/// ```
Expand All @@ -327,7 +327,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 <= 8.0 * f64::EPSILON);
///
/// assert_eq!(f64::powf(1.0, f64::NAN), 1.0);
/// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0);
Expand Down
65 changes: 51 additions & 14 deletions library/std/tests/floats/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ const NAN_MASK1: u32 = 0x002a_aaaa;
/// Second pattern over the mantissa
const NAN_MASK2: u32 = 0x0055_5555;

/// 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-4 } else { 1e-6 };

#[allow(unused_macros)]
macro_rules! assert_f32_biteq {
($left : expr, $right : expr) => {
Expand Down Expand Up @@ -442,8 +447,12 @@ fn test_powi() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.powi(1), 1.0);
assert_approx_eq!((-3.1f32).powi(2), 9.61);
assert_approx_eq!(1.0f32.powi(1), 1.0);
assert_approx_eq!(
(-3.1f32).powi(2),
9.61,
APPROX_DELTA /* Miri float-non-det: Make tests pass for now */
);
assert_approx_eq!(5.9f32.powi(-2), 0.028727);
assert_eq!(8.3f32.powi(0), 1.0);
assert!(nan.powi(2).is_nan());
Expand All @@ -457,9 +466,17 @@ 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 /* Miri float-non-det: Make tests pass for now */
);
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 /* Miri float-non-det: Make tests pass for now */
);
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());
Expand All @@ -481,8 +498,12 @@ fn test_sqrt_domain() {
#[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 /* Miri float-non-det: Make tests pass for now */
);

let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
Expand All @@ -494,7 +515,11 @@ fn test_exp() {

#[test]
fn test_exp2() {
assert_eq!(32.0, 5.0f32.exp2());
assert_approx_eq!(
32.0,
5.0f32.exp2(),
APPROX_DELTA /* Miri float-non-det: Make tests pass for now */
);
assert_eq!(1.0, 0.0f32.exp2());

let inf: f32 = f32::INFINITY;
Expand All @@ -517,17 +542,21 @@ 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 /* Miri float-non-det: Make tests pass for now */
);
}

#[test]
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);
assert!(1.0f32.log(1.0).is_nan());
assert!(1.0f32.log(-13.9).is_nan());
assert!(nan.log(2.3).is_nan());
Expand Down Expand Up @@ -559,7 +588,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);
Expand Down Expand Up @@ -639,7 +668,11 @@ 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 /* Miri float-non-det: Make tests pass for now */
);
}

#[test]
Expand Down Expand Up @@ -718,7 +751,11 @@ 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 /* Miri float-non-det: Make tests pass for now */
);
assert_approx_eq!(frac_pi_4, pi / 4f32);
assert_approx_eq!(frac_pi_6, pi / 6f32);
assert_approx_eq!(frac_pi_8, pi / 8f32);
Expand All @@ -730,7 +767,7 @@ 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);
}

#[test]
Expand Down
10 changes: 5 additions & 5 deletions library/std/tests/floats/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ fn test_powi() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(1.0f64.powi(1), 1.0);
assert_approx_eq!(1.0f64.powi(1), 1.0);
assert_approx_eq!((-3.1f64).powi(2), 9.61);
assert_approx_eq!(5.9f64.powi(-2), 0.028727);
assert_eq!(8.3f64.powi(0), 1.0);
Expand Down Expand Up @@ -479,7 +479,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;
Expand Down Expand Up @@ -510,9 +510,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());
Expand Down Expand Up @@ -544,7 +544,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);
Expand Down
Loading
Loading