//! 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: [$($attr:meta),*], ) => { paste::paste! { #[test] $(#[$attr])* fn [< mp_random_ $fn_name >]() { test_one_random::(); } } }; } /// Test a single routine with random inputs fn test_one_random() where Op: MathOp + MpOp, CachedInput: GenerateInput, { let mut mp_vals = Op::new_mp(); let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); let cases = random::get_test_cases::(&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: [$($attr:meta),*], ) => { paste::paste! { #[test] $(#[$attr])* fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; domain_test_runner::(edge_cases::get_test_cases::); } #[test] $(#[$attr])* fn [< mp_logspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; domain_test_runner::(domain_logspace::get_test_cases::); } } }; } /// Test a single routine against domaine-aware inputs. fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I) where // Complicated generics... // The operation must take a single float argument (unary only) Op: MathOp::FTy,)>, // It must also support multiprecision operations Op: MpOp, // And it must have a domain specified Op: HasDomain, // The single float argument tuple must be able to call the `RustFn` and return `RustRet` (OpFTy,): TupleCall, Output = OpRustRet>, I: Iterator, { 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, ], }