Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 7788a3d

Browse files
committed
Adjust precision and add xfails based on new tests
1 parent 577310c commit 7788a3d

File tree

2 files changed

+134
-13
lines changed

2 files changed

+134
-13
lines changed

crates/libm-test/src/precision.rs

Lines changed: 128 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -370,59 +370,129 @@ 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)
400+
}
401+
402+
fn check_int<I: Int>(
403+
_input: (f32, f32),
404+
actual: I,
405+
expected: I,
406+
ctx: &CheckCtx,
407+
) -> Option<TestResult> {
408+
remquo_common(actual, expected, ctx)
391409
}
392410
}
393411

394412
impl MaybeOverride<(f64, f64)> for SpecialCase {
395413
fn check_float<F: Float>(
396414
input: (f64, f64),
397-
_actual: F,
415+
actual: F,
398416
expected: F,
399417
_ulp: &mut u32,
400418
ctx: &CheckCtx,
401419
) -> Option<TestResult> {
402-
maybe_skip_binop_nan(input, expected, ctx)
420+
if ctx.base_name == BaseName::Fmin
421+
&& input.0.biteq(f64::NEG_ZERO)
422+
&& input.1.biteq(f64::ZERO)
423+
&& expected.biteq(F::ZERO)
424+
&& actual.biteq(F::NEG_ZERO)
425+
{
426+
return XFAIL;
427+
}
428+
429+
binop_common(input, actual, expected, ctx)
430+
}
431+
432+
fn check_int<I: Int>(
433+
_input: (f64, f64),
434+
actual: I,
435+
expected: I,
436+
ctx: &CheckCtx,
437+
) -> Option<TestResult> {
438+
remquo_common(actual, expected, ctx)
439+
}
440+
}
441+
442+
fn remquo_common<I: Int>(actual: I, expected: I, ctx: &CheckCtx) -> Option<TestResult> {
443+
// FIXME: Our MPFR implementation disagrees with musl and may need to be updated.
444+
if ctx.basis == CheckBasis::Mpfr
445+
&& ctx.base_name == BaseName::Remquo
446+
&& expected == I::MIN
447+
&& actual == I::ZERO
448+
{
449+
return XFAIL;
403450
}
451+
452+
None
404453
}
405454

406455
#[cfg(f128_enabled)]
407456
impl MaybeOverride<(f128, f128)> for SpecialCase {
408457
fn check_float<F: Float>(
409458
input: (f128, f128),
410-
_actual: F,
459+
actual: F,
411460
expected: F,
412461
_ulp: &mut u32,
413462
ctx: &CheckCtx,
414463
) -> Option<TestResult> {
415-
maybe_skip_binop_nan(input, expected, ctx)
464+
binop_common(input, actual, expected, ctx)
416465
}
417466
}
418467

419-
/// Musl propagates NaNs if one is provided as the input, but we return the other input.
420468
// F1 and F2 are always the same type, this is just to please generics
421-
fn maybe_skip_binop_nan<F1: Float, F2: Float>(
469+
fn binop_common<F1: Float, F2: Float>(
422470
input: (F1, F1),
471+
actual: F2,
423472
expected: F2,
424473
ctx: &CheckCtx,
425474
) -> Option<TestResult> {
475+
/* FIXME(#439): we do not compare signed zeros */
476+
477+
if ctx.base_name == BaseName::Fmin
478+
&& input.0.biteq(F1::NEG_ZERO)
479+
&& input.1.biteq(F1::ZERO)
480+
&& expected.biteq(F2::NEG_ZERO)
481+
&& actual.biteq(F2::ZERO)
482+
{
483+
return XFAIL;
484+
}
485+
486+
if ctx.base_name == BaseName::Fmax
487+
&& input.0.biteq(F1::NEG_ZERO)
488+
&& input.1.biteq(F1::ZERO)
489+
&& expected.biteq(F2::ZERO)
490+
&& actual.biteq(F2::NEG_ZERO)
491+
{
492+
return XFAIL;
493+
}
494+
495+
// Musl propagates NaNs if one is provided as the input, but we return the other input.
426496
match (&ctx.basis, ctx.base_name) {
427497
(Musl, BaseName::Fmin | BaseName::Fmax)
428498
if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() =>
@@ -502,7 +572,53 @@ fn bessel_prec_dropoff<F: Float>(
502572
None
503573
}
504574

505-
impl MaybeOverride<(f32, f32, f32)> for SpecialCase {}
506-
impl MaybeOverride<(f64, f64, f64)> for SpecialCase {}
507575
impl MaybeOverride<(f32, i32)> for SpecialCase {}
508576
impl MaybeOverride<(f64, i32)> for SpecialCase {}
577+
578+
impl MaybeOverride<(f32, f32, f32)> for SpecialCase {
579+
fn check_float<F: Float>(
580+
input: (f32, f32, f32),
581+
actual: F,
582+
expected: F,
583+
_ulp: &mut u32,
584+
ctx: &CheckCtx,
585+
) -> Option<TestResult> {
586+
ternop_common(input, actual, expected, ctx)
587+
}
588+
}
589+
impl MaybeOverride<(f64, f64, f64)> for SpecialCase {
590+
fn check_float<F: Float>(
591+
input: (f64, f64, f64),
592+
actual: F,
593+
expected: F,
594+
_ulp: &mut u32,
595+
ctx: &CheckCtx,
596+
) -> Option<TestResult> {
597+
ternop_common(input, actual, expected, ctx)
598+
}
599+
}
600+
601+
// F1 and F2 are always the same type, this is just to please generics
602+
fn ternop_common<F1: Float, F2: Float>(
603+
input: (F1, F1, F1),
604+
actual: F2,
605+
expected: F2,
606+
ctx: &CheckCtx,
607+
) -> Option<TestResult> {
608+
// FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result
609+
// of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the
610+
// exact result". Our implementation returns the wrong sign:
611+
// fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0)
612+
if ctx.base_name == BaseName::Fma
613+
&& (input.0.is_sign_negative() ^ input.1.is_sign_negative())
614+
&& input.0 != F1::ZERO
615+
&& input.1 != F1::ZERO
616+
&& input.2.biteq(F1::ZERO)
617+
&& expected.biteq(F2::NEG_ZERO)
618+
&& actual.biteq(F2::ZERO)
619+
{
620+
return XFAIL;
621+
}
622+
623+
None
624+
}

src/math/support/float_traits.rs

Lines changed: 6 additions & 1 deletion
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)