Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Add fmodf128 #470

Merged
merged 2 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/libm-macros/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
FloatTy::F128,
Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] },
None,
&["copysignf128", "fdimf128", "fmaxf128", "fminf128"],
&["copysignf128", "fdimf128", "fmaxf128", "fminf128", "fmodf128"],
),
(
// `(f32, f32, f32) -> f32`
Expand Down
1 change: 1 addition & 0 deletions crates/libm-test/benches/icount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ main!(
icount_bench_fmin_group,
icount_bench_fminf_group,
icount_bench_fmod_group,
icount_bench_fmodf128_group,
icount_bench_fmodf16_group,
icount_bench_fmodf_group,
icount_bench_frexp_group,
Expand Down
1 change: 1 addition & 0 deletions crates/libm-test/benches/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ libm_macros::for_each_function! {
| fmaxf16
| fminf128
| fminf16
| fmodf128
| fmodf16
| rintf128
| rintf16
Expand Down
4 changes: 2 additions & 2 deletions crates/libm-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub use op::{
Ty,
};
pub use precision::{MaybeOverride, SpecialCase, default_ulp};
use run_cfg::EXTENSIVE_MAX_ITERATIONS;
use run_cfg::extensive_max_iterations;
pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test};
pub use test_traits::{CheckOutput, Hex, TupleCall};

Expand Down Expand Up @@ -89,7 +89,7 @@ pub fn test_log(s: &str) {
writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap();
writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap();
writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap();
writeln!(f, "extensive iterations {}", *EXTENSIVE_MAX_ITERATIONS).unwrap();
writeln!(f, "extensive iterations {}", extensive_max_iterations()).unwrap();

Some(f)
});
Expand Down
47 changes: 16 additions & 31 deletions crates/libm-test/src/mpfloat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ libm_macros::for_each_function! {
floorf16,
fmod,
fmodf,
fmodf128,
fmodf16,
frexp,
frexpf,
Expand Down Expand Up @@ -301,21 +302,6 @@ macro_rules! impl_op_for_ty {
}
}

impl MpOp for crate::op::[<fmod $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);
let ord = this.0.rem_assign_round(&this.1, Nearest);
prep_retval::<Self::RustRet>(&mut this.0, ord)
}
}

impl MpOp for crate::op::[<frexp $suffix>]::Routine {
type MpTy = MpFloat;

Expand Down Expand Up @@ -481,6 +467,21 @@ macro_rules! impl_op_for_ty_all {
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
}
}

impl MpOp for crate::op::[<fmod $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);
let ord = this.0.rem_assign_round(&this.1, Nearest);
prep_retval::<Self::RustRet>(&mut this.0, ord)
}
}
}
};
}
Expand Down Expand Up @@ -526,22 +527,6 @@ impl MpOp for crate::op::lgammaf_r::Routine {
}
}

// No fmodf128 yet
impl MpOp for crate::op::fmodf16::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);
let ord = this.0.rem_assign_round(&this.1, Nearest);
prep_retval::<Self::RustRet>(&mut this.0, ord)
}
}

/* stub implementations so we don't need to special case them */

impl MpOp for crate::op::nextafter::Routine {
Expand Down
37 changes: 30 additions & 7 deletions crates/libm-test/src/run_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,30 @@ pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS";
/// Specify the number of iterations via this environment variable, rather than using the default.
pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS";

/// The override value, if set by the above environment.
static EXTENSIVE_ITER_OVERRIDE: LazyLock<Option<u64>> = LazyLock::new(|| {
env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok()
});

/// Specific tests that need to have a reduced amount of iterations to complete in a reasonable
/// amount of time.
///
/// Contains the itentifier+generator combo to match on, plus the factor to reduce by.
const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[
(Identifier::Fmodf128, GeneratorKind::QuickSpaced, 40),
(Identifier::Fmodf128, GeneratorKind::Extensive, 40),
];

/// Maximum number of iterations to run for a single routine.
///
/// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines
/// and single- or double-argument `f16` routines exhaustively. `f64` and `f128` can't feasibly
/// be tested exhaustively; however, [`EXTENSIVE_ITER_ENV`] can be set to run tests for multiple
/// hours.
pub static EXTENSIVE_MAX_ITERATIONS: LazyLock<u64> = LazyLock::new(|| {
let default = 1 << 32;
env::var(EXTENSIVE_ITER_ENV)
.map(|v| v.parse().expect("failed to parse iteration count"))
.unwrap_or(default)
});
pub fn extensive_max_iterations() -> u64 {
let default = 1 << 32; // default value
EXTENSIVE_ITER_OVERRIDE.unwrap_or(default)
}

/// Context passed to [`CheckOutput`].
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -206,12 +218,23 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 {
let mut total_iterations = match ctx.gen_kind {
GeneratorKind::QuickSpaced => domain_iter_count,
GeneratorKind::Random => random_iter_count,
GeneratorKind::Extensive => *EXTENSIVE_MAX_ITERATIONS,
GeneratorKind::Extensive => extensive_max_iterations(),
GeneratorKind::EdgeCases => {
unimplemented!("edge case tests shoudn't need `iteration_count`")
}
};

// Some tests are significantly slower than others and need to be further reduced.
if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS
.iter()
.find(|(id, gen, _scale)| *id == ctx.fn_ident && *gen == ctx.gen_kind)
{
// However, do not override if the extensive iteration count has been manually set.
if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) {
total_iterations /= scale;
}
}

// FMA has a huge domain but is reasonably fast to run, so increase iterations.
if ctx.base_name == BaseName::Fma {
total_iterations *= 4;
Expand Down
1 change: 1 addition & 0 deletions crates/libm-test/tests/compare_built_musl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ libm_macros::for_each_function! {
fmaxf16,
fminf128,
fminf16,
fmodf128,
fmodf16,
rintf128,
rintf16,
Expand Down
1 change: 1 addition & 0 deletions crates/util/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
| fmaxf16
| fminf128
| fminf16
| fmodf128
| fmodf16
| rintf128
| rintf16
Expand Down
7 changes: 7 additions & 0 deletions etc/function-definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,13 @@
],
"type": "f32"
},
"fmodf128": {
"sources": [
"src/math/fmodf128.rs",
"src/math/generic/fmod.rs"
],
"type": "f128"
},
"fmodf16": {
"sources": [
"src/math/fmodf16.rs",
Expand Down
1 change: 1 addition & 0 deletions etc/function-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ fminf128
fminf16
fmod
fmodf
fmodf128
fmodf16
frexp
frexpf
Expand Down
5 changes: 5 additions & 0 deletions src/math/fmodf128.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf128(x: f128, y: f128) -> f128 {
super::generic::fmod(x, y)
}
2 changes: 2 additions & 0 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ cfg_if! {
mod floorf128;
mod fmaxf128;
mod fminf128;
mod fmodf128;
mod rintf128;
mod roundf128;
mod sqrtf128;
Expand All @@ -390,6 +391,7 @@ cfg_if! {
pub use self::floorf128::floorf128;
pub use self::fmaxf128::fmaxf128;
pub use self::fminf128::fminf128;
pub use self::fmodf128::fmodf128;
pub use self::rintf128::rintf128;
pub use self::roundf128::roundf128;
pub use self::sqrtf128::sqrtf128;
Expand Down