about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <tmgross@umich.edu>2025-05-28 00:58:14 +0000
committerTrevor Gross <tmgross@umich.edu>2025-05-29 21:13:26 +0000
commit6a79b272ba5edbb79d57cc96de8c9b363894e3fc (patch)
treeb5e0a05e1514c7471f7057cb4b37e741d42aa3e9
parent45f256d9d7cffb66185c0bf1b8a864cba79db90c (diff)
downloadrust-6a79b272ba5edbb79d57cc96de8c9b363894e3fc.tar.gz
rust-6a79b272ba5edbb79d57cc96de8c9b363894e3fc.zip
float: Use a shared `assert_biteq!` macro for tests
Clean up the separate `assert_f{16,32,64,128}` macros with a single
`assert_biteq!` macro that works for all float widths.
-rw-r--r--library/coretests/tests/floats/f128.rs77
-rw-r--r--library/coretests/tests/floats/f16.rs77
-rw-r--r--library/coretests/tests/floats/f32.rs77
-rw-r--r--library/coretests/tests/floats/f64.rs77
-rw-r--r--library/coretests/tests/floats/mod.rs31
5 files changed, 163 insertions, 176 deletions
diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs
index 12cf651f03f..2ae10d48bf1 100644
--- a/library/coretests/tests/floats/f128.rs
+++ b/library/coretests/tests/floats/f128.rs
@@ -39,17 +39,6 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa;
 /// Second pattern over the mantissa
 const NAN_MASK2: u128 = 0x00005555555555555555555555555555;
 
-/// Compare by representation
-#[allow(unused_macros)]
-macro_rules! assert_f128_biteq {
-    ($a:expr, $b:expr) => {
-        let (l, r): (&f128, &f128) = (&$a, &$b);
-        let lb = l.to_bits();
-        let rb = r.to_bits();
-        assert_eq!(lb, rb, "float {l:?} is not bitequal to {r:?}.\na: {lb:#034x}\nb: {rb:#034x}");
-    };
-}
-
 #[test]
 fn test_num_f128() {
     // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128`
@@ -401,27 +390,27 @@ fn test_next_up() {
     let max_down = f128::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f128_biteq!(f128::NEG_INFINITY.next_up(), f128::MIN);
-    assert_f128_biteq!(f128::MIN.next_up(), -max_down);
-    assert_f128_biteq!((-1.0 - f128::EPSILON).next_up(), -1.0);
-    assert_f128_biteq!((-smallest_normal).next_up(), -largest_subnormal);
-    assert_f128_biteq!((-tiny_up).next_up(), -tiny);
-    assert_f128_biteq!((-tiny).next_up(), -0.0f128);
-    assert_f128_biteq!((-0.0f128).next_up(), tiny);
-    assert_f128_biteq!(0.0f128.next_up(), tiny);
-    assert_f128_biteq!(tiny.next_up(), tiny_up);
-    assert_f128_biteq!(largest_subnormal.next_up(), smallest_normal);
-    assert_f128_biteq!(1.0f128.next_up(), 1.0 + f128::EPSILON);
-    assert_f128_biteq!(f128::MAX.next_up(), f128::INFINITY);
-    assert_f128_biteq!(f128::INFINITY.next_up(), f128::INFINITY);
+    assert_biteq!(f128::NEG_INFINITY.next_up(), f128::MIN);
+    assert_biteq!(f128::MIN.next_up(), -max_down);
+    assert_biteq!((-1.0 - f128::EPSILON).next_up(), -1.0f128);
+    assert_biteq!((-smallest_normal).next_up(), -largest_subnormal);
+    assert_biteq!((-tiny_up).next_up(), -tiny);
+    assert_biteq!((-tiny).next_up(), -0.0f128);
+    assert_biteq!((-0.0f128).next_up(), tiny);
+    assert_biteq!(0.0f128.next_up(), tiny);
+    assert_biteq!(tiny.next_up(), tiny_up);
+    assert_biteq!(largest_subnormal.next_up(), smallest_normal);
+    assert_biteq!(1.0f128.next_up(), 1.0 + f128::EPSILON);
+    assert_biteq!(f128::MAX.next_up(), f128::INFINITY);
+    assert_biteq!(f128::INFINITY.next_up(), f128::INFINITY);
 
     // Check that NaNs roundtrip.
     let nan0 = f128::NAN;
     let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa);
     let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555);
