Skip to content

Commit dae9908

Browse files
committed
interpret: test SNaN handling of float min/max and update comments
1 parent 864339a commit dae9908

File tree

2 files changed

+28
-33
lines changed

2 files changed

+28
-33
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,19 @@ pub(crate) enum MinMax {
4040
/// In particular, `-0.0` is considered smaller than `+0.0` and
4141
/// if either input is NaN, the result is NaN.
4242
Minimum,
43-
/// The IEEE-2008 `minNum` operation - see `f32::min` etc.
43+
/// The IEEE-2008 `minNum` operation with the SNaN handling of the
44+
/// IEEE-2019 `minimumNumber` operation - see `f32::min` etc.
4445
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
45-
/// and if one argument is NaN, the other one is returned.
46+
/// and if one argument is NaN (quiet or signaling), the other one is returned.
4647
MinNum,
4748
/// The IEEE-2019 `maximum` operation - see `f32::maximum` etc.
4849
/// In particular, `-0.0` is considered smaller than `+0.0` and
4950
/// if either input is NaN, the result is NaN.
5051
Maximum,
51-
/// The IEEE-2008 `maxNum` operation - see `f32::max` etc.
52+
/// The IEEE-2008 `maxNum` operation with the SNaN handling of the
53+
/// IEEE-2019 `maximumNumber` operation - see `f32::max` etc.
5254
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
53-
/// and if one argument is NaN, the other one is returned.
55+
/// and if one argument is NaN (quiet or signaling), the other one is returned.
5456
MaxNum,
5557
}
5658

src/tools/miri/tests/pass/float.rs

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,29 +48,14 @@ macro_rules! assert_approx_eq {
4848
};
4949
}
5050

51-
/// From IEEE 754 a Signaling NaN for single precision has the following representation:
52-
/// ```
53-
/// s | 1111 1111 | 0x..x
54-
/// ````
55-
/// Were at least one `x` is a 1.
56-
///
57-
/// This sNaN has the following representation and is used for testing purposes.:
58-
/// ```
59-
/// 0 | 1111111 | 01..0
60-
/// ```
61-
const SNAN_F32: f32 = f32::from_bits(0x7fa00000);
62-
63-
/// From IEEE 754 a Signaling NaN for double precision has the following representation:
64-
/// ```
65-
/// s | 1111 1111 111 | 0x..x
66-
/// ````
67-
/// Were at least one `x` is a 1.
68-
///
69-
/// This sNaN has the following representation and is used for testing purposes.:
70-
/// ```
71-
/// 0 | 1111 1111 111 | 01..0
72-
/// ```
73-
const SNAN_F64: f64 = f64::from_bits(0x7ff4000000000000);
51+
/// We turn the quiet NaN f*::NAN into a signaling one by flipping the first (most significant)
52+
/// two bits of the mantissa. For this we have to shift by `MANTISSA_DIGITS-3` because:
53+
/// we subtract 1 as the actual mantissa is 1 bit smaller, and 2 more as that's the width
54+
/// if the value we are shifting.
55+
const F16_SNAN: f16 =f16::from_bits(f16::NAN.to_bits() ^ (0b11 << (f16::MANTISSA_DIGITS-3)));
56+
const F32_SNAN: f32 =f32::from_bits(f32::NAN.to_bits() ^ (0b11 << (f32::MANTISSA_DIGITS-3)));
57+
const F64_SNAN: f64 =f64::from_bits(f64::NAN.to_bits() ^ (0b11 << (f64::MANTISSA_DIGITS-3)));
58+
const F128_SNAN: f128 =f128::from_bits(f128::NAN.to_bits() ^ (0b11 << (f128::MANTISSA_DIGITS-3)));
7459

7560
fn main() {
7661
basic();
@@ -757,6 +742,8 @@ fn ops() {
757742
assert_eq(f16::NAN.max(-9.0), -9.0);
758743
assert_eq((9.0_f16).min(f16::NAN), 9.0);
759744
assert_eq((-9.0_f16).max(f16::NAN), -9.0);
745+
assert_eq(F16_SNAN.min(9.0), 9.0);
746+
assert_eq((-9.0_f16).max(F16_SNAN), -9.0);
760747

761748
// f32 min/max
762749
assert_eq((1.0 as f32).max(-1.0), 1.0);
@@ -765,6 +752,8 @@ fn ops() {
765752
assert_eq(f32::NAN.max(-9.0), -9.0);
766753
assert_eq((9.0 as f32).min(f32::NAN), 9.0);
767754
assert_eq((-9.0 as f32).max(f32::NAN), -9.0);
755+
assert_eq(F32_SNAN.min(9.0), 9.0);
756+
assert_eq((-9.0_f32).max(F32_SNAN), -9.0);
768757

769758
// f64 min/max
770759
assert_eq((1.0 as f64).max(-1.0), 1.0);
@@ -773,6 +762,8 @@ fn ops() {
773762
assert_eq(f64::NAN.max(-9.0), -9.0);
774763
assert_eq((9.0 as f64).min(f64::NAN), 9.0);
775764
assert_eq((-9.0 as f64).max(f64::NAN), -9.0);
765+
assert_eq(F64_SNAN.min(9.0), 9.0);
766+
assert_eq((-9.0_f64).max(F64_SNAN), -9.0);
776767

777768
// f128 min/max
778769
assert_eq((1.0_f128).max(-1.0), 1.0);
@@ -781,6 +772,8 @@ fn ops() {
781772
assert_eq(f128::NAN.max(-9.0), -9.0);
782773
assert_eq((9.0_f128).min(f128::NAN), 9.0);
783774
assert_eq((-9.0_f128).max(f128::NAN), -9.0);
775+
assert_eq(F128_SNAN.min(9.0), 9.0);
776+
assert_eq((-9.0_f128).max(F128_SNAN), -9.0);
784777

785778
// f16 copysign
786779
assert_eq(3.5_f16.copysign(0.42), 3.5_f16);
@@ -1548,15 +1541,15 @@ fn test_non_determinism() {
15481541
test_operations_f128(25., 18.);
15491542

15501543
// SNaN^0 = (1 | NaN)
1551-
check_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan());
1552-
check_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan());
1544+
check_nondet(|| f32::powf(F32_SNAN, 0.0).is_nan());
1545+
check_nondet(|| f64::powf(F64_SNAN, 0.0).is_nan());
15531546

15541547
// 1^SNaN = (1 | NaN)
1555-
check_nondet(|| f32::powf(1.0, SNAN_F32).is_nan());
1556-
check_nondet(|| f64::powf(1.0, SNAN_F64).is_nan());
1548+
check_nondet(|| f32::powf(1.0, F32_SNAN).is_nan());
1549+
check_nondet(|| f64::powf(1.0, F64_SNAN).is_nan());
15571550

15581551
// same as powf (keep it consistent):
15591552
// x^SNaN = (1 | NaN)
1560-
check_nondet(|| f32::powi(SNAN_F32, 0).is_nan());
1561-
check_nondet(|| f64::powi(SNAN_F64, 0).is_nan());
1553+
check_nondet(|| f32::powi(F32_SNAN, 0).is_nan());
1554+
check_nondet(|| f64::powi(F64_SNAN, 0).is_nan());
15621555
}

0 commit comments

Comments
 (0)