diff options
| author | Trevor Gross <tmgross@umich.edu> | 2025-02-06 00:34:56 +0000 |
|---|---|---|
| committer | Trevor Gross <tmgross@umich.edu> | 2025-02-06 02:03:19 +0000 |
| commit | 23989245ce549411b9d80323b89c9eb48fff53ec (patch) | |
| tree | 38b2a95a7ef6e44ca51f848d1f68829a0669f345 | |
| parent | 3fbe59f8503fb5eb151bc995ba2c1ebad80dcbb5 (diff) | |
| download | rust-23989245ce549411b9d80323b89c9eb48fff53ec.tar.gz rust-23989245ce549411b9d80323b89c9eb48fff53ec.zip | |
fma: Ensure zero has the correct sign
Currently, `fma(tiny, -tiny, 0.0)` returns 0.0 while the answer should
be -0.0. This is because `-0.0 + 0.0 = +0.0` in the default rounding
mode; however, the result should be negative. Musl has the same pattern
but that version worked because the C compiler was contracting `x*y + z`
to (ironically) `fmadd`.
Musl was fixed in 9683bd6241 ("math: fix fma(x,y,0) when x*y rounds to
-0"). Add the same fix here, which allows dropping the xfails.
| -rw-r--r-- | library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 47 | ||||
| -rw-r--r-- | library/compiler-builtins/libm/src/math/generic/fma.rs | 2 |
2 files changed, 3 insertions, 46 deletions
diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 051960b7a55..596f91fe1ef 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -558,48 +558,5 @@ impl MaybeOverride<(f64, i32)> for SpecialCase {} #[cfg(f128_enabled)] impl MaybeOverride<(f128, i32)> for SpecialCase {} -impl MaybeOverride<(f32, f32, f32)> for SpecialCase { - fn check_float<F: Float>( - input: (f32, f32, f32), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - ternop_common(input, actual, expected, ctx) - } -} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase { - fn check_float<F: Float>( - input: (f64, f64, f64), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - ternop_common(input, actual, expected, ctx) - } -} - -// F1 and F2 are always the same type, this is just to please generics -fn ternop_common<F1: Float, F2: Float>( - input: (F1, F1, F1), - actual: F2, - expected: F2, - ctx: &CheckCtx, -) -> CheckAction { - // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result - // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result". Our implementation returns the wrong sign: - // fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0) - if ctx.base_name == BaseName::Fma - && (input.0.is_sign_negative() ^ input.1.is_sign_negative()) - && input.0 != F1::ZERO - && input.1 != F1::ZERO - && input.2.biteq(F1::ZERO) - && expected.biteq(F2::NEG_ZERO) - && actual.biteq(F2::ZERO) - { - return XFAIL("fma sign"); - } - - DEFAULT -} +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 3d5459f1a04..b0e2117ea09 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -31,7 +31,7 @@ where if nz.e >= ZEROINFNAN { if nz.e > ZEROINFNAN { /* z==0 */ - return x * y + z; + return x * y; } return z; } |