-    assert_f128_biteq!(nan0.next_up(), nan0);
-    assert_f128_biteq!(nan1.next_up(), nan1);
-    assert_f128_biteq!(nan2.next_up(), nan2);
+    assert_biteq!(nan0.next_up(), nan0);
+    assert_biteq!(nan1.next_up(), nan1);
+    assert_biteq!(nan2.next_up(), nan2);
 }
 
 #[test]
@@ -431,28 +420,28 @@ fn test_next_down() {
     let max_down = f128::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f128_biteq!(f128::NEG_INFINITY.next_down(), f128::NEG_INFINITY);
-    assert_f128_biteq!(f128::MIN.next_down(), f128::NEG_INFINITY);
-    assert_f128_biteq!((-max_down).next_down(), f128::MIN);
-    assert_f128_biteq!((-1.0f128).next_down(), -1.0 - f128::EPSILON);
-    assert_f128_biteq!((-largest_subnormal).next_down(), -smallest_normal);
-    assert_f128_biteq!((-tiny).next_down(), -tiny_up);
-    assert_f128_biteq!((-0.0f128).next_down(), -tiny);
-    assert_f128_biteq!((0.0f128).next_down(), -tiny);
-    assert_f128_biteq!(tiny.next_down(), 0.0f128);
-    assert_f128_biteq!(tiny_up.next_down(), tiny);
-    assert_f128_biteq!(smallest_normal.next_down(), largest_subnormal);
-    assert_f128_biteq!((1.0 + f128::EPSILON).next_down(), 1.0f128);
-    assert_f128_biteq!(f128::MAX.next_down(), max_down);
-    assert_f128_biteq!(f128::INFINITY.next_down(), f128::MAX);
+    assert_biteq!(f128::NEG_INFINITY.next_down(), f128::NEG_INFINITY);
+    assert_biteq!(f128::MIN.next_down(), f128::NEG_INFINITY);
+    assert_biteq!((-max_down).next_down(), f128::MIN);
+    assert_biteq!((-1.0f128).next_down(), -1.0 - f128::EPSILON);
+    assert_biteq!((-largest_subnormal).next_down(), -smallest_normal);
+    assert_biteq!((-tiny).next_down(), -tiny_up);
+    assert_biteq!((-0.0f128).next_down(), -tiny);
+    assert_biteq!((0.0f128).next_down(), -tiny);
+    assert_biteq!(tiny.next_down(), 0.0f128);
+    assert_biteq!(tiny_up.next_down(), tiny);
+    assert_biteq!(smallest_normal.next_down(), largest_subnormal);
+    assert_biteq!((1.0 + f128::EPSILON).next_down(), 1.0f128);
+    assert_biteq!(f128::MAX.next_down(), max_down);
+    assert_biteq!(f128::INFINITY.next_down(), f128::MAX);
 
     // Check that NaNs roundtrip.
     let nan0 = f128::NAN;
     let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa);
     let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555);
-    assert_f128_biteq!(nan0.next_down(), nan0);
-    assert_f128_biteq!(nan1.next_down(), nan1);
-    assert_f128_biteq!(nan2.next_down(), nan2);
+    assert_biteq!(nan0.next_down(), nan0);
+    assert_biteq!(nan1.next_down(), nan1);
+    assert_biteq!(nan2.next_down(), nan2);
 }
 
 #[test]
diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs
index db98181226c..4246cec25dd 100644
--- a/library/coretests/tests/floats/f16.rs
+++ b/library/coretests/tests/floats/f16.rs
@@ -41,17 +41,6 @@ const NAN_MASK1: u16 = 0x02aa;
 /// Second pattern over the mantissa
 const NAN_MASK2: u16 = 0x0155;
 
-/// Compare by representation
-#[allow(unused_macros)]
-macro_rules! assert_f16_biteq {
-    ($a:expr, $b:expr) => {
-        let (l, r): (&f16, &f16) = (&$a, &$b);
-        let lb = l.to_bits();
-        let rb = r.to_bits();
-        assert_eq!(lb, rb, "float {l:?} ({lb:#04x}) is not bitequal to {r:?} ({rb:#04x})");
-    };
-}
-
 #[test]
 fn test_num_f16() {
     super::test_num(10f16, 2f16);
@@ -387,27 +376,27 @@ fn test_next_up() {
     let max_down = f16::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f16_biteq!(f16::NEG_INFINITY.next_up(), f16::MIN);
-    assert_f16_biteq!(f16::MIN.next_up(), -max_down);
-    assert_f16_biteq!((-1.0 - f16::EPSILON).next_up(), -1.0);
-    assert_f16_biteq!((-smallest_normal).next_up(), -largest_subnormal);
-    assert_f16_biteq!((-tiny_up).next_up(), -tiny);
-    assert_f16_biteq!((-tiny).next_up(), -0.0f16);
-    assert_f16_biteq!((-0.0f16).next_up(), tiny);
-    assert_f16_biteq!(0.0f16.next_up(), tiny);
-    assert_f16_biteq!(tiny.next_up(), tiny_up);
-    assert_f16_biteq!(largest_subnormal.next_up(), smallest_normal);
-    assert_f16_biteq!(1.0f16.next_up(), 1.0 + f16::EPSILON);
-    assert_f16_biteq!(f16::MAX.next_up(), f16::INFINITY);
-    assert_f16_biteq!(f16::INFINITY.next_up(), f16::INFINITY);
+    assert_biteq!(f16::NEG_INFINITY.next_up(), f16::MIN);
+    assert_biteq!(f16::MIN.next_up(), -max_down);
+    assert_biteq!((-1.0 - f16::EPSILON).next_up(), -1.0f16);
+    assert_biteq!((-smallest_normal).next_up(), -largest_subnormal);
+    assert_biteq!((-tiny_up).next_up(), -tiny);
+    assert_biteq!((-tiny).next_up(), -0.0f16);
+    assert_biteq!((-0.0f16).next_up(), tiny);
+    assert_biteq!(0.0f16.next_up(), tiny);
+    assert_biteq!(tiny.next_up(), tiny_up);
+    assert_biteq!(largest_subnormal.next_up(), smallest_normal);
+    assert_biteq!(1.0f16.next_up(), 1.0 + f16::EPSILON);
+    assert_biteq!(f16::MAX.next_up(), f16::INFINITY);
+    assert_biteq!(f16::INFINITY.next_up(), f16::INFINITY);
 
     // Check that NaNs roundtrip.
     let nan0 = f16::NAN;
     let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1);
     let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2);
-    assert_f16_biteq!(nan0.next_up(), nan0);
-    assert_f16_biteq!(nan1.next_up(), nan1);
-    assert_f16_biteq!(nan2.next_up(), nan2);
+    assert_biteq!(nan0.next_up(), nan0);
+    assert_biteq!(nan1.next_up(), nan1);
+    assert_biteq!(nan2.next_up(), nan2);
 }
 
 #[test]
