Skip to content

Commit daad206

Browse files
committed
Adjust precision and add xfails based on new tests
1 parent 1251e2a commit daad206

File tree

2 files changed

+103
-13
lines changed

2 files changed

+103
-13
lines changed

crates/libm-test/src/precision.rs

+97-12
Original file line numberDiff line numberDiff line change
@@ -370,59 +370,98 @@ fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Opt
370370
impl MaybeOverride<(f16, f16)> for SpecialCase {
371371
fn check_float<F: Float>(
372372
input: (f16, f16),
373-
_actual: F,
373+
actual: F,
374374
expected: F,
375375
_ulp: &mut u32,
376376
ctx: &CheckCtx,
377377
) -> Option<TestResult> {
378-
maybe_skip_binop_nan(input, expected, ctx)
378+
binop_common(input, actual, expected, ctx)
379379
}
380380
}
381381

382382
impl MaybeOverride<(f32, f32)> for SpecialCase {
383383
fn check_float<F: Float>(
384384
input: (f32, f32),
385-
_actual: F,
385+
actual: F,
386386
expected: F,
387387
_ulp: &mut u32,
388388
ctx: &CheckCtx,
389389
) -> Option<TestResult> {
390-
maybe_skip_binop_nan(input, expected, ctx)
390+
if ctx.base_name == BaseName::Fmin
391+
&& input.0.biteq(f32::NEG_ZERO)
392+
&& input.1.biteq(f32::ZERO)
393+
&& expected.biteq(F::NEG_ZERO)
394+
&& actual.biteq(F::ZERO)
395+
{
396+
return XFAIL;
397+
}
398+
399+
binop_common(input, actual, expected, ctx)
391400
}
392401
}
393402

394403
impl MaybeOverride<(f64, f64)> for SpecialCase {
395404
fn check_float<F: Float>(
396405
input: (f64, f64),
397-
_actual: F,
406+
actual: F,
398407
expected: F,
399408
_ulp: &mut u32,
400409
ctx: &CheckCtx,
401410
) -> Option<TestResult> {
402-
maybe_skip_binop_nan(input, expected, ctx)
411+
if ctx.base_name == BaseName::Fmin
412+
&& input.0.biteq(f64::NEG_ZERO)
413+
&& input.1.biteq(f64::ZERO)
414+
&& expected.biteq(F::ZERO)
415+
&& actual.biteq(F::NEG_ZERO)
416+
{
417+
return XFAIL;
418+
}
419+
420+
binop_common(input, actual, expected, ctx)
403421
}
404422
}
405423

406424
#[cfg(f128_enabled)]
407425
impl MaybeOverride<(f128, f128)> for SpecialCase {
408426
fn check_float<F: Float>(
409427
input: (f128, f128),
410-
_actual: F,
428+
actual: F,
411429
expected: F,
412430
_ulp: &mut u32,
413431
ctx: &CheckCtx,
414432
) -> Option<TestResult> {
415-
maybe_skip_binop_nan(input, expected, ctx)
433+
binop_common(input, actual, expected, ctx)
416434
}
417435
}
418436

419-
/// Musl propagates NaNs if one is provided as the input, but we return the other input.
420437
// F1 and F2 are always the same type, this is just to please generics
421-
fn maybe_skip_binop_nan<F1: Float, F2: Float>(
438+
fn binop_common<F1: Float, F2: Float>(
422439
input: (F1, F1),
440+
actual: F2,
423441
expected: F2,
424442
ctx: &CheckCtx,
425443
) -> Option<TestResult> {
444+
/* FIXME(#439): we do not compare signed zeros */
445+
446+
if ctx.base_name == BaseName::Fmin
447+
&& input.0.biteq(F1::NEG_ZERO)
448+
&& input.1.biteq(F1::ZERO)
449+
&& expected.biteq(F2::NEG_ZERO)
450+
&& actual.biteq(F2::ZERO)
451+
{
452+
return XFAIL;
453+
}
454+
455+
if ctx.base_name == BaseName::Fmax
456+
&& input.0.biteq(F1::NEG_ZERO)
457+
&& input.1.biteq(F1::ZERO)
458+
&& expected.biteq(F2::ZERO)
459+
&& actual.biteq(F2::NEG_ZERO)
460+
{
461+
return XFAIL;
462+
}
463+
464+
// Musl propagates NaNs if one is provided as the input, but we return the other input.
426465
match (&ctx.basis, ctx.base_name) {
427466
(Musl, BaseName::Fmin | BaseName::Fmax)
428467
if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() =>
@@ -502,7 +541,53 @@ fn bessel_prec_dropoff<F: Float>(
502541
None
503542
}
504543

505-
impl MaybeOverride<(f32, f32, f32)> for SpecialCase {}
506-
impl MaybeOverride<(f64, f64, f64)> for SpecialCase {}
507544
impl MaybeOverride<(f32, i32)> for SpecialCase {}
508545
impl MaybeOverride<(f64, i32)> for SpecialCase {}
546+
547+
impl MaybeOverride<(f32, f32, f32)> for SpecialCase {
548+
fn check_float<F: Float>(
549+
input: (f32, f32, f32),
550+
actual: F,
551+
expected: F,
552+
_ulp: &mut u32,
553+
ctx: &CheckCtx,
554+
) -> Option<TestResult> {
555+
ternop_common(input, actual, expected, ctx)
556+
}
557+
}
558+
impl MaybeOverride<(f64, f64, f64)> for SpecialCase {
559+
fn check_float<F: Float>(
560+
input: (f64, f64, f64),
561+
actual: F,
562+
expected: F,
563+
_ulp: &mut u32,
564+
ctx: &CheckCtx,
565+
) -> Option<TestResult> {
566+
ternop_common(input, actual, expected, ctx)
567+
}
568+
}
569+
570+
// F1 and F2 are always the same type, this is just to please generics
571+
fn ternop_common<F1: Float, F2: Float>(
572+
input: (F1, F1, F1),
573+
actual: F2,
574+
expected: F2,
575+
ctx: &CheckCtx,
576+
) -> Option<TestResult> {
577+
// FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result
578+
// of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the
579+
// exact result". Our implementation returns the wrong sign:
580+
// fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0)
581+
if ctx.base_name == BaseName::Fma
582+
&& (input.0.is_sign_negative() ^ input.1.is_sign_negative())
583+
&& input.0 != F1::ZERO
584+
&& input.1 != F1::ZERO
585+
&& input.2.biteq(F1::ZERO)
586+
&& expected.biteq(F2::NEG_ZERO)
587+
&& actual.biteq(F2::ZERO)
588+
{
589+
return XFAIL;
590+
}
591+
592+
None
593+
}

src/math/support/float_traits.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,14 @@ pub trait Float:
9393
/// Returns true if the value is +inf or -inf.
9494
fn is_infinite(self) -> bool;
9595

96-
/// Returns true if the sign is negative.
96+
/// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN.
9797
fn is_sign_negative(self) -> bool;
9898

99+
/// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN.
100+
fn is_sign_positive(self) -> bool {
101+
!self.is_sign_negative()
102+
}
103+
99104
/// Returns if `self` is subnormal
100105
fn is_subnormal(self) -> bool {
101106
(self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO

0 commit comments

Comments
 (0)