Trevor Gross e754ecb6d9 Add missing functions to the macro list
Now that we are using rustdoc output to locate public functions, the
test is indicating a few that were missed since they don't have their
own function. Update everything to now include the following routines:

* `erfc`
* `erfcf`
* `y0`
* `y0f`
* `y1`
* `y1f`
* `yn`
* `ynf`
2025-01-01 11:15:48 +00:00

172 lines
4.2 KiB
Rust

//! Test with "infinite precision"
#![cfg(feature = "test-multiprecision")]
use libm_test::domain::HasDomain;
use libm_test::gen::{CachedInput, domain_logspace, edge_cases, random};
use libm_test::mpfloat::MpOp;
use libm_test::{
CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall,
};
/// Test against MPFR with random inputs.
macro_rules! mp_rand_tests {
(
fn_name: $fn_name:ident,
attrs: [$($meta:meta)*]
) => {
paste::paste! {
#[test]
$(#[$meta])*
fn [< mp_random_ $fn_name >]() {
test_one_random::<libm_test::op::$fn_name::Routine>();
}
}
};
}
/// Test a single routine with random inputs
fn test_one_random<Op>()
where
Op: MathOp + MpOp,
CachedInput: GenerateInput<Op::RustArgs>,
{
let mut mp_vals = Op::new_mp();
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr);
let cases = random::get_test_cases::<Op::RustArgs>(&ctx);
for input in cases {
let mp_res = Op::run(&mut mp_vals, input);
let crate_res = input.call(Op::ROUTINE);
crate_res.validate(mp_res, input, &ctx).unwrap();
}
}
libm_macros::for_each_function! {
callback: mp_rand_tests,
attributes: [
// Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())`
#[ignore = "large values are infeasible in MPFR"]
[jn, jnf, yn, ynf],
],
skip: [
// FIXME: MPFR tests needed
frexp,
frexpf,
ilogb,
ilogbf,
ldexp,
ldexpf,
modf,
modff,
remquo,
remquof,
scalbn,
scalbnf,
// FIXME: test needed, see
// https://github.com/rust-lang/libm/pull/311#discussion_r1818273392
nextafter,
nextafterf,
],
}
/// Test against MPFR with generators from a domain.
macro_rules! mp_domain_tests {
(
fn_name: $fn_name:ident,
attrs: [$($meta:meta)*]
) => {
paste::paste! {
#[test]
$(#[$meta])*
fn [< mp_edge_case_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op, _>(edge_cases::get_test_cases::<Op, _>);
}
#[test]
$(#[$meta])*
fn [< mp_logspace_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op, _>(domain_logspace::get_test_cases::<Op>);
}
}
};
}
/// Test a single routine against domaine-aware inputs.
fn domain_test_runner<Op, I>(gen: impl FnOnce(&CheckCtx) -> I)
where
// Complicated generics...
// The operation must take a single float argument (unary only)
Op: MathOp<RustArgs = (<Op as MathOp>::FTy,)>,
// It must also support multiprecision operations
Op: MpOp,
// And it must have a domain specified
Op: HasDomain<Op::FTy>,
// The single float argument tuple must be able to call the `RustFn` and return `RustRet`
(OpFTy<Op>,): TupleCall<OpRustFn<Op>, Output = OpRustRet<Op>>,
I: Iterator<Item = (Op::FTy,)>,
{
let mut mp_vals = Op::new_mp();
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr);
let cases = gen(&ctx);
for input in cases {
let mp_res = Op::run(&mut mp_vals, input);
let crate_res = input.call(Op::ROUTINE);
crate_res.validate(mp_res, input, &ctx).unwrap();
}
}
libm_macros::for_each_function! {
callback: mp_domain_tests,
attributes: [],
skip: [
// Functions with multiple inputs
atan2,
atan2f,
copysign,
copysignf,
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,
// FIXME: MPFR tests needed
frexp,
frexpf,
ilogb,
ilogbf,
modf,
modff,
],
}