support: Print sNaN or qNaN for hex floats

Give more descriptive output in tests since we sometimes need to treat
these differently. We still don't parse `sNaN`/`qNaN` for now, though we
could in the future.
This commit is contained in:
Trevor Gross
2026-03-05 19:05:55 -05:00
parent ccd1042884
commit 3a352497c3
@@ -340,8 +340,10 @@ pub(super) fn fmt_any_hex<F: Float>(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::R
write!(f, "-")?;
}
if x.is_nan() {
return write!(f, "NaN");
if x.is_snan() {
return write!(f, "sNaN");
} else if x.is_nan() {
return write!(f, "qNaN");
} else if x.is_infinite() {
return write!(f, "inf");
} else if *x == F::ZERO {
@@ -511,6 +513,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(test)]
mod parse_tests {
extern crate std;
use std::string::String;
use std::{format, println};
use super::*;
@@ -559,6 +562,16 @@ fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> {
}
Ok(())
}
#[cfg_attr(not(f16_enabled), expect(unused))]
pub fn canonicalize_snan_str(s: String) -> String {
if s.contains("sNaN") || s.contains("qNaN") {
s.replace("sNaN", "NaN").replace("qNaN", "NaN")
} else {
s
}
}
#[test]
#[cfg(f16_enabled)]
fn test_rounding() {
@@ -566,7 +579,11 @@ fn test_rounding() {
for i in -n..n {
let u = i.rotate_right(11) as u32;
let s = format!("{}", Hexf(f32::from_bits(u)));
assert!(rounding_properties(&s).is_ok());
let s = canonicalize_snan_str(s);
match rounding_properties(&s) {
Ok(()) => (),
Err(e) => panic!("failed rounding properties for `{s}`: {e:?}"),
}
}
}
@@ -1099,8 +1116,11 @@ fn test_f16() {
use std::format;
// Exhaustively check that `f16` roundtrips.
for x in 0..=u16::MAX {
use super::parse_tests::canonicalize_snan_str;
let f = f16::from_bits(x);
let s = format!("{}", Hexf(f));
let s = canonicalize_snan_str(s);
let from_s = hf16(&s);
if f.is_nan() && from_s.is_nan() {
@@ -1119,6 +1139,8 @@ fn test_f16() {
#[cfg(f16_enabled)]
fn test_f16_to_f32() {
use std::format;
use super::parse_tests::canonicalize_snan_str;
// Exhaustively check that these are equivalent for all `f16`:
// - `f16 -> f32`
// - `f16 -> str -> f32`
@@ -1127,8 +1149,10 @@ fn test_f16_to_f32() {
for x in 0..=u16::MAX {
let f16 = f16::from_bits(x);
let s16 = format!("{}", Hexf(f16));
let s16 = canonicalize_snan_str(s16);
let f32 = f16 as f32;
let s32 = format!("{}", Hexf(f32));
let s32 = canonicalize_snan_str(s32);
let a = hf32(&s16);
let b = hf32(&s32);
@@ -1169,8 +1193,17 @@ fn spot_checks() {
assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0");
assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0");
assert_eq!(Hexf(f32::NAN).to_string(), "NaN");
assert_eq!(Hexf(f64::NAN).to_string(), "NaN");
assert_eq!(Hexf(f32::NAN).to_string(), "qNaN");
assert_eq!(Hexf(f64::NAN).to_string(), "qNaN");
assert_eq!(Hexf(f32::NEG_NAN).to_string(), "-qNaN");
assert_eq!(Hexf(f64::NEG_NAN).to_string(), "-qNaN");
if !cfg!(x86_no_sse) {
// FIXME(rust-lang/rust#115567): calls quiet the sNaN
assert_eq!(Hexf(f32::SNAN).to_string(), "sNaN");
assert_eq!(Hexf(f64::SNAN).to_string(), "sNaN");
assert_eq!(Hexf(f32::NEG_SNAN).to_string(), "-sNaN");
assert_eq!(Hexf(f64::NEG_SNAN).to_string(), "-sNaN");
}
assert_eq!(Hexf(f32::INFINITY).to_string(), "inf");
assert_eq!(Hexf(f64::INFINITY).to_string(), "inf");
@@ -1184,7 +1217,9 @@ fn spot_checks() {
assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15");
assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0");
assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0");
assert_eq!(Hexf(f16::NAN).to_string(), "NaN");
assert_eq!(Hexf(f16::NAN).to_string(), "qNaN");
assert_eq!(Hexf(f16::SNAN).to_string(), "sNaN");
assert_eq!(Hexf(f16::NEG_NAN).to_string(), "-qNaN");
assert_eq!(Hexf(f16::INFINITY).to_string(), "inf");
assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf");
}
@@ -1201,7 +1236,9 @@ fn spot_checks() {
);
assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0");
assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0");
assert_eq!(Hexf(f128::NAN).to_string(), "NaN");
assert_eq!(Hexf(f128::NAN).to_string(), "qNaN");
assert_eq!(Hexf(f128::SNAN).to_string(), "sNaN");
assert_eq!(Hexf(f128::NEG_NAN).to_string(), "-qNaN");
assert_eq!(Hexf(f128::INFINITY).to_string(), "inf");
assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf");
}