@@ -102,6 +102,15 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
102
102
}
103
103
}
104
104
105
+ if cfg ! ( target_arch = "x86" ) {
106
+ match ctx. fn_ident {
107
+ // Input `fma(0.999999999999999, 1.0000000000000013, 0.0) = 1.0000000000000002` is
108
+ // incorrect on i586 and i686.
109
+ Id :: Fma => ulp = 1 ,
110
+ _ => ( ) ,
111
+ }
112
+ }
113
+
105
114
// In some cases, our implementation is less accurate than musl on i586.
106
115
if cfg ! ( x86_no_sse) {
107
116
match ctx. fn_ident {
@@ -370,59 +379,129 @@ fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Opt
370
379
impl MaybeOverride < ( f16 , f16 ) > for SpecialCase {
371
380
fn check_float < F : Float > (
372
381
input : ( f16 , f16 ) ,
373
- _actual : F ,
382
+ actual : F ,
374
383
expected : F ,
375
384
_ulp : & mut u32 ,
376
385
ctx : & CheckCtx ,
377
386
) -> Option < TestResult > {
378
- maybe_skip_binop_nan ( input, expected, ctx)
387
+ binop_common ( input, actual , expected, ctx)
379
388
}
380
389
}
381
390
382
391
impl MaybeOverride < ( f32 , f32 ) > for SpecialCase {
383
392
fn check_float < F : Float > (
384
393
input : ( f32 , f32 ) ,
385
- _actual : F ,
394
+ actual : F ,
386
395
expected : F ,
387
396
_ulp : & mut u32 ,
388
397
ctx : & CheckCtx ,
389
398
) -> Option < TestResult > {
390
- maybe_skip_binop_nan ( input, expected, ctx)
399
+ if ctx. base_name == BaseName :: Fmin
400
+ && input. 0 . biteq ( f32:: NEG_ZERO )
401
+ && input. 1 . biteq ( f32:: ZERO )
402
+ && expected. biteq ( F :: NEG_ZERO )
403
+ && actual. biteq ( F :: ZERO )
404
+ {
405
+ return XFAIL ;
406
+ }
407
+
408
+ binop_common ( input, actual, expected, ctx)
409
+ }
410
+
411
+ fn check_int < I : Int > (
412
+ _input : ( f32 , f32 ) ,
413
+ actual : I ,
414
+ expected : I ,
415
+ ctx : & CheckCtx ,
416
+ ) -> Option < TestResult > {
417
+ remquo_common ( actual, expected, ctx)
391
418
}
392
419
}
393
420
394
421
impl MaybeOverride < ( f64 , f64 ) > for SpecialCase {
395
422
fn check_float < F : Float > (
396
423
input : ( f64 , f64 ) ,
397
- _actual : F ,
424
+ actual : F ,
398
425
expected : F ,
399
426
_ulp : & mut u32 ,
400
427
ctx : & CheckCtx ,
401
428
) -> Option < TestResult > {
402
- maybe_skip_binop_nan ( input, expected, ctx)
429
+ if ctx. base_name == BaseName :: Fmin
430
+ && input. 0 . biteq ( f64:: NEG_ZERO )
431
+ && input. 1 . biteq ( f64:: ZERO )
432
+ && expected. biteq ( F :: ZERO )
433
+ && actual. biteq ( F :: NEG_ZERO )
434
+ {
435
+ return XFAIL ;
436
+ }
437
+
438
+ binop_common ( input, actual, expected, ctx)
439
+ }
440
+
441
+ fn check_int < I : Int > (
442
+ _input : ( f64 , f64 ) ,
443
+ actual : I ,
444
+ expected : I ,
445
+ ctx : & CheckCtx ,
446
+ ) -> Option < TestResult > {
447
+ remquo_common ( actual, expected, ctx)
448
+ }
449
+ }
450
+
451
+ fn remquo_common < I : Int > ( actual : I , expected : I , ctx : & CheckCtx ) -> Option < TestResult > {
452
+ // FIXME: Our MPFR implementation disagrees with musl and may need to be updated.
453
+ if ctx. basis == CheckBasis :: Mpfr
454
+ && ctx. base_name == BaseName :: Remquo
455
+ && expected == I :: MIN
456
+ && actual == I :: ZERO
457
+ {
458
+ return XFAIL ;
403
459
}
460
+
461
+ None
404
462
}
405
463
406
464
#[ cfg( f128_enabled) ]
407
465
impl MaybeOverride < ( f128 , f128 ) > for SpecialCase {
408
466
fn check_float < F : Float > (
409
467
input : ( f128 , f128 ) ,
410
- _actual : F ,
468
+ actual : F ,
411
469
expected : F ,
412
470
_ulp : & mut u32 ,
413
471
ctx : & CheckCtx ,
414
472
) -> Option < TestResult > {
415
- maybe_skip_binop_nan ( input, expected, ctx)
473
+ binop_common ( input, actual , expected, ctx)
416
474
}
417
475
}
418
476
419
- /// Musl propagates NaNs if one is provided as the input, but we return the other input.
420
477
// F1 and F2 are always the same type, this is just to please generics
421
- fn maybe_skip_binop_nan < F1 : Float , F2 : Float > (
478
+ fn binop_common < F1 : Float , F2 : Float > (
422
479
input : ( F1 , F1 ) ,
480
+ actual : F2 ,
423
481
expected : F2 ,
424
482
ctx : & CheckCtx ,
425
483
) -> Option < TestResult > {
484
+ /* FIXME(#439): we do not compare signed zeros */
485
+
486
+ if ctx. base_name == BaseName :: Fmin
487
+ && input. 0 . biteq ( F1 :: NEG_ZERO )
488
+ && input. 1 . biteq ( F1 :: ZERO )
489
+ && expected. biteq ( F2 :: NEG_ZERO )
490
+ && actual. biteq ( F2 :: ZERO )
491
+ {
492
+ return XFAIL ;
493
+ }
494
+
495
+ if ctx. base_name == BaseName :: Fmax
496
+ && input. 0 . biteq ( F1 :: NEG_ZERO )
497
+ && input. 1 . biteq ( F1 :: ZERO )
498
+ && expected. biteq ( F2 :: ZERO )
499
+ && actual. biteq ( F2 :: NEG_ZERO )
500
+ {
501
+ return XFAIL ;
502
+ }
503
+
504
+ // Musl propagates NaNs if one is provided as the input, but we return the other input.
426
505
match ( & ctx. basis , ctx. base_name ) {
427
506
( Musl , BaseName :: Fmin | BaseName :: Fmax )
428
507
if ( input. 0 . is_nan ( ) || input. 1 . is_nan ( ) ) && expected. is_nan ( ) =>
@@ -502,7 +581,53 @@ fn bessel_prec_dropoff<F: Float>(
502
581
None
503
582
}
504
583
505
- impl MaybeOverride < ( f32 , f32 , f32 ) > for SpecialCase { }
506
- impl MaybeOverride < ( f64 , f64 , f64 ) > for SpecialCase { }
507
584
impl MaybeOverride < ( f32 , i32 ) > for SpecialCase { }
508
585
impl MaybeOverride < ( f64 , i32 ) > for SpecialCase { }
586
+
587
+ impl MaybeOverride < ( f32 , f32 , f32 ) > for SpecialCase {
588
+ fn check_float < F : Float > (
589
+ input : ( f32 , f32 , f32 ) ,
590
+ actual : F ,
591
+ expected : F ,
592
+ _ulp : & mut u32 ,
593
+ ctx : & CheckCtx ,
594
+ ) -> Option < TestResult > {
595
+ ternop_common ( input, actual, expected, ctx)
596
+ }
597
+ }
598
+ impl MaybeOverride < ( f64 , f64 , f64 ) > for SpecialCase {
599
+ fn check_float < F : Float > (
600
+ input : ( f64 , f64 , f64 ) ,
601
+ actual : F ,
602
+ expected : F ,
603
+ _ulp : & mut u32 ,
604
+ ctx : & CheckCtx ,
605
+ ) -> Option < TestResult > {
606
+ ternop_common ( input, actual, expected, ctx)
607
+ }
608
+ }
609
+
610
+ // F1 and F2 are always the same type, this is just to please generics
611
+ fn ternop_common < F1 : Float , F2 : Float > (
612
+ input : ( F1 , F1 , F1 ) ,
613
+ actual : F2 ,
614
+ expected : F2 ,
615
+ ctx : & CheckCtx ,
616
+ ) -> Option < TestResult > {
617
+ // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result
618
+ // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the
619
+ // exact result". Our implementation returns the wrong sign:
620
+ // fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0)
621
+ if ctx. base_name == BaseName :: Fma
622
+ && ( input. 0 . is_sign_negative ( ) ^ input. 1 . is_sign_negative ( ) )
623
+ && input. 0 != F1 :: ZERO
624
+ && input. 1 != F1 :: ZERO
625
+ && input. 2 . biteq ( F1 :: ZERO )
626
+ && expected. biteq ( F2 :: NEG_ZERO )
627
+ && actual. biteq ( F2 :: ZERO )
628
+ {
629
+ return XFAIL ;
630
+ }
631
+
632
+ None
633
+ }
0 commit comments