Print the hex float format upon failure

Now that we have a hex float formatter, make use of it for test output.
This produces values that are easier to read than the bitwise hex
representation.

Example:

    thread 'mp_quickspace_fmaf128' panicked at crates/libm-test/tests/multiprecision.rs:17:48:
    called `Result::unwrap()` on an `Err` value:
        input:    (0xe38d71c71c71c71c71c71c71c71c71c8, 0xe38d71c71c71c71c71c71c71c71c71c8, 0xffff0000000000000000000000000000)
        as hex:   (-0x1.71c71c71c71c71c71c71c71c71c8p+9102, -0x1.71c71c71c71c71c71c71c71c71c8p+9102, -inf)
        as bits:  (0xe38d71c71c71c71c71c71c71c71c71c8, 0xe38d71c71c71c71c71c71c71c71c71c8, 0xffff0000000000000000000000000000)
        expected: 0xffff0000000000000000000000000000 -inf 0xffff0000000000000000000000000000
        actual:   0x7fff8000000000000000000000000000 NaN 0x7fff8000000000000000000000000000

    Caused by:
        real value != NaN
This commit is contained in:
Trevor Gross 2025-02-06 00:02:00 +00:00 committed by Trevor Gross
parent e01ce5d53a
commit 3fbe59f850

View file

@ -9,6 +9,7 @@
use std::fmt;
use anyhow::{Context, anyhow, bail, ensure};
use libm::support::Hexf;
use crate::precision::CheckAction;
use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult};
@ -35,7 +36,10 @@ pub trait CheckOutput<Input>: Sized {
///
/// This is only used for printing errors so allocating is okay.
pub trait Hex: Copy {
/// Hex integer syntax.
fn hex(self) -> String;
/// Hex float syntax.
fn hexf(self) -> String;
}
/* implement `TupleCall` */
@ -128,6 +132,10 @@ where
fn hex(self) -> String {
format!("({},)", self.0.hex())
}
fn hexf(self) -> String {
format!("({},)", self.0.hexf())
}
}
impl<T1, T2> Hex for (T1, T2)
@ -138,6 +146,10 @@ where
fn hex(self) -> String {
format!("({}, {})", self.0.hex(), self.1.hex())
}
fn hexf(self) -> String {
format!("({}, {})", self.0.hexf(), self.1.hexf())
}
}
impl<T1, T2, T3> Hex for (T1, T2, T3)
@ -149,6 +161,10 @@ where
fn hex(self) -> String {
format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex())
}
fn hexf(self) -> String {
format!("({}, {}, {})", self.0.hexf(), self.1.hexf(), self.2.hexf())
}
}
/* trait implementations for ints */
@ -160,6 +176,10 @@ macro_rules! impl_int {
fn hex(self) -> String {
format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize)
}
fn hexf(self) -> String {
String::new()
}
}
impl<Input> $crate::CheckOutput<Input> for $ty
@ -234,6 +254,10 @@ macro_rules! impl_float {
width = ((Self::BITS / 4) + 2) as usize
)
}
fn hexf(self) -> String {
format!("{}", Hexf(self))
}
}
impl<Input> $crate::CheckOutput<Input> for $ty
@ -324,13 +348,18 @@ where
res.with_context(|| {
format!(
"\
\n input: {input:?} {ibits}\
\n expected: {expected:<22?} {expbits}\
\n actual: {actual:<22?} {actbits}\
\n input: {input:?}\
\n as hex: {ihex}\
\n as bits: {ibits}\
\n expected: {expected:<22?} {exphex} {expbits}\
\n actual: {actual:<22?} {acthex} {actbits}\
",
actbits = actual.hex(),
expbits = expected.hex(),
ihex = input.hexf(),
ibits = input.hex(),
exphex = expected.hexf(),
expbits = expected.hex(),
actbits = actual.hex(),
acthex = actual.hexf(),
)
})
}
@ -365,12 +394,15 @@ macro_rules! impl_tuples {
.with_context(|| format!(
"full context:\
\n input: {input:?} {ibits}\
\n as hex: {ihex}\
\n as bits: {ibits}\
\n expected: {expected:?} {expbits}\
\n actual: {self:?} {actbits}\
",
actbits = self.hex(),
expbits = expected.hex(),
ihex = input.hexf(),
ibits = input.hex(),
expbits = expected.hex(),
actbits = self.hex(),
))
}
}