Skip to content

Commit 4e86806

Browse files
committed
fmaf128: fix exponent calculation for subnormals
When `fmaf128` was introduced in [1], it included a bug where `self` gets returned rather than the expected minimum positive value. Resolve this and add a regression test. [1]: rust-lang/libm#494
1 parent 0fbdb7b commit 4e86806

File tree

2 files changed

+26
-12
lines changed

2 files changed

+26
-12
lines changed

crates/libm-test/src/gen/case_list.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,26 @@ fn fmaf128_cases() -> Vec<TestCase<op::fmaf128::Routine>> {
269269
let mut v = vec![];
270270
TestCase::append_pairs(
271271
&mut v,
272-
&[(
273-
// Tricky rounding case that previously failed in extensive tests
272+
&[
273+
(
274+
// Tricky rounding case that previously failed in extensive tests
275+
(
276+
hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"),
277+
hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"),
278+
hf128!("-0x0.000000000000000000000000048ap-16382"),
279+
),
280+
Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")),
281+
),
274282
(
275-
hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"),
276-
hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"),
277-
hf128!("-0x0.000000000000000000000000048ap-16382"),
283+
// Subnormal edge case that caused a failure
284+
(
285+
hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"),
286+
hf128!("0x1.ffffffffffffffffffffffffffffp-1"),
287+
hf128!("0x0.8000000000000000000000000009p-16382"),
288+
),
289+
Some(hf128!("0x1.0000000000000000000000000000p-16382")),
278290
),
279-
Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")),
280-
)],
291+
],
281292
);
282293
v
283294
}

src/math/generic/fma.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ where
146146
// exact +/- 0.0
147147
return x * y + z;
148148
}
149+
149150
e -= d;
150151

151152
// Use int->float conversion to populate the significand.
@@ -174,7 +175,7 @@ where
174175

175176
if r == c {
176177
// Min normal after rounding,
177-
return r.raise_underflow_ret_self();
178+
return r.raise_underflow_as_min_positive();
178179
}
179180

180181
if (rhi << (F::SIG_BITS + 1)) != zero {
@@ -275,12 +276,14 @@ impl<F: Float> Norm<F> {
275276

276277
/// Type-specific helpers that are not needed outside of fma.
277278
pub trait FmaHelper {
278-
fn raise_underflow_ret_self(self) -> Self;
279+
/// Raise underflow and return the minimum positive normal value with the sign of `self`.
280+
fn raise_underflow_as_min_positive(self) -> Self;
281+
/// Raise underflow and return zero.
279282
fn raise_underflow_ret_zero(self) -> Self;
280283
}
281284

282285
impl FmaHelper for f64 {
283-
fn raise_underflow_ret_self(self) -> Self {
286+
fn raise_underflow_as_min_positive(self) -> Self {
284287
/* min normal after rounding, underflow depends
285288
* on arch behaviour which can be imitated by
286289
* a double to float conversion */
@@ -298,8 +301,8 @@ impl FmaHelper for f64 {
298301

299302
#[cfg(f128_enabled)]
300303
impl FmaHelper for f128 {
301-
fn raise_underflow_ret_self(self) -> Self {
302-
self
304+
fn raise_underflow_as_min_positive(self) -> Self {
305+
f128::MIN_POSITIVE.copysign(self)
303306
}
304307

305308
fn raise_underflow_ret_zero(self) -> Self {

0 commit comments

Comments
 (0)