libm: Fix tests for lgamma
The tests were using `rug::ln_gamma` as a reference for `libm::lgamma`, which actually computes the natural logarithm *of the absolute value* of the Gamma function. This changes the range of inputs used for the icount-benchmarks of these functions, which causes false regressions in [1]. [1]: https://github.com/rust-lang/compiler-builtins/actions/runs/21788698368/job/62864230903?pr=1075#step:7:2710. Fixes: a1a066611dc2 ("Create interfaces for testing against MPFR")
This commit is contained in:
parent
3d0989266d
commit
8cd47adab2
3 changed files with 45 additions and 20 deletions
|
|
@ -207,7 +207,7 @@ impl<F: Float, I: Int> EitherPrim<Domain<F>, Domain<I>> {
|
|||
.into_prim_float()];
|
||||
|
||||
/// Domain for `loggamma`
|
||||
const LGAMMA: [Self; 1] = Self::STRICTLY_POSITIVE;
|
||||
const LGAMMA: [Self; 1] = Self::UNBOUNDED1;
|
||||
|
||||
/// Domain for `jn` and `yn`.
|
||||
// FIXME: the domain should provide some sort of "reasonable range" so we don't actually test
|
||||
|
|
|
|||
|
|
@ -170,7 +170,9 @@ libm_macros::for_each_function! {
|
|||
ldexpf,
|
||||
ldexpf128,
|
||||
ldexpf16,
|
||||
lgamma,
|
||||
lgamma_r,
|
||||
lgammaf,
|
||||
lgammaf_r,
|
||||
modf,
|
||||
modff,
|
||||
|
|
@ -213,7 +215,6 @@ libm_macros::for_each_function! {
|
|||
fmaximum_num | fmaximum_numf | fmaximum_numf16 | fmaximum_numf128 => max,
|
||||
fmin | fminf | fminf16 | fminf128 |
|
||||
fminimum_num | fminimum_numf | fminimum_numf16 | fminimum_numf128 => min,
|
||||
lgamma | lgammaf => ln_gamma,
|
||||
log | logf => ln,
|
||||
log1p | log1pf => ln_1p,
|
||||
tgamma | tgammaf => gamma,
|
||||
|
|
@ -576,6 +577,30 @@ impl MpOp for crate::op::lgammaf_r::Routine {
|
|||
}
|
||||
}
|
||||
|
||||
impl MpOp for crate::op::lgamma::Routine {
|
||||
type MpTy = MpFloat;
|
||||
|
||||
fn new_mp() -> Self::MpTy {
|
||||
new_mpfloat::<Self::FTy>()
|
||||
}
|
||||
|
||||
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
|
||||
<crate::op::lgamma_r::Routine as MpOp>::run(this, input).0
|
||||
}
|
||||
}
|
||||
|
||||
impl MpOp for crate::op::lgammaf::Routine {
|
||||
type MpTy = MpFloat;
|
||||
|
||||
fn new_mp() -> Self::MpTy {
|
||||
new_mpfloat::<Self::FTy>()
|
||||
}
|
||||
|
||||
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
|
||||
<crate::op::lgammaf_r::Routine as MpOp>::run(this, input).0
|
||||
}
|
||||
}
|
||||
|
||||
/* stub implementations so we don't need to special case them */
|
||||
|
||||
impl MpOp for crate::op::nextafter::Routine {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
|
|||
Bn::Exp2 => 1,
|
||||
Bn::Expm1 => 1,
|
||||
Bn::Hypot => 1,
|
||||
Bn::Lgamma | Bn::LgammaR => 16,
|
||||
Bn::Lgamma | Bn::LgammaR => 4,
|
||||
Bn::Log => 1,
|
||||
Bn::Log10 => 1,
|
||||
Bn::Log1p => 1,
|
||||
|
|
@ -102,7 +102,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
|
|||
match ctx.base_name {
|
||||
Bn::Cosh => ulp = 2,
|
||||
Bn::Exp10 if usize::BITS < 64 => ulp = 4,
|
||||
Bn::Lgamma | Bn::LgammaR => ulp = 400,
|
||||
Bn::Tanh => ulp = 4,
|
||||
_ => (),
|
||||
}
|
||||
|
|
@ -218,17 +217,17 @@ impl MaybeOverride<(f16,)> for SpecialCase {}
|
|||
|
||||
impl MaybeOverride<(f32,)> for SpecialCase {
|
||||
fn check_float<F: Float>(input: (f32,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction {
|
||||
if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR)
|
||||
&& input.0 > 4e36
|
||||
&& expected.is_infinite()
|
||||
&& !actual.is_infinite()
|
||||
{
|
||||
// This result should saturate but we return a finite value.
|
||||
if ctx.base_name == BaseName::J0 && input.0 < -1e34 {
|
||||
// Errors get huge close to -inf
|
||||
return XFAIL_NOCHECK;
|
||||
}
|
||||
|
||||
if ctx.base_name == BaseName::J0 && input.0 < -1e34 {
|
||||
// Errors get huge close to -inf
|
||||
// FIXME(correctness): lgammaf has high relative inaccuracy near its zeroes
|
||||
if matches!(ctx.base_name, BaseName::Lgamma | BaseName::LgammaR)
|
||||
&& input.0 > -13.0625
|
||||
&& input.0 < -2.0
|
||||
&& (expected.abs() < F::ONE || (input.0 - input.0.round()).abs() < 0.02)
|
||||
{
|
||||
return XFAIL_NOCHECK;
|
||||
}
|
||||
|
||||
|
|
@ -275,6 +274,15 @@ impl MaybeOverride<(f64,)> for SpecialCase {
|
|||
return XFAIL_NOCHECK;
|
||||
}
|
||||
|
||||
// FIXME(correctness): lgamma has high relative inaccuracy near its zeroes
|
||||
if matches!(ctx.base_name, BaseName::Lgamma | BaseName::LgammaR)
|
||||
&& input.0 > -32.0
|
||||
&& input.0 < -2.0
|
||||
&& (expected.abs() < F::ONE || (input.0 - input.0.round()).abs() < 0.02)
|
||||
{
|
||||
return XFAIL_NOCHECK;
|
||||
}
|
||||
|
||||
// maybe_check_nan_bits(actual, expected, ctx)
|
||||
unop_common(input, actual, expected, ctx)
|
||||
}
|
||||
|
|
@ -304,14 +312,6 @@ fn unop_common<F1: Float, F2: Float>(
|
|||
expected: F2,
|
||||
ctx: &CheckCtx,
|
||||
) -> CheckAction {
|
||||
if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR)
|
||||
&& input.0 < F1::ZERO
|
||||
&& !input.0.is_infinite()
|
||||
{
|
||||
// loggamma should not be defined for x < 0, yet we both return results
|
||||
return XFAIL_NOCHECK;
|
||||
}
|
||||
|
||||
// fabs and copysign must leave NaNs untouched.
|
||||
if ctx.base_name == BaseName::Fabs && input.0.is_nan() {
|
||||
// LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue