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:
Juho Kahala 2026-02-09 12:32:04 +02:00 committed by GitHub
parent 3d0989266d
commit 8cd47adab2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 45 additions and 20 deletions

View file

@ -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

View file

@ -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 {

View file

@ -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