Add test infrastructure for f16 and f128

Update test traits to support `f16` and `f128`, as applicable. Add the
new routines (`fabs` and `copysign` for `f16` and `f128`) to the list of
all operations.
This commit is contained in:
Trevor Gross
2025-01-03 00:12:53 +00:00
parent 42c7ace5ba
commit 6b5e8b20f0
13 changed files with 205 additions and 43 deletions

View File

@@ -187,3 +187,15 @@ impl HasDomain<f32> for crate::op::lgammaf_r::Routine {
impl HasDomain<f64> for crate::op::lgamma_r::Routine {
const DOMAIN: Domain<f64> = Domain::<f64>::LGAMMA;
}
/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */
#[cfg(f16_enabled)]
impl HasDomain<f16> for crate::op::fabsf16::Routine {
const DOMAIN: Domain<f16> = Domain::<f16>::UNBOUNDED;
}
#[cfg(f128_enabled)]
impl HasDomain<f128> for crate::op::fabsf128::Routine {
const DOMAIN: Domain<f128> = Domain::<f128>::UNBOUNDED;
}

View File

@@ -138,8 +138,12 @@ macro_rules! impl_extensive_input {
};
}
#[cfg(f16_enabled)]
impl_extensive_input!(f16);
impl_extensive_input!(f32);
impl_extensive_input!(f64);
#[cfg(f128_enabled)]
impl_extensive_input!(f128);
/// Create a test case iterator for extensive inputs.
pub fn get_test_cases<Op>(

View File

@@ -107,8 +107,12 @@ macro_rules! impl_random_input {
};
}
#[cfg(f16_enabled)]
impl_random_input!(f16);
impl_random_input!(f32);
impl_random_input!(f64);
#[cfg(f128_enabled)]
impl_random_input!(f128);
/// Create a test case iterator.
pub fn get_test_cases<RustArgs: RandomInput>(

View File

@@ -137,6 +137,7 @@ libm_macros::for_each_function! {
fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf,
lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf,
remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf,
copysignf16, copysignf128, fabsf16, fabsf128,
],
fn_extra: match MACRO_FN_NAME {
// Remap function names that are different between mpfr and libm
@@ -157,10 +158,8 @@ libm_macros::for_each_function! {
/// Implement unary functions that don't have a `_round` version
macro_rules! impl_no_round {
// Unary matcher
($($fn_name:ident, $rug_name:ident;)*) => {
($($fn_name:ident => $rug_name:ident;)*) => {
paste::paste! {
// Implement for both f32 and f64
$( impl_no_round!{ @inner_unary [< $fn_name f >], $rug_name } )*
$( impl_no_round!{ @inner_unary $fn_name, $rug_name } )*
}
};
@@ -183,33 +182,34 @@ macro_rules! impl_no_round {
}
impl_no_round! {
fabs, abs_mut;
ceil, ceil_mut;
floor, floor_mut;
rint, round_even_mut; // FIXME: respect rounding mode
round, round_mut;
trunc, trunc_mut;
ceil => ceil_mut;
ceilf => ceil_mut;
fabs => abs_mut;
fabsf => abs_mut;
floor => floor_mut;
floorf => floor_mut;
rint => round_even_mut; // FIXME: respect rounding mode
rintf => round_even_mut; // FIXME: respect rounding mode
round => round_mut;
roundf => round_mut;
trunc => trunc_mut;
truncf => trunc_mut;
}
#[cfg(f16_enabled)]
impl_no_round! {
fabsf16 => abs_mut;
}
#[cfg(f128_enabled)]
impl_no_round! {
fabsf128 => abs_mut;
}
/// Some functions are difficult to do in a generic way. Implement them here.
macro_rules! impl_op_for_ty {
($fty:ty, $suffix:literal) => {
paste::paste! {
impl MpOp for crate::op::[<copysign $suffix>]::Routine {
type MpTy = (MpFloat, MpFloat);
fn new_mp() -> Self::MpTy {
(new_mpfloat::<Self::FTy>(), new_mpfloat::<Self::FTy>())
}
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
this.0.assign(input.0);
this.1.assign(input.1);
this.0.copysign_mut(&this.1);
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
}
}
impl MpOp for crate::op::[<modf $suffix>]::Routine {
type MpTy = (MpFloat, MpFloat);
@@ -379,9 +379,38 @@ macro_rules! impl_op_for_ty {
};
}
/// Version of `impl_op_for_ty` with only functions that have `f16` and `f128` implementations.
macro_rules! impl_op_for_ty_all {
($fty:ty, $suffix:literal) => {
paste::paste! {
impl MpOp for crate::op::[<copysign $suffix>]::Routine {
type MpTy = (MpFloat, MpFloat);
fn new_mp() -> Self::MpTy {
(new_mpfloat::<Self::FTy>(), new_mpfloat::<Self::FTy>())
}
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
this.0.assign(input.0);
this.1.assign(input.1);
this.0.copysign_mut(&this.1);
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
}
}
}
};
}
impl_op_for_ty!(f32, "f");
impl_op_for_ty!(f64, "");
#[cfg(f16_enabled)]
impl_op_for_ty_all!(f16, "f16");
impl_op_for_ty_all!(f32, "f");
impl_op_for_ty_all!(f64, "");
#[cfg(f128_enabled)]
impl_op_for_ty_all!(f128, "f128");
// `lgamma_r` is not a simple suffix so we can't use the above macro.
impl MpOp for crate::op::lgamma_r::Routine {
type MpTy = MpFloat;

View File

@@ -157,6 +157,9 @@ pub trait MaybeOverride<Input> {
}
}
#[cfg(f16_enabled)]
impl MaybeOverride<(f16,)> for SpecialCase {}
impl MaybeOverride<(f32,)> for SpecialCase {
fn check_float<F: Float>(
input: (f32,),
@@ -290,6 +293,9 @@ impl MaybeOverride<(f64,)> for SpecialCase {
}
}
#[cfg(f128_enabled)]
impl MaybeOverride<(f128,)> for SpecialCase {}
/// Check NaN bits if the function requires it
fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Option<TestResult> {
if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) {
@@ -317,6 +323,19 @@ fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Opt
}
}
#[cfg(f16_enabled)]
impl MaybeOverride<(f16, f16)> for SpecialCase {
fn check_float<F: Float>(
input: (f16, f16),
_actual: F,
expected: F,
_ulp: &mut u32,
ctx: &CheckCtx,
) -> Option<TestResult> {
maybe_skip_binop_nan(input, expected, ctx)
}
}
impl MaybeOverride<(f32, f32)> for SpecialCase {
fn check_float<F: Float>(
input: (f32, f32),
@@ -341,6 +360,19 @@ impl MaybeOverride<(f64, f64)> for SpecialCase {
}
}
#[cfg(f128_enabled)]
impl MaybeOverride<(f128, f128)> for SpecialCase {
fn check_float<F: Float>(
input: (f128, f128),
_actual: F,
expected: F,
_ulp: &mut u32,
ctx: &CheckCtx,
) -> Option<TestResult> {
maybe_skip_binop_nan(input, expected, ctx)
}
}
/// Musl propagates NaNs if one is provided as the input, but we return the other input.
// F1 and F2 are always the same type, this is just to please generics
fn maybe_skip_binop_nan<F1: Float, F2: Float>(

View File

@@ -303,6 +303,12 @@ where
impl_float!(f32, f64);
#[cfg(f16_enabled)]
impl_float!(f16);
#[cfg(f128_enabled)]
impl_float!(f128);
/* trait implementations for compound types */
/// Implement `CheckOutput` for combinations of types.