Skip to content

Commit faa3f43

Browse files
authored
Merge pull request rust-lang#497 from tgross35/edge-case-max-subnorm
fmaf128: fix exponent calculation for subnormals
2 parents 724e47d + 4e86806 commit faa3f43

File tree

5 files changed

+49
-14
lines changed

5 files changed

+49
-14
lines changed

.github/workflows/main.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ jobs:
273273
exit
274274
fi
275275
276+
# Run the non-extensive tests first to catch any easy failures
277+
cargo t --profile release-checked -- "$CHANGED"
278+
276279
LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \
277280
--features build-mpfr,unstable,force-soft-floats \
278281
--profile release-checked \

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
}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs.
22
3-
use libm::support::{CastInto, Float, Int};
3+
use libm::support::{CastInto, Float, Int, MinInt};
44

55
use crate::domain::get_domain;
66
use crate::gen::KnownSize;
7+
use crate::op::OpITy;
78
use crate::run_cfg::{check_near_count, check_point_count};
89
use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log};
910

@@ -21,6 +22,7 @@ where
2122
Op: MathOp,
2223
{
2324
let mut ret = Vec::new();
25+
let one = OpITy::<Op>::ONE;
2426
let values = &mut ret;
2527
let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float();
2628
let domain_start = domain.range_start();
@@ -51,6 +53,22 @@ where
5153
values.push(Op::FTy::NAN);
5254
values.extend(Op::FTy::consts().iter());
5355

56+
// Check around the maximum subnormal value
57+
let sub_max = Op::FTy::from_bits(Op::FTy::SIG_MASK);
58+
count_up(sub_max, near_points, values);
59+
count_down(sub_max, near_points, values);
60+
count_up(-sub_max, near_points, values);
61+
count_down(-sub_max, near_points, values);
62+
63+
// Check a few values around the subnormal range
64+
for shift in (0..Op::FTy::SIG_BITS).step_by(Op::FTy::SIG_BITS as usize / 5) {
65+
let v = Op::FTy::from_bits(one << shift);
66+
count_up(v, 2, values);
67+
count_down(v, 2, values);
68+
count_up(-v, 2, values);
69+
count_down(-v, 2, values);
70+
}
71+
5472
// Check around asymptotes
5573
if let Some(f) = domain.check_points {
5674
let iter = f();

crates/libm-test/src/run_cfg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ pub fn check_near_count(ctx: &CheckCtx) -> u64 {
342342
x => panic!("unexpected argument count {x}"),
343343
}
344344
} else {
345-
10
345+
8
346346
}
347347
}
348348

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)