Merge pull request rust-lang/libm#406 from tgross35/musl-domain-tests

Add domain and edge case tests to musl
This commit is contained in:
Trevor Gross 2025-01-06 07:00:29 -05:00 committed by GitHub
commit 2fff7dd979
4 changed files with 123 additions and 2 deletions

View file

@ -23,7 +23,9 @@ use std::time::SystemTime;
pub use f8_impl::f8;
pub use libm::support::{Float, Int, IntTy, MinInt};
pub use num::{FloatExt, logspace};
pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty};
pub use op::{
BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty,
};
pub use precision::{MaybeOverride, SpecialCase, default_ulp};
use run_cfg::EXTENSIVE_MAX_ITERATIONS;
pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test};

View file

@ -96,6 +96,8 @@ pub type OpFTy<Op> = <Op as MathOp>::FTy;
pub type OpITy<Op> = <<Op as MathOp>::FTy as Float>::Int;
/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types).
pub type OpCFn<Op> = <Op as MathOp>::CFn;
/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types).
pub type OpCRet<Op> = <Op as MathOp>::CRet;
/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types).
pub type OpRustFn<Op> = <Op as MathOp>::RustFn;
/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types).

View file

@ -106,7 +106,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
match ctx.fn_ident {
Id::Asinh => ulp = 3,
Id::Asinhf => ulp = 3,
Id::Exp10 | Id::Exp10f => ulp = 1_000_000,
Id::Exp2 | Id::Exp2f => ulp = 10_000_000,
Id::Fmaf => ulp = 1,
Id::Log1p | Id::Log1pf => ulp = 2,
Id::Rint => ulp = 100_000,
Id::Round => ulp = 1,
Id::Tan => ulp = 2,
_ => (),
@ -270,6 +274,24 @@ impl MaybeOverride<(f64,)> for SpecialCase {
return XFAIL;
}
if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor)
&& cfg!(x86_no_sse)
&& expected.eq_repr(F::NEG_ZERO)
&& actual.eq_repr(F::ZERO)
{
// FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0.
// See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955
return XFAIL;
}
if (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2)
&& cfg!(x86_no_sse)
{
// FIXME: i586 has very imprecise results with ULP > u32::MAX for these
// operations so we can't reasonably provide a limit.
return XFAIL;
}
maybe_check_nan_bits(actual, expected, ctx)
}

View file

@ -9,8 +9,9 @@
// There are some targets we can't build musl for
#![cfg(feature = "build-musl")]
use libm_test::gen::random;
use libm_test::domain::HasDomain;
use libm_test::gen::random::RandomInput;
use libm_test::gen::{domain_logspace, edge_cases, random};
use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall};
macro_rules! musl_rand_tests {
@ -53,3 +54,97 @@ libm_macros::for_each_function! {
[exp10, exp10f, exp2, exp2f, rint]
],
}
/// Test against musl with generators from a domain.
macro_rules! musl_domain_tests {
(
fn_name: $fn_name:ident,
attrs: [$($attr:meta),*],
) => {
paste::paste! {
#[test]
$(#[$attr])*
fn [< musl_edge_case_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op, _>(
edge_cases::get_test_cases::<Op, _>,
musl_math_sys::$fn_name,
);
}
#[test]
$(#[$attr])*
fn [< musl_logspace_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op, _>(
domain_logspace::get_test_cases::<Op>,
musl_math_sys::$fn_name,
);
}
}
};
}
/// Test a single routine against domaine-aware inputs.
fn domain_test_runner<Op, I>(gen: impl FnOnce(&CheckCtx) -> I, musl_fn: Op::CFn)
where
Op: MathOp,
Op: HasDomain<Op::FTy>,
I: Iterator<Item = Op::RustArgs>,
{
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl);
let cases = gen(&ctx);
for input in cases {
let musl_res = input.call(musl_fn);
let crate_res = input.call(Op::ROUTINE);
crate_res.validate(musl_res, input, &ctx).unwrap();
}
}
libm_macros::for_each_function! {
callback: musl_domain_tests,
attributes: [],
skip: [
// Functions with multiple inputs
atan2,
atan2f,
copysign,
copysignf,
copysignf16,
copysignf128,
fdim,
fdimf,
fma,
fmaf,
fmax,
fmaxf,
fmin,
fminf,
fmod,
fmodf,
hypot,
hypotf,
jn,
jnf,
ldexp,
ldexpf,
nextafter,
nextafterf,
pow,
powf,
remainder,
remainderf,
remquo,
remquof,
scalbn,
scalbnf,
yn,
ynf,
// Not provided by musl
fabsf16,
fabsf128,
],
}