8
8
#![ allow( internal_features) ]
9
9
#![ allow( unnecessary_transmutes) ]
10
10
11
+ #[ path = "../utils/mod.rs" ]
12
+ mod utils;
11
13
use std:: any:: type_name;
12
14
use std:: cmp:: min;
13
15
use std:: fmt:: { Debug , Display , LowerHex } ;
14
16
use std:: hint:: black_box;
15
17
use std:: { f32, f64} ;
16
18
19
+ use utils:: check_nondet;
20
+
17
21
/// Compare the two floats, allowing for $ulp many ULPs of error.
18
22
///
19
23
/// ULP means "Units in the Last Place" or "Units of Least Precision".
@@ -1429,29 +1433,14 @@ fn test_fmuladd() {
1429
1433
1430
1434
/// `min` and `max` on equal arguments are non-deterministic.
1431
1435
fn test_min_max_nondet ( ) {
1432
- /// Ensure that if we call the closure often enough, we see both `true` and `false.`
1433
- #[ track_caller]
1434
- fn ensure_both ( f : impl Fn ( ) -> bool ) {
1435
- let rounds = 32 ;
1436
- let first = f ( ) ;
1437
- for _ in 1 ..rounds {
1438
- if f ( ) != first {
1439
- // We saw two different values!
1440
- return ;
1441
- }
1442
- }
1443
- // We saw the same thing N times.
1444
- panic ! ( "expected non-determinism, got {rounds} times the same result: {first:?}" ) ;
1445
- }
1446
-
1447
- ensure_both ( || f16:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1448
- ensure_both ( || f16:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1449
- ensure_both ( || f32:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1450
- ensure_both ( || f32:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1451
- ensure_both ( || f64:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1452
- ensure_both ( || f64:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1453
- ensure_both ( || f128:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1454
- ensure_both ( || f128:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1436
+ check_nondet ( || f16:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1437
+ check_nondet ( || f16:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1438
+ check_nondet ( || f32:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1439
+ check_nondet ( || f32:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1440
+ check_nondet ( || f64:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1441
+ check_nondet ( || f64:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1442
+ check_nondet ( || f128:: min ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1443
+ check_nondet ( || f128:: max ( 0.0 , -0.0 ) . is_sign_positive ( ) ) ;
1455
1444
}
1456
1445
1457
1446
fn test_non_determinism ( ) {
@@ -1461,35 +1450,20 @@ fn test_non_determinism() {
1461
1450
} ;
1462
1451
use std:: { f32, f64} ;
1463
1452
1464
- /// Ensure that the operation is non-deterministic
1465
- #[ track_caller]
1466
- fn ensure_nondet < T : PartialEq + std:: fmt:: Debug > ( f : impl Fn ( ) -> T ) {
1467
- let rounds = 16 ;
1468
- let first = f ( ) ;
1469
- for _ in 1 ..rounds {
1470
- if f ( ) != first {
1471
- // We saw two different values!
1472
- return ;
1473
- }
1474
- }
1475
- // We saw the same thing N times.
1476
- panic ! ( "expected non-determinism, got {rounds} times the same result: {first:?}" ) ;
1477
- }
1478
-
1479
1453
macro_rules! test_operations_f {
1480
1454
( $a: expr, $b: expr) => {
1481
- ensure_nondet ( || fadd_algebraic( $a, $b) ) ;
1482
- ensure_nondet ( || fsub_algebraic( $a, $b) ) ;
1483
- ensure_nondet ( || fmul_algebraic( $a, $b) ) ;
1484
- ensure_nondet ( || fdiv_algebraic( $a, $b) ) ;
1485
- ensure_nondet ( || frem_algebraic( $a, $b) ) ;
1455
+ check_nondet ( || fadd_algebraic( $a, $b) ) ;
1456
+ check_nondet ( || fsub_algebraic( $a, $b) ) ;
1457
+ check_nondet ( || fmul_algebraic( $a, $b) ) ;
1458
+ check_nondet ( || fdiv_algebraic( $a, $b) ) ;
1459
+ check_nondet ( || frem_algebraic( $a, $b) ) ;
1486
1460
1487
1461
unsafe {
1488
- ensure_nondet ( || fadd_fast( $a, $b) ) ;
1489
- ensure_nondet ( || fsub_fast( $a, $b) ) ;
1490
- ensure_nondet ( || fmul_fast( $a, $b) ) ;
1491
- ensure_nondet ( || fdiv_fast( $a, $b) ) ;
1492
- ensure_nondet ( || frem_fast( $a, $b) ) ;
1462
+ check_nondet ( || fadd_fast( $a, $b) ) ;
1463
+ check_nondet ( || fsub_fast( $a, $b) ) ;
1464
+ check_nondet ( || fmul_fast( $a, $b) ) ;
1465
+ check_nondet ( || fdiv_fast( $a, $b) ) ;
1466
+ check_nondet ( || frem_fast( $a, $b) ) ;
1493
1467
}
1494
1468
} ;
1495
1469
}
@@ -1499,70 +1473,70 @@ fn test_non_determinism() {
1499
1473
}
1500
1474
pub fn test_operations_f32 ( a : f32 , b : f32 ) {
1501
1475
test_operations_f ! ( a, b) ;
1502
- ensure_nondet ( || a. powf ( b) ) ;
1503
- ensure_nondet ( || a. powi ( 2 ) ) ;
1504
- ensure_nondet ( || a. log ( b) ) ;
1505
- ensure_nondet ( || a. exp ( ) ) ;
1506
- ensure_nondet ( || 10f32 . exp2 ( ) ) ;
1507
- ensure_nondet ( || f32:: consts:: E . ln ( ) ) ;
1508
- ensure_nondet ( || 10f32 . log10 ( ) ) ;
1509
- ensure_nondet ( || 8f32 . log2 ( ) ) ;
1510
- ensure_nondet ( || 1f32 . ln_1p ( ) ) ;
1511
- ensure_nondet ( || 27.0f32 . cbrt ( ) ) ;
1512
- ensure_nondet ( || 3.0f32 . hypot ( 4.0f32 ) ) ;
1513
- ensure_nondet ( || 1f32 . sin ( ) ) ;
1514
- ensure_nondet ( || 1f32 . cos ( ) ) ;
1476
+ check_nondet ( || a. powf ( b) ) ;
1477
+ check_nondet ( || a. powi ( 2 ) ) ;
1478
+ check_nondet ( || a. log ( b) ) ;
1479
+ check_nondet ( || a. exp ( ) ) ;
1480
+ check_nondet ( || 10f32 . exp2 ( ) ) ;
1481
+ check_nondet ( || f32:: consts:: E . ln ( ) ) ;
1482
+ check_nondet ( || 10f32 . log10 ( ) ) ;
1483
+ check_nondet ( || 8f32 . log2 ( ) ) ;
1484
+ check_nondet ( || 1f32 . ln_1p ( ) ) ;
1485
+ check_nondet ( || 27.0f32 . cbrt ( ) ) ;
1486
+ check_nondet ( || 3.0f32 . hypot ( 4.0f32 ) ) ;
1487
+ check_nondet ( || 1f32 . sin ( ) ) ;
1488
+ check_nondet ( || 1f32 . cos ( ) ) ;
1515
1489
// On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version,
1516
1490
// which means the little rounding errors Miri introduces are discarded by the cast down to
1517
1491
// `f32`. Just skip the test for them.
1518
1492
if !cfg ! ( all( target_os = "windows" , target_env = "msvc" , target_arch = "x86" ) ) {
1519
- ensure_nondet ( || 1.0f32 . tan ( ) ) ;
1520
- ensure_nondet ( || 1.0f32 . asin ( ) ) ;
1521
- ensure_nondet ( || 5.0f32 . acos ( ) ) ;
1522
- ensure_nondet ( || 1.0f32 . atan ( ) ) ;
1523
- ensure_nondet ( || 1.0f32 . atan2 ( 2.0f32 ) ) ;
1524
- ensure_nondet ( || 1.0f32 . sinh ( ) ) ;
1525
- ensure_nondet ( || 1.0f32 . cosh ( ) ) ;
1526
- ensure_nondet ( || 1.0f32 . tanh ( ) ) ;
1493
+ check_nondet ( || 1.0f32 . tan ( ) ) ;
1494
+ check_nondet ( || 1.0f32 . asin ( ) ) ;
1495
+ check_nondet ( || 5.0f32 . acos ( ) ) ;
1496
+ check_nondet ( || 1.0f32 . atan ( ) ) ;
1497
+ check_nondet ( || 1.0f32 . atan2 ( 2.0f32 ) ) ;
1498
+ check_nondet ( || 1.0f32 . sinh ( ) ) ;
1499
+ check_nondet ( || 1.0f32 . cosh ( ) ) ;
1500
+ check_nondet ( || 1.0f32 . tanh ( ) ) ;
1527
1501
}
1528
- ensure_nondet ( || 1.0f32 . asinh ( ) ) ;
1529
- ensure_nondet ( || 2.0f32 . acosh ( ) ) ;
1530
- ensure_nondet ( || 0.5f32 . atanh ( ) ) ;
1531
- ensure_nondet ( || 5.0f32 . gamma ( ) ) ;
1532
- ensure_nondet ( || 5.0f32 . ln_gamma ( ) ) ;
1533
- ensure_nondet ( || 5.0f32 . erf ( ) ) ;
1534
- ensure_nondet ( || 5.0f32 . erfc ( ) ) ;
1502
+ check_nondet ( || 1.0f32 . asinh ( ) ) ;
1503
+ check_nondet ( || 2.0f32 . acosh ( ) ) ;
1504
+ check_nondet ( || 0.5f32 . atanh ( ) ) ;
1505
+ check_nondet ( || 5.0f32 . gamma ( ) ) ;
1506
+ check_nondet ( || 5.0f32 . ln_gamma ( ) ) ;
1507
+ check_nondet ( || 5.0f32 . erf ( ) ) ;
1508
+ check_nondet ( || 5.0f32 . erfc ( ) ) ;
1535
1509
}
1536
1510
pub fn test_operations_f64 ( a : f64 , b : f64 ) {
1537
1511
test_operations_f ! ( a, b) ;
1538
- ensure_nondet ( || a. powf ( b) ) ;
1539
- ensure_nondet ( || a. powi ( 2 ) ) ;
1540
- ensure_nondet ( || a. log ( b) ) ;
1541
- ensure_nondet ( || a. exp ( ) ) ;
1542
- ensure_nondet ( || 50f64 . exp2 ( ) ) ;
1543
- ensure_nondet ( || 3f64 . ln ( ) ) ;
1544
- ensure_nondet ( || f64:: consts:: E . log10 ( ) ) ;
1545
- ensure_nondet ( || f64:: consts:: E . log2 ( ) ) ;
1546
- ensure_nondet ( || 1f64 . ln_1p ( ) ) ;
1547
- ensure_nondet ( || 27.0f64 . cbrt ( ) ) ;
1548
- ensure_nondet ( || 3.0f64 . hypot ( 4.0f64 ) ) ;
1549
- ensure_nondet ( || 1f64 . sin ( ) ) ;
1550
- ensure_nondet ( || 1f64 . cos ( ) ) ;
1551
- ensure_nondet ( || 1.0f64 . tan ( ) ) ;
1552
- ensure_nondet ( || 1.0f64 . asin ( ) ) ;
1553
- ensure_nondet ( || 5.0f64 . acos ( ) ) ;
1554
- ensure_nondet ( || 1.0f64 . atan ( ) ) ;
1555
- ensure_nondet ( || 1.0f64 . atan2 ( 2.0f64 ) ) ;
1556
- ensure_nondet ( || 1.0f64 . sinh ( ) ) ;
1557
- ensure_nondet ( || 1.0f64 . cosh ( ) ) ;
1558
- ensure_nondet ( || 1.0f64 . tanh ( ) ) ;
1559
- ensure_nondet ( || 1.0f64 . asinh ( ) ) ;
1560
- ensure_nondet ( || 3.0f64 . acosh ( ) ) ;
1561
- ensure_nondet ( || 0.5f64 . atanh ( ) ) ;
1562
- ensure_nondet ( || 5.0f64 . gamma ( ) ) ;
1563
- ensure_nondet ( || 5.0f64 . ln_gamma ( ) ) ;
1564
- ensure_nondet ( || 5.0f64 . erf ( ) ) ;
1565
- ensure_nondet ( || 5.0f64 . erfc ( ) ) ;
1512
+ check_nondet ( || a. powf ( b) ) ;
1513
+ check_nondet ( || a. powi ( 2 ) ) ;
1514
+ check_nondet ( || a. log ( b) ) ;
1515
+ check_nondet ( || a. exp ( ) ) ;
1516
+ check_nondet ( || 50f64 . exp2 ( ) ) ;
1517
+ check_nondet ( || 3f64 . ln ( ) ) ;
1518
+ check_nondet ( || f64:: consts:: E . log10 ( ) ) ;
1519
+ check_nondet ( || f64:: consts:: E . log2 ( ) ) ;
1520
+ check_nondet ( || 1f64 . ln_1p ( ) ) ;
1521
+ check_nondet ( || 27.0f64 . cbrt ( ) ) ;
1522
+ check_nondet ( || 3.0f64 . hypot ( 4.0f64 ) ) ;
1523
+ check_nondet ( || 1f64 . sin ( ) ) ;
1524
+ check_nondet ( || 1f64 . cos ( ) ) ;
1525
+ check_nondet ( || 1.0f64 . tan ( ) ) ;
1526
+ check_nondet ( || 1.0f64 . asin ( ) ) ;
1527
+ check_nondet ( || 5.0f64 . acos ( ) ) ;
1528
+ check_nondet ( || 1.0f64 . atan ( ) ) ;
1529
+ check_nondet ( || 1.0f64 . atan2 ( 2.0f64 ) ) ;
1530
+ check_nondet ( || 1.0f64 . sinh ( ) ) ;
1531
+ check_nondet ( || 1.0f64 . cosh ( ) ) ;
1532
+ check_nondet ( || 1.0f64 . tanh ( ) ) ;
1533
+ check_nondet ( || 1.0f64 . asinh ( ) ) ;
1534
+ check_nondet ( || 3.0f64 . acosh ( ) ) ;
1535
+ check_nondet ( || 0.5f64 . atanh ( ) ) ;
1536
+ check_nondet ( || 5.0f64 . gamma ( ) ) ;
1537
+ check_nondet ( || 5.0f64 . ln_gamma ( ) ) ;
1538
+ check_nondet ( || 5.0f64 . erf ( ) ) ;
1539
+ check_nondet ( || 5.0f64 . erfc ( ) ) ;
1566
1540
}
1567
1541
pub fn test_operations_f128 ( a : f128 , b : f128 ) {
1568
1542
test_operations_f ! ( a, b) ;
@@ -1574,15 +1548,15 @@ fn test_non_determinism() {
1574
1548
test_operations_f128 ( 25. , 18. ) ;
1575
1549
1576
1550
// SNaN^0 = (1 | NaN)
1577
- ensure_nondet ( || f32:: powf ( SNAN_F32 , 0.0 ) . is_nan ( ) ) ;
1578
- ensure_nondet ( || f64:: powf ( SNAN_F64 , 0.0 ) . is_nan ( ) ) ;
1551
+ check_nondet ( || f32:: powf ( SNAN_F32 , 0.0 ) . is_nan ( ) ) ;
1552
+ check_nondet ( || f64:: powf ( SNAN_F64 , 0.0 ) . is_nan ( ) ) ;
1579
1553
1580
1554
// 1^SNaN = (1 | NaN)
1581
- ensure_nondet ( || f32:: powf ( 1.0 , SNAN_F32 ) . is_nan ( ) ) ;
1582
- ensure_nondet ( || f64:: powf ( 1.0 , SNAN_F64 ) . is_nan ( ) ) ;
1555
+ check_nondet ( || f32:: powf ( 1.0 , SNAN_F32 ) . is_nan ( ) ) ;
1556
+ check_nondet ( || f64:: powf ( 1.0 , SNAN_F64 ) . is_nan ( ) ) ;
1583
1557
1584
1558
// same as powf (keep it consistent):
1585
1559
// x^SNaN = (1 | NaN)
1586
- ensure_nondet ( || f32:: powi ( SNAN_F32 , 0 ) . is_nan ( ) ) ;
1587
- ensure_nondet ( || f64:: powi ( SNAN_F64 , 0 ) . is_nan ( ) ) ;
1560
+ check_nondet ( || f32:: powi ( SNAN_F32 , 0 ) . is_nan ( ) ) ;
1561
+ check_nondet ( || f64:: powi ( SNAN_F64 , 0 ) . is_nan ( ) ) ;
1588
1562
}
0 commit comments