@@ -417,28 +406,28 @@ fn test_next_down() {
     let max_down = f16::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f16_biteq!(f16::NEG_INFINITY.next_down(), f16::NEG_INFINITY);
-    assert_f16_biteq!(f16::MIN.next_down(), f16::NEG_INFINITY);
-    assert_f16_biteq!((-max_down).next_down(), f16::MIN);
-    assert_f16_biteq!((-1.0f16).next_down(), -1.0 - f16::EPSILON);
-    assert_f16_biteq!((-largest_subnormal).next_down(), -smallest_normal);
-    assert_f16_biteq!((-tiny).next_down(), -tiny_up);
-    assert_f16_biteq!((-0.0f16).next_down(), -tiny);
-    assert_f16_biteq!((0.0f16).next_down(), -tiny);
-    assert_f16_biteq!(tiny.next_down(), 0.0f16);
-    assert_f16_biteq!(tiny_up.next_down(), tiny);
-    assert_f16_biteq!(smallest_normal.next_down(), largest_subnormal);
-    assert_f16_biteq!((1.0 + f16::EPSILON).next_down(), 1.0f16);
-    assert_f16_biteq!(f16::MAX.next_down(), max_down);
-    assert_f16_biteq!(f16::INFINITY.next_down(), f16::MAX);
+    assert_biteq!(f16::NEG_INFINITY.next_down(), f16::NEG_INFINITY);
+    assert_biteq!(f16::MIN.next_down(), f16::NEG_INFINITY);
+    assert_biteq!((-max_down).next_down(), f16::MIN);
+    assert_biteq!((-1.0f16).next_down(), -1.0 - f16::EPSILON);
+    assert_biteq!((-largest_subnormal).next_down(), -smallest_normal);
+    assert_biteq!((-tiny).next_down(), -tiny_up);
+    assert_biteq!((-0.0f16).next_down(), -tiny);
+    assert_biteq!((0.0f16).next_down(), -tiny);
+    assert_biteq!(tiny.next_down(), 0.0f16);
+    assert_biteq!(tiny_up.next_down(), tiny);
+    assert_biteq!(smallest_normal.next_down(), largest_subnormal);
+    assert_biteq!((1.0 + f16::EPSILON).next_down(), 1.0f16);
+    assert_biteq!(f16::MAX.next_down(), max_down);
+    assert_biteq!(f16::INFINITY.next_down(), f16::MAX);
 
     // Check that NaNs roundtrip.
     let nan0 = f16::NAN;
     let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1);
     let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2);
-    assert_f16_biteq!(nan0.next_down(), nan0);
-    assert_f16_biteq!(nan1.next_down(), nan1);
-    assert_f16_biteq!(nan2.next_down(), nan2);
+    assert_biteq!(nan0.next_down(), nan0);
+    assert_biteq!(nan1.next_down(), nan1);
+    assert_biteq!(nan2.next_down(), nan2);
 }
 
 #[test]
diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs
index 36f1937bedf..b989a8f0b33 100644
--- a/library/coretests/tests/floats/f32.rs
+++ b/library/coretests/tests/floats/f32.rs
@@ -23,17 +23,6 @@ const NAN_MASK1: u32 = 0x002a_aaaa;
 /// Second pattern over the mantissa
 const NAN_MASK2: u32 = 0x0055_5555;
 
-#[allow(unused_macros)]
-macro_rules! assert_f32_biteq {
-    ($left : expr, $right : expr) => {
-        let l: &f32 = &$left;
-        let r: &f32 = &$right;
-        let lb = l.to_bits();
-        let rb = r.to_bits();
-        assert_eq!(lb, rb, "float {l} ({lb:#010x}) is not bitequal to {r} ({rb:#010x})");
-    };
-}
-
 #[test]
 fn test_num_f32() {
     super::test_num(10f32, 2f32);
@@ -356,27 +345,27 @@ fn test_next_up() {
     let max_down = f32::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f32_biteq!(f32::NEG_INFINITY.next_up(), f32::MIN);
-    assert_f32_biteq!(f32::MIN.next_up(), -max_down);
-    assert_f32_biteq!((-1.0 - f32::EPSILON).next_up(), -1.0);
-    assert_f32_biteq!((-smallest_normal).next_up(), -largest_subnormal);
-    assert_f32_biteq!((-tiny_up).next_up(), -tiny);
-    assert_f32_biteq!((-tiny).next_up(), -0.0f32);
-    assert_f32_biteq!((-0.0f32).next_up(), tiny);
-    assert_f32_biteq!(0.0f32.next_up(), tiny);
-    assert_f32_biteq!(tiny.next_up(), tiny_up);
-    assert_f32_biteq!(largest_subnormal.next_up(), smallest_normal);
-    assert_f32_biteq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
-    assert_f32_biteq!(f32::MAX.next_up(), f32::INFINITY);
-    assert_f32_biteq!(f32::INFINITY.next_up(), f32::INFINITY);
+    assert_biteq!(f32::NEG_INFINITY.next_up(), f32::MIN);
+    assert_biteq!(f32::MIN.next_up(), -max_down);
+    assert_biteq!((-1.0f32 - f32::EPSILON).next_up(), -1.0f32);
+    assert_biteq!((-smallest_normal).next_up(), -largest_subnormal);
+    assert_biteq!((-tiny_up).next_up(), -tiny);
+    assert_biteq!((-tiny).next_up(), -0.0f32);
+    assert_biteq!((-0.0f32).next_up(), tiny);
+    assert_biteq!(0.0f32.next_up(), tiny);
+    assert_biteq!(tiny.next_up(), tiny_up);
+    assert_biteq!(largest_subnormal.next_up(), smallest_normal);
+    assert_biteq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
+    assert_biteq!(f32::MAX.next_up(), f32::INFINITY);
+    assert_biteq!(f32::INFINITY.next_up(), f32::INFINITY);
 
     // Check that NaNs roundtrip.
     let nan0 = f32::NAN;
     let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1);
     let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2);
