Skip to content

Commit aec2f66

Browse files
committed
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](rust-lang/miri#4208) and [#3555](rust-lang/miri#3555) in Miri. Non-determinism of floating point operations was disabled in #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](rust-lang/miri#4286 (comment)) - 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 rust-lang/miri#4208
2 parents 7c10378 + 00452bd commit aec2f66

File tree

12 files changed

+386
-107
lines changed

12 files changed

+386
-107
lines changed

library/core/src/num/f32.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1879,7 +1879,7 @@ pub mod math {
18791879
///
18801880
/// let x = 2.0_f32;
18811881
/// let abs_difference = (f32::math::powi(x, 2) - (x * x)).abs();
1882-
/// assert!(abs_difference <= f32::EPSILON);
1882+
/// assert!(abs_difference <= 1e-5);
18831883
///
18841884
/// assert_eq!(f32::math::powi(f32::NAN, 0), 1.0);
18851885
/// ```

library/core/src/num/f64.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,7 @@ pub mod math {
18771877
///
18781878
/// let x = 2.0_f64;
18791879
/// let abs_difference = (f64::math::powi(x, 2) - (x * x)).abs();
1880-
/// assert!(abs_difference <= f64::EPSILON);
1880+
/// assert!(abs_difference <= 1e-6);
18811881
///
18821882
/// assert_eq!(f64::math::powi(f64::NAN, 0), 1.0);
18831883
/// ```

library/coretests/tests/floats/f32.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const NAN_MASK1: u32 = 0x002a_aaaa;
2323
/// Second pattern over the mantissa
2424
const NAN_MASK2: u32 = 0x0055_5555;
2525

26+
/// Miri adds some extra errors to float functions; make sure the tests still pass.
27+
/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides.
28+
/// They serve as a way to get an idea of the real precision of floating point operations on different platforms.
29+
const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 };
30+
2631
#[test]
2732
fn test_num_f32() {
2833
super::test_num(10f32, 2f32);
@@ -437,8 +442,8 @@ fn test_powi() {
437442
let nan: f32 = f32::NAN;
438443
let inf: f32 = f32::INFINITY;
439444
let neg_inf: f32 = f32::NEG_INFINITY;
440-
assert_biteq!(1.0f32.powi(1), 1.0);
441-
assert_approx_eq!((-3.1f32).powi(2), 9.61);
445+
assert_approx_eq!(1.0f32.powi(1), 1.0);
446+
assert_approx_eq!((-3.1f32).powi(2), 9.61, APPROX_DELTA);
442447
assert_approx_eq!(5.9f32.powi(-2), 0.028727);
443448
assert_biteq!(8.3f32.powi(0), 1.0);
444449
assert!(nan.powi(2).is_nan());

library/coretests/tests/floats/f64.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ fn test_powi() {
422422
let nan: f64 = f64::NAN;
423423
let inf: f64 = f64::INFINITY;
424424
let neg_inf: f64 = f64::NEG_INFINITY;
425-
assert_biteq!(1.0f64.powi(1), 1.0);
425+
assert_approx_eq!(1.0f64.powi(1), 1.0);
426426
assert_approx_eq!((-3.1f64).powi(2), 9.61);
427427
assert_approx_eq!(5.9f64.powi(-2), 0.028727);
428428
assert_biteq!(8.3f64.powi(0), 1.0);

library/coretests/tests/num/dec2flt/float.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ fn test_f16_integer_decode() {
2323
fn test_f32_integer_decode() {
2424
assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
2525
assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
26-
assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
26+
// Set 2^100 directly instead of using powf, because it doesn't guarentee precision
27+
assert_eq!(1.2676506e30_f32.integer_decode(), (8388608, 77, 1));
2728
assert_eq!(0f32.integer_decode(), (0, -150, 1));
2829
assert_eq!((-0f32).integer_decode(), (0, -150, -1));
2930
assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1));
@@ -39,7 +40,8 @@ fn test_f32_integer_decode() {
3940
fn test_f64_integer_decode() {
4041
assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
4142
assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
42-
assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
43+
// Set 2^100 directly instead of using powf, because it doesn't guarentee precision
44+
assert_eq!(1.2676506002282294e30_f64.integer_decode(), (4503599627370496, 48, 1));
4345
assert_eq!(0f64.integer_decode(), (0, -1075, 1));
4446
assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
4547
assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1));

library/std/src/num/f32.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ impl f32 {
304304
/// ```
305305
/// let x = 2.0_f32;
306306
/// let abs_difference = (x.powi(2) - (x * x)).abs();
307-
/// assert!(abs_difference <= f32::EPSILON);
307+
/// assert!(abs_difference <= 1e-5);
308308
///
309309
/// assert_eq!(f32::powi(f32::NAN, 0), 1.0);
310310
/// ```
@@ -328,7 +328,7 @@ impl f32 {
328328
/// ```
329329
/// let x = 2.0_f32;
330330
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
331-
/// assert!(abs_difference <= f32::EPSILON);
331+
/// assert!(abs_difference <= 1e-5);
332332
///
333333
/// assert_eq!(f32::powf(1.0, f32::NAN), 1.0);
334334
/// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0);
@@ -388,7 +388,7 @@ impl f32 {
388388
/// // ln(e) - 1 == 0
389389
/// let abs_difference = (e.ln() - 1.0).abs();
390390
///
391-
/// assert!(abs_difference <= f32::EPSILON);
391+
/// assert!(abs_difference <= 1e-6);
392392
/// ```
393393
#[rustc_allow_incoherent_impl]
394394
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -413,7 +413,7 @@ impl f32 {
413413
/// // 2^2 - 4 == 0
414414
/// let abs_difference = (f.exp2() - 4.0).abs();
415415
///
416-
/// assert!(abs_difference <= f32::EPSILON);
416+
/// assert!(abs_difference <= 1e-5);
417417
/// ```
418418
#[rustc_allow_incoherent_impl]
419419
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -442,7 +442,7 @@ impl f32 {
442442
/// // ln(e) - 1 == 0
443443
/// let abs_difference = (e.ln() - 1.0).abs();
444444
///
445-
/// assert!(abs_difference <= f32::EPSILON);
445+
/// assert!(abs_difference <= 1e-6);
446446
/// ```
447447
///
448448
/// Non-positive values:
@@ -479,7 +479,7 @@ impl f32 {
479479
/// // log5(5) - 1 == 0
480480
/// let abs_difference = (five.log(5.0) - 1.0).abs();
481481
///
482-
/// assert!(abs_difference <= f32::EPSILON);
482+
/// assert!(abs_difference <= 1e-6);
483483
/// ```
484484
///
485485
/// Non-positive values:
@@ -512,7 +512,7 @@ impl f32 {
512512
/// // log2(2) - 1 == 0
513513
/// let abs_difference = (two.log2() - 1.0).abs();
514514
///
515-
/// assert!(abs_difference <= f32::EPSILON);
515+
/// assert!(abs_difference <= 1e-6);
516516
/// ```
517517
///
518518
/// Non-positive values:
@@ -545,7 +545,7 @@ impl f32 {
545545
/// // log10(10) - 1 == 0
546546
/// let abs_difference = (ten.log10() - 1.0).abs();
547547
///
548-
/// assert!(abs_difference <= f32::EPSILON);
548+
/// assert!(abs_difference <= 1e-6);
549549
/// ```
550550
///
551551
/// Non-positive values:
@@ -652,7 +652,7 @@ impl f32 {
652652
/// // sqrt(x^2 + y^2)
653653
/// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
654654
///
655-
/// assert!(abs_difference <= f32::EPSILON);
655+
/// assert!(abs_difference <= 1e-6);
656656
/// ```
657657
#[rustc_allow_incoherent_impl]
658658
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -676,7 +676,7 @@ impl f32 {
676676
///
677677
/// let abs_difference = (x.sin() - 1.0).abs();
678678
///
679-
/// assert!(abs_difference <= f32::EPSILON);
679+
/// assert!(abs_difference <= 1e-6);
680680
/// ```
681681
#[rustc_allow_incoherent_impl]
682682
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -700,7 +700,7 @@ impl f32 {
700700
///
701701
/// let abs_difference = (x.cos() - 1.0).abs();
702702
///
703-
/// assert!(abs_difference <= f32::EPSILON);
703+
/// assert!(abs_difference <= 1e-6);
704704
/// ```
705705
#[rustc_allow_incoherent_impl]
706706
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -754,7 +754,7 @@ impl f32 {
754754
/// // asin(sin(pi/2))
755755
/// let abs_difference = (f.sin().asin() - std::f32::consts::FRAC_PI_2).abs();
756756
///
757-
/// assert!(abs_difference <= f32::EPSILON);
757+
/// assert!(abs_difference <= 1e-3);
758758
/// ```
759759
#[doc(alias = "arcsin")]
760760
#[rustc_allow_incoherent_impl]
@@ -784,7 +784,7 @@ impl f32 {
784784
/// // acos(cos(pi/4))
785785
/// let abs_difference = (f.cos().acos() - std::f32::consts::FRAC_PI_4).abs();
786786
///
787-
/// assert!(abs_difference <= f32::EPSILON);
787+
/// assert!(abs_difference <= 1e-6);
788788
/// ```
789789
#[doc(alias = "arccos")]
790790
#[rustc_allow_incoherent_impl]
@@ -884,8 +884,8 @@ impl f32 {
884884
/// let abs_difference_0 = (f.0 - x.sin()).abs();
885885
/// let abs_difference_1 = (f.1 - x.cos()).abs();
886886
///
887-
/// assert!(abs_difference_0 <= f32::EPSILON);
888-
/// assert!(abs_difference_1 <= f32::EPSILON);
887+
/// assert!(abs_difference_0 <= 1e-6);
888+
/// assert!(abs_difference_1 <= 1e-6);
889889
/// ```
890890
#[doc(alias = "sincos")]
891891
#[rustc_allow_incoherent_impl]
@@ -1067,7 +1067,7 @@ impl f32 {
10671067
///
10681068
/// let abs_difference = (f - x).abs();
10691069
///
1070-
/// assert!(abs_difference <= f32::EPSILON);
1070+
/// assert!(abs_difference <= 1e-7);
10711071
/// ```
10721072
#[doc(alias = "arcsinh")]
10731073
#[rustc_allow_incoherent_impl]
@@ -1095,7 +1095,7 @@ impl f32 {
10951095
///
10961096
/// let abs_difference = (f - x).abs();
10971097
///
1098-
/// assert!(abs_difference <= f32::EPSILON);
1098+
/// assert!(abs_difference <= 1e-6);
10991099
/// ```
11001100
#[doc(alias = "arccosh")]
11011101
#[rustc_allow_incoherent_impl]

library/std/src/num/f64.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ impl f64 {
304304
/// ```
305305
/// let x = 2.0_f64;
306306
/// let abs_difference = (x.powi(2) - (x * x)).abs();
307-
/// assert!(abs_difference <= f64::EPSILON);
307+
/// assert!(abs_difference <= 1e-14);
308308
///
309309
/// assert_eq!(f64::powi(f64::NAN, 0), 1.0);
310310
/// ```
@@ -328,7 +328,7 @@ impl f64 {
328328
/// ```
329329
/// let x = 2.0_f64;
330330
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
331-
/// assert!(abs_difference <= f64::EPSILON);
331+
/// assert!(abs_difference <= 1e-14);
332332
///
333333
/// assert_eq!(f64::powf(1.0, f64::NAN), 1.0);
334334
/// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0);
@@ -754,7 +754,7 @@ impl f64 {
754754
/// // asin(sin(pi/2))
755755
/// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs();
756756
///
757-
/// assert!(abs_difference < 1e-10);
757+
/// assert!(abs_difference < 1e-7);
758758
/// ```
759759
#[doc(alias = "arcsin")]
760760
#[rustc_allow_incoherent_impl]

library/std/tests/floats/f32.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
use std::f32::consts;
22

3+
/// Miri adds some extra errors to float functions; make sure the tests still pass.
4+
/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides.
5+
/// They serve as a way to get an idea of the real precision of floating point operations on different platforms.
6+
const APPROX_DELTA: f32 = if cfg!(miri) { 1e-3 } else { 1e-6 };
7+
38
#[allow(unused_macros)]
49
macro_rules! assert_f32_biteq {
510
($left : expr, $right : expr) => {
@@ -17,9 +22,9 @@ fn test_powf() {
1722
let inf: f32 = f32::INFINITY;
1823
let neg_inf: f32 = f32::NEG_INFINITY;
1924
assert_eq!(1.0f32.powf(1.0), 1.0);
20-
assert_approx_eq!(3.4f32.powf(4.5), 246.408218);
25+
assert_approx_eq!(3.4f32.powf(4.5), 246.408218, APPROX_DELTA);
2126
assert_approx_eq!(2.7f32.powf(-3.2), 0.041652);
22-
assert_approx_eq!((-3.1f32).powf(2.0), 9.61);
27+
assert_approx_eq!((-3.1f32).powf(2.0), 9.61, APPROX_DELTA);
2328
assert_approx_eq!(5.9f32.powf(-2.0), 0.028727);
2429
assert_eq!(8.3f32.powf(0.0), 1.0);
2530
assert!(nan.powf(2.0).is_nan());
@@ -30,8 +35,8 @@ fn test_powf() {
3035
#[test]
3136
fn test_exp() {
3237
assert_eq!(1.0, 0.0f32.exp());
33-
assert_approx_eq!(2.718282, 1.0f32.exp());
34-
assert_approx_eq!(148.413162, 5.0f32.exp());
38+
assert_approx_eq!(2.718282, 1.0f32.exp(), APPROX_DELTA);
39+
assert_approx_eq!(148.413162, 5.0f32.exp(), APPROX_DELTA);
3540

3641
let inf: f32 = f32::INFINITY;
3742
let neg_inf: f32 = f32::NEG_INFINITY;
@@ -43,7 +48,7 @@ fn test_exp() {
4348

4449
#[test]
4550
fn test_exp2() {
46-
assert_eq!(32.0, 5.0f32.exp2());
51+
assert_approx_eq!(32.0, 5.0f32.exp2(), APPROX_DELTA);
4752
assert_eq!(1.0, 0.0f32.exp2());
4853

4954
let inf: f32 = f32::INFINITY;
@@ -66,17 +71,17 @@ fn test_ln() {
6671
assert!((-2.3f32).ln().is_nan());
6772
assert_eq!((-0.0f32).ln(), neg_inf);
6873
assert_eq!(0.0f32.ln(), neg_inf);
69-
assert_approx_eq!(4.0f32.ln(), 1.386294);
74+
assert_approx_eq!(4.0f32.ln(), 1.386294, APPROX_DELTA);
7075
}
7176

7277
#[test]
7378
fn test_log() {
7479
let nan: f32 = f32::NAN;
7580
let inf: f32 = f32::INFINITY;
7681
let neg_inf: f32 = f32::NEG_INFINITY;
77-
assert_eq!(10.0f32.log(10.0), 1.0);
82+
assert_approx_eq!(10.0f32.log(10.0), 1.0);
7883
assert_approx_eq!(2.3f32.log(3.5), 0.664858);
79-
assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0);
84+
assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA);
8085
assert!(1.0f32.log(1.0).is_nan());
8186
assert!(1.0f32.log(-13.9).is_nan());
8287
assert!(nan.log(2.3).is_nan());
@@ -92,9 +97,9 @@ fn test_log2() {
9297
let nan: f32 = f32::NAN;
9398
let inf: f32 = f32::INFINITY;
9499
let neg_inf: f32 = f32::NEG_INFINITY;
95-
assert_approx_eq!(10.0f32.log2(), 3.321928);
100+
assert_approx_eq!(10.0f32.log2(), 3.321928, APPROX_DELTA);
96101
assert_approx_eq!(2.3f32.log2(), 1.201634);
97-
assert_approx_eq!(1.0f32.exp().log2(), 1.442695);
102+
assert_approx_eq!(1.0f32.exp().log2(), 1.442695, APPROX_DELTA);
98103
assert!(nan.log2().is_nan());
99104
assert_eq!(inf.log2(), inf);
100105
assert!(neg_inf.log2().is_nan());
@@ -108,7 +113,7 @@ fn test_log10() {
108113
let nan: f32 = f32::NAN;
109114
let inf: f32 = f32::INFINITY;
110115
let neg_inf: f32 = f32::NEG_INFINITY;
111-
assert_eq!(10.0f32.log10(), 1.0);
116+
assert_approx_eq!(10.0f32.log10(), 1.0);
112117
assert_approx_eq!(2.3f32.log10(), 0.361728);
113118
assert_approx_eq!(1.0f32.exp().log10(), 0.434294);
114119
assert_eq!(1.0f32.log10(), 0.0);
@@ -158,7 +163,7 @@ fn test_acosh() {
158163
assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
159164

160165
// test for low accuracy from issue 104548
161-
assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh());
166+
assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh(), APPROX_DELTA);
162167
}
163168

164169
#[test]
@@ -237,7 +242,7 @@ fn test_real_consts() {
237242
let ln_10: f32 = consts::LN_10;
238243

239244
assert_approx_eq!(frac_pi_2, pi / 2f32);
240-
assert_approx_eq!(frac_pi_3, pi / 3f32);
245+
assert_approx_eq!(frac_pi_3, pi / 3f32, APPROX_DELTA);
241246
assert_approx_eq!(frac_pi_4, pi / 4f32);
242247
assert_approx_eq!(frac_pi_6, pi / 6f32);
243248
assert_approx_eq!(frac_pi_8, pi / 8f32);
@@ -249,5 +254,5 @@ fn test_real_consts() {
249254
assert_approx_eq!(log2_e, e.log2());
250255
assert_approx_eq!(log10_e, e.log10());
251256
assert_approx_eq!(ln_2, 2f32.ln());
252-
assert_approx_eq!(ln_10, 10f32.ln());
257+
assert_approx_eq!(ln_10, 10f32.ln(), APPROX_DELTA);
253258
}

library/std/tests/floats/f64.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn test_exp() {
4343

4444
#[test]
4545
fn test_exp2() {
46-
assert_eq!(32.0, 5.0f64.exp2());
46+
assert_approx_eq!(32.0, 5.0f64.exp2());
4747
assert_eq!(1.0, 0.0f64.exp2());
4848

4949
let inf: f64 = f64::INFINITY;
@@ -74,9 +74,9 @@ fn test_log() {
7474
let nan: f64 = f64::NAN;
7575
let inf: f64 = f64::INFINITY;
7676
let neg_inf: f64 = f64::NEG_INFINITY;
77-
assert_eq!(10.0f64.log(10.0), 1.0);
77+
assert_approx_eq!(10.0f64.log(10.0), 1.0);
7878
assert_approx_eq!(2.3f64.log(3.5), 0.664858);
79-
assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
79+
assert_approx_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
8080
assert!(1.0f64.log(1.0).is_nan());
8181
assert!(1.0f64.log(-13.9).is_nan());
8282
assert!(nan.log(2.3).is_nan());
@@ -108,7 +108,7 @@ fn test_log10() {
108108
let nan: f64 = f64::NAN;
109109
let inf: f64 = f64::INFINITY;
110110
let neg_inf: f64 = f64::NEG_INFINITY;
111-
assert_eq!(10.0f64.log10(), 1.0);
111+
assert_approx_eq!(10.0f64.log10(), 1.0);
112112
assert_approx_eq!(2.3f64.log10(), 0.361728);
113113
assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
114114
assert_eq!(1.0f64.log10(), 0.0);

0 commit comments

Comments
 (0)