|  | //! Compare our implementations with the result of musl functions, as provided by `musl-math-sys`. | 
|  | //! | 
|  | //! Currently this only tests randomized inputs. In the future this may be improved to test edge | 
|  | //! cases or run exhaustive tests. | 
|  | //! | 
|  | //! Note that musl functions do not always provide 0.5ULP rounding, so our functions can do better | 
|  | //! than these results. | 
|  |  | 
|  | // There are some targets we can't build musl for | 
|  | #![cfg(feature = "build-musl")] | 
|  |  | 
|  | use libm_test::generate::{case_list, edge_cases, random, spaced}; | 
|  | use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; | 
|  |  | 
|  | const BASIS: CheckBasis = CheckBasis::Musl; | 
|  |  | 
|  | fn musl_runner<Op: MathOp>( | 
|  | ctx: &CheckCtx, | 
|  | cases: impl Iterator<Item = Op::RustArgs>, | 
|  | musl_fn: Op::CFn, | 
|  | ) { | 
|  | for input in cases { | 
|  | let musl_res = input.call(musl_fn); | 
|  | let crate_res = input.call_intercept_panics(Op::ROUTINE); | 
|  |  | 
|  | crate_res.validate(musl_res, input, ctx).unwrap(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Test against musl with generators from a domain. | 
|  | macro_rules! musl_tests { | 
|  | ( | 
|  | fn_name: $fn_name:ident, | 
|  | attrs: [$($attr:meta),*], | 
|  | ) => { | 
|  | paste::paste! { | 
|  | #[test] | 
|  | $(#[$attr])* | 
|  | fn [< musl_case_list_ $fn_name >]() { | 
|  | type Op = libm_test::op::$fn_name::Routine; | 
|  | let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); | 
|  | let cases = case_list::get_test_cases_basis::<Op>(&ctx).0; | 
|  | musl_runner::<Op>(&ctx, cases, musl_math_sys::$fn_name); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | $(#[$attr])* | 
|  | fn [< musl_random_ $fn_name >]() { | 
|  | type Op = libm_test::op::$fn_name::Routine; | 
|  | let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); | 
|  | let cases = random::get_test_cases::<<Op as MathOp>::RustArgs>(&ctx).0; | 
|  | musl_runner::<Op>(&ctx, cases, musl_math_sys::$fn_name); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | $(#[$attr])* | 
|  | fn [< musl_edge_case_ $fn_name >]() { | 
|  | type Op = libm_test::op::$fn_name::Routine; | 
|  | let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); | 
|  | let cases = edge_cases::get_test_cases::<Op>(&ctx).0; | 
|  | musl_runner::<Op>(&ctx, cases, musl_math_sys::$fn_name); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | $(#[$attr])* | 
|  | fn [< musl_quickspace_ $fn_name >]() { | 
|  | type Op = libm_test::op::$fn_name::Routine; | 
|  | let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Spaced); | 
|  | let cases = spaced::get_test_cases::<Op>(&ctx).0; | 
|  | musl_runner::<Op>(&ctx, cases, musl_math_sys::$fn_name); | 
|  | } | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | libm_macros::for_each_function! { | 
|  | callback: musl_tests, | 
|  | attributes: [], | 
|  | // Not provided by musl | 
|  | skip_f16_f128: true, | 
|  | skip: [ | 
|  | // TODO integer inputs | 
|  | jn, | 
|  | jnf, | 
|  | ldexp, | 
|  | ldexpf, | 
|  | scalbn, | 
|  | scalbnf, | 
|  | yn, | 
|  | ynf, | 
|  |  | 
|  | // Not provided by musl | 
|  | // verify-sorted-start | 
|  | fmaximum, | 
|  | fmaximum_num, | 
|  | fmaximum_numf, | 
|  | fmaximumf, | 
|  | fminimum, | 
|  | fminimum_num, | 
|  | fminimum_numf, | 
|  | fminimumf, | 
|  | roundeven, | 
|  | roundevenf, | 
|  | // // verify-sorted-end | 
|  | ], | 
|  | } |