-    assert_f32_biteq!(nan0.next_up(), nan0);
-    assert_f32_biteq!(nan1.next_up(), nan1);
-    assert_f32_biteq!(nan2.next_up(), nan2);
+    assert_biteq!(nan0.next_up(), nan0);
+    assert_biteq!(nan1.next_up(), nan1);
+    assert_biteq!(nan2.next_up(), nan2);
 }
 
 #[test]
@@ -386,28 +375,28 @@ fn test_next_down() {
     let max_down = f32::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f32_biteq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY);
-    assert_f32_biteq!(f32::MIN.next_down(), f32::NEG_INFINITY);
-    assert_f32_biteq!((-max_down).next_down(), f32::MIN);
-    assert_f32_biteq!((-1.0f32).next_down(), -1.0 - f32::EPSILON);
-    assert_f32_biteq!((-largest_subnormal).next_down(), -smallest_normal);
-    assert_f32_biteq!((-tiny).next_down(), -tiny_up);
-    assert_f32_biteq!((-0.0f32).next_down(), -tiny);
-    assert_f32_biteq!((0.0f32).next_down(), -tiny);
-    assert_f32_biteq!(tiny.next_down(), 0.0f32);
-    assert_f32_biteq!(tiny_up.next_down(), tiny);
-    assert_f32_biteq!(smallest_normal.next_down(), largest_subnormal);
-    assert_f32_biteq!((1.0 + f32::EPSILON).next_down(), 1.0f32);
-    assert_f32_biteq!(f32::MAX.next_down(), max_down);
-    assert_f32_biteq!(f32::INFINITY.next_down(), f32::MAX);
+    assert_biteq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY);
+    assert_biteq!(f32::MIN.next_down(), f32::NEG_INFINITY);
+    assert_biteq!((-max_down).next_down(), f32::MIN);
+    assert_biteq!((-1.0f32).next_down(), -1.0 - f32::EPSILON);
+    assert_biteq!((-largest_subnormal).next_down(), -smallest_normal);
+    assert_biteq!((-tiny).next_down(), -tiny_up);
+    assert_biteq!((-0.0f32).next_down(), -tiny);
+    assert_biteq!((0.0f32).next_down(), -tiny);
+    assert_biteq!(tiny.next_down(), 0.0f32);
+    assert_biteq!(tiny_up.next_down(), tiny);
+    assert_biteq!(smallest_normal.next_down(), largest_subnormal);
+    assert_biteq!((1.0 + f32::EPSILON).next_down(), 1.0f32);
+    assert_biteq!(f32::MAX.next_down(), max_down);
+    assert_biteq!(f32::INFINITY.next_down(), f32::MAX);
 
     // Check that NaNs roundtrip.
     let nan0 = f32::NAN;
     let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1);
     let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2);
-    assert_f32_biteq!(nan0.next_down(), nan0);
-    assert_f32_biteq!(nan1.next_down(), nan1);
-    assert_f32_biteq!(nan2.next_down(), nan2);
+    assert_biteq!(nan0.next_down(), nan0);
+    assert_biteq!(nan1.next_down(), nan1);
+    assert_biteq!(nan2.next_down(), nan2);
 }
 
 // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs
index 97051998353..2b0f6b4001c 100644
--- a/library/coretests/tests/floats/f64.rs
+++ b/library/coretests/tests/floats/f64.rs
@@ -23,17 +23,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa;
 /// Second pattern over the mantissa
 const NAN_MASK2: u64 = 0x0005_5555_5555_5555;
 
-#[allow(unused_macros)]
-macro_rules! assert_f64_biteq {
-    ($left : expr, $right : expr) => {
-        let l: &f64 = &$left;
-        let r: &f64 = &$right;
-        let lb = l.to_bits();
-        let rb = r.to_bits();
-        assert_eq!(lb, rb, "float {l} ({lb:#018x}) is not bitequal to {r} ({rb:#018x})");
-    };
-}
-
 #[test]
 fn test_num_f64() {
     super::test_num(10f64, 2f64);
@@ -343,26 +332,26 @@ fn test_next_up() {
     let max_down = f64::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f64_biteq!(f64::NEG_INFINITY.next_up(), f64::MIN);
-    assert_f64_biteq!(f64::MIN.next_up(), -max_down);
-    assert_f64_biteq!((-1.0 - f64::EPSILON).next_up(), -1.0);
-    assert_f64_biteq!((-smallest_normal).next_up(), -largest_subnormal);
-    assert_f64_biteq!((-tiny_up).next_up(), -tiny);
-    assert_f64_biteq!((-tiny).next_up(), -0.0f64);
-    assert_f64_biteq!((-0.0f64).next_up(), tiny);
-    assert_f64_biteq!(0.0f64.next_up(), tiny);
-    assert_f64_biteq!(tiny.next_up(), tiny_up);
-    assert_f64_biteq!(largest_subnormal.next_up(), smallest_normal);
-    assert_f64_biteq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
-    assert_f64_biteq!(f64::MAX.next_up(), f64::INFINITY);
-    assert_f64_biteq!(f64::INFINITY.next_up(), f64::INFINITY);
+    assert_biteq!(f64::NEG_INFINITY.next_up(), f64::MIN);
+    assert_biteq!(f64::MIN.next_up(), -max_down);
+    assert_biteq!((-1.0 - f64::EPSILON).next_up(), -1.0f64);
+    assert_biteq!((-smallest_normal).next_up(), -largest_subnormal);
+    assert_biteq!((-tiny_up).next_up(), -tiny);
+    assert_biteq!((-tiny).next_up(), -0.0f64);
+    assert_biteq!((-0.0f64).next_up(), tiny);
+    assert_biteq!(0.0f64.next_up(), tiny);
+    assert_biteq!(tiny.next_up(), tiny_up);
+    assert_biteq!(largest_subnormal.next_up(), smallest_normal);
+    assert_biteq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
+    assert_biteq!(f64::MAX.next_up(), f64::INFINITY);
+    assert_biteq!(f64::INFINITY.next_up(), f64::INFINITY);
 
     let nan0 = f64::NAN;
     let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1);
     let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2);
-    assert_f64_biteq!(nan0.next_up(), nan0);
-    assert_f64_biteq!(nan1.next_up(), nan1);
-    assert_f64_biteq!(nan2.next_up(), nan2);
+    assert_biteq!(nan0.next_up(), nan0);
+    assert_biteq!(nan1.next_up(), nan1);
+    assert_biteq!(nan2.next_up(), nan2);
 }
 
 #[test]
@@ -372,27 +361,27 @@ fn test_next_down() {
     let max_down = f64::from_bits(MAX_DOWN_BITS);
     let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS);
     let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS);
-    assert_f64_biteq!(f64::NEG_INFINITY.next_down(), f64::NEG_INFINITY);
-    assert_f64_biteq!(f64::MIN.next_down(), f64::NEG_INFINITY);
-    assert_f64_biteq!((-max_down).next_down(), f64::MIN);
-    assert_f64_biteq!((-1.0f64).next_down(), -1.0 - f64::EPSILON);
-    assert_f64_biteq!((-largest_subnormal).next_down(), -smallest_normal);
-    assert_f64_biteq!((-tiny).next_down(), -tiny_up);
-    assert_f64_biteq!((-0.0f64).next_down(), -tiny);
-    assert_f64_biteq!((0.0f64).next_down(), -tiny);
-    assert_f64_biteq!(tiny.next_down(), 0.0f64);
-    assert_f64_biteq!(tiny_up.next_down(), tiny);
-    assert_f64_biteq!(smallest_normal.next_down(), largest_subnormal);
-    assert_f64_biteq!((1.0 + f64::EPSILON).next_down(), 1.0f64);
-    assert_f64_biteq!(f64::MAX.next_down(), max_down);
-    assert_f64_biteq!(f64::INFINITY.next_down(), f64::MAX);
+    assert_biteq!(f64::NEG_INFINITY.next_down(), f64::NEG_INFINITY);
+    assert_biteq!(f64::MIN.next_down(), f64::NEG_INFINITY);
+    assert_biteq!((-max_down).next_down(), f64::MIN);
+    assert_biteq!((-1.0f64).next_down(), -1.0 - f64::EPSILON);
+    assert_biteq!((-largest_subnormal).next_down(), -smallest_normal);
+    assert_biteq!((-tiny).next_down(), -tiny_up);
+    assert_biteq!((-0.0f64).next_down(), -tiny);
+    assert_biteq!((0.0f64).next_down(), -tiny);
+    assert_biteq!(tiny.next_down(), 0.0f64);
+    assert_biteq!(tiny_up.next_down(), tiny);
+    assert_biteq!(smallest_normal.next_down(), largest_subnormal);
+    assert_biteq!((1.0 + f64::EPSILON).next_down(), 1.0f64);
+    assert_biteq!(f64::MAX.next_down(), max_down);
+    assert_biteq!(f64::INFINITY.next_down(), f64::MAX);
 
     let nan0 = f64::NAN;
     let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1);
     let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2);
-    assert_f64_biteq!(nan0.next_down(), nan0);
-    assert_f64_biteq!(nan1.next_down(), nan1);
-    assert_f64_biteq!(nan2.next_down(), nan2);
+    assert_biteq!(nan0.next_down(), nan0);
+    assert_biteq!(nan1.next_down(), nan1);
+    assert_biteq!(nan2.next_down(), nan2);
 }
 
 // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs
index 7de34271ad0..c861b5ceff3 100644
--- a/library/coretests/tests/floats/mod.rs
+++ b/library/coretests/tests/floats/mod.rs
@@ -15,6 +15,37 @@ macro_rules! assert_approx_eq {
     }};
 }
 
+/// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0`
+/// behavior, as well as to ensure exact NaN bitpatterns.
+macro_rules! assert_biteq {
+    (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{
+        let l = $left;
+        let r = $right;
+
+        // Hack to coerce left and right to the same type
+        let mut _eq_ty = l;
+        _eq_ty = r;
+
+        // Hack to get the width from a value
+        let bits = (l.to_bits() - l.to_bits()).leading_zeros();
+        assert!(
+            l.to_bits() == r.to_bits(),
+            "{msg}{nl}l: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})",
+            msg = format_args!($($tt)*),
+            nl = $msg_sep,
+            lb = l.to_bits(),
+            rb = r.to_bits(),
+            width = ((bits / 4) + 2) as usize,
+        );
+    }};
+    ($left:expr, $right:expr , $($tt:tt)*) => {
+        assert_biteq!(@inner $left, $right, "\n", $($tt)*)
+    };
+    ($left:expr, $right:expr $(,)?) => {
+        assert_biteq!(@inner $left, $right, "", "")
+    };
+}
+
 /// Helper function for testing numeric operations
 pub fn test_num<T>(ten: T, two: T)
 where