diff --git a/crates/libm-macros/src/shared.rs b/crates/libm-macros/src/shared.rs index ef0f18801..16547404f 100644 --- a/crates/libm-macros/src/shared.rs +++ b/crates/libm-macros/src/shared.rs @@ -4,6 +4,13 @@ use std::fmt; use std::sync::LazyLock; const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ + ( + // `fn(f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16], returns: &[Ty::F16] }, + None, + &["fabsf16"], + ), ( // `fn(f32) -> f32` FloatTy::F32, @@ -28,6 +35,20 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "tgamma", "trunc", "y0", "y1", ], ), + ( + // `fn(f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128], returns: &[Ty::F128] }, + None, + &["fabsf128"], + ), + ( + // `(f16, f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, + None, + &["copysignf16"], + ), ( // `(f32, f32) -> f32` FloatTy::F32, @@ -64,6 +85,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "remainder", ], ), + ( + // `(f128, f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, + None, + &["copysignf128"], + ), ( // `(f32, f32, f32) -> f32` FloatTy::F32, diff --git a/crates/libm-test/Cargo.toml b/crates/libm-test/Cargo.toml index 69e96034e..2761d3d52 100644 --- a/crates/libm-test/Cargo.toml +++ b/crates/libm-test/Cargo.toml @@ -8,7 +8,7 @@ publish = false default = ["unstable-float"] # Propagated from libm because this affects which functions we test. -unstable-float = ["libm/unstable-float"] +unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. diff --git a/crates/libm-test/benches/random.rs b/crates/libm-test/benches/random.rs index 23f429455..cd1e2d2cc 100644 --- a/crates/libm-test/benches/random.rs +++ b/crates/libm-test/benches/random.rs @@ -20,7 +20,7 @@ macro_rules! musl_rand_benches { ( fn_name: $fn_name:ident, attrs: [$($attr:meta),*], - fn_extra: $skip_on_i586:expr, + fn_extra: ($skip_on_i586:expr, $musl_fn:expr), ) => { paste::paste! { $(#[$attr])* @@ -28,15 +28,15 @@ macro_rules! musl_rand_benches { type Op = libm_test::op::$fn_name::Routine; #[cfg(feature = "build-musl")] - let musl_extra = MuslExtra { - musl_fn: Some(musl_math_sys::$fn_name as libm_test::OpCFn), - skip_on_i586: $skip_on_i586 + let musl_extra = MuslExtra::> { + musl_fn: $musl_fn, + skip_on_i586: $skip_on_i586, }; #[cfg(not(feature = "build-musl"))] let musl_extra = MuslExtra { musl_fn: None, - skip_on_i586: $skip_on_i586 + skip_on_i586: $skip_on_i586, }; bench_one::(c, musl_extra); @@ -67,7 +67,10 @@ where break; } - let musl_res = input.call(musl_extra.musl_fn.unwrap()); + let Some(musl_fn) = musl_extra.musl_fn else { + continue; + }; + let musl_res = input.call(musl_fn); let crate_res = input.call(Op::ROUTINE); crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); @@ -91,15 +94,16 @@ where // Don't test against musl if it is not available #[cfg(feature = "build-musl")] { - let musl_fn = musl_extra.musl_fn.unwrap(); - group.bench_function("musl", |b| { - b.iter(|| { - let f = black_box(musl_fn); - for input in benchvec.iter().copied() { - input.call(f); - } - }) - }); + if let Some(musl_fn) = musl_extra.musl_fn { + group.bench_function("musl", |b| { + b.iter(|| { + let f = black_box(musl_fn); + for input in benchvec.iter().copied() { + input.call(f); + } + }) + }); + } } } @@ -107,9 +111,16 @@ libm_macros::for_each_function! { callback: musl_rand_benches, skip: [], fn_extra: match MACRO_FN_NAME { - // FIXME(correctness): wrong result on i586 - exp10 | exp10f | exp2 | exp2f => true, - _ => false + // We pass a tuple of `(skip_on_i586, musl_fn)` + + // FIXME(correctness): exp functions have the wrong result on i586 + exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), + + // Musl does not provide `f16` and `f128` functions + copysignf16 | copysignf128 | fabsf16 | fabsf128 => (false, None), + + // By default we never skip (false) and always have a musl function available + _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) } } diff --git a/crates/libm-test/src/domain.rs b/crates/libm-test/src/domain.rs index 7b5a01b96..52393d402 100644 --- a/crates/libm-test/src/domain.rs +++ b/crates/libm-test/src/domain.rs @@ -187,3 +187,15 @@ impl HasDomain for crate::op::lgammaf_r::Routine { impl HasDomain for crate::op::lgamma_r::Routine { const DOMAIN: Domain = Domain::::LGAMMA; } + +/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */ + +#[cfg(f16_enabled)] +impl HasDomain for crate::op::fabsf16::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + +#[cfg(f128_enabled)] +impl HasDomain for crate::op::fabsf128::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} diff --git a/crates/libm-test/src/gen/extensive.rs b/crates/libm-test/src/gen/extensive.rs index d8b991b2a..d724226e9 100644 --- a/crates/libm-test/src/gen/extensive.rs +++ b/crates/libm-test/src/gen/extensive.rs @@ -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( diff --git a/crates/libm-test/src/gen/random.rs b/crates/libm-test/src/gen/random.rs index 29a9dcd2b..6b08e560d 100644 --- a/crates/libm-test/src/gen/random.rs +++ b/crates/libm-test/src/gen/random.rs @@ -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( diff --git a/crates/libm-test/src/mpfloat.rs b/crates/libm-test/src/mpfloat.rs index ad98fafc8..f2b7b2f25 100644 --- a/crates/libm-test/src/mpfloat.rs +++ b/crates/libm-test/src/mpfloat.rs @@ -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::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - 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::(&mut this.0, Ordering::Equal) - } - } - impl MpOp for crate::op::[]::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::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + 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::(&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; diff --git a/crates/libm-test/src/precision.rs b/crates/libm-test/src/precision.rs index 696bb3735..f8c3a7b8f 100644 --- a/crates/libm-test/src/precision.rs +++ b/crates/libm-test/src/precision.rs @@ -157,6 +157,9 @@ pub trait MaybeOverride { } } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16,)> for SpecialCase {} + impl MaybeOverride<(f32,)> for SpecialCase { fn check_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(actual: F, expected: F, ctx: &CheckCtx) -> Option { if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) { @@ -317,6 +323,19 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt } } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16, f16)> for SpecialCase { + fn check_float( + input: (f16, f16), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_binop_nan(input, expected, ctx) + } +} + impl MaybeOverride<(f32, f32)> for SpecialCase { fn check_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( + input: (f128, f128), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + 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( diff --git a/crates/libm-test/src/test_traits.rs b/crates/libm-test/src/test_traits.rs index 261d1f254..0a4baa2e3 100644 --- a/crates/libm-test/src/test_traits.rs +++ b/crates/libm-test/src/test_traits.rs @@ -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. diff --git a/crates/libm-test/tests/compare_built_musl.rs b/crates/libm-test/tests/compare_built_musl.rs index ecd379a0a..3e11d322a 100644 --- a/crates/libm-test/tests/compare_built_musl.rs +++ b/crates/libm-test/tests/compare_built_musl.rs @@ -46,6 +46,8 @@ where libm_macros::for_each_function! { callback: musl_rand_tests, + // Musl does not support `f16` and `f128` on all platforms. + skip: [copysignf16, copysignf128, fabsf16, fabsf128], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] diff --git a/crates/libm-test/tests/multiprecision.rs b/crates/libm-test/tests/multiprecision.rs index 42ec965c1..7961b0802 100644 --- a/crates/libm-test/tests/multiprecision.rs +++ b/crates/libm-test/tests/multiprecision.rs @@ -120,6 +120,8 @@ libm_macros::for_each_function! { atan2f, copysign, copysignf, + copysignf16, + copysignf128, fdim, fdimf, fma, diff --git a/etc/function-definitions.json b/etc/function-definitions.json index 4b10812c3..0b2d6214f 100644 --- a/etc/function-definitions.json +++ b/etc/function-definitions.json @@ -136,6 +136,20 @@ ], "type": "f32" }, + "copysignf128": { + "sources": [ + "src/math/copysignf128.rs", + "src/math/generic/copysign.rs" + ], + "type": "f128" + }, + "copysignf16": { + "sources": [ + "src/math/copysignf16.rs", + "src/math/generic/copysign.rs" + ], + "type": "f16" + }, "cos": { "sources": [ "src/libm_helper.rs", @@ -258,6 +272,20 @@ ], "type": "f32" }, + "fabsf128": { + "sources": [ + "src/math/fabsf128.rs", + "src/math/generic/fabs.rs" + ], + "type": "f128" + }, + "fabsf16": { + "sources": [ + "src/math/fabsf16.rs", + "src/math/generic/fabs.rs" + ], + "type": "f16" + }, "fdim": { "sources": [ "src/libm_helper.rs", diff --git a/etc/function-list.txt b/etc/function-list.txt index 51f5b221c..0a1bbab24 100644 --- a/etc/function-list.txt +++ b/etc/function-list.txt @@ -19,6 +19,8 @@ ceil ceilf copysign copysignf +copysignf128 +copysignf16 cos cosf cosh @@ -37,6 +39,8 @@ expm1 expm1f fabs fabsf +fabsf128 +fabsf16 fdim fdimf floor diff --git a/etc/update-api-list.py b/etc/update-api-list.py index a4587aa81..67f73e59c 100755 --- a/etc/update-api-list.py +++ b/etc/update-api-list.py @@ -13,6 +13,7 @@ from typing import Any, TypeAlias ETC_DIR = Path(__file__).parent +ROOT_DIR = ETC_DIR.parent IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" @@ -56,10 +57,12 @@ def get_rustdoc_json() -> dict[Any, Any]: "--edition=2021", "--document-private-items", "--output-format=json", + "--cfg=f16_enabled", + "--cfg=f128_enabled", "-Zunstable-options", "-o-", ], - cwd=ETC_DIR.parent, + cwd=ROOT_DIR, text=True, ) j = json.loads(j) @@ -105,8 +108,8 @@ def _init_defs(self, index: IndexTy) -> None: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("src/math/arch/**.rs", root_dir=ETC_DIR.parent): - contents = Path(fname).read_text() + for fname in glob("src/math/arch/**.rs", root_dir=ROOT_DIR): + contents = (ROOT_DIR.joinpath(fname)).read_text() for name in self.public_functions: if f"fn {name}" in contents: diff --git a/src/libm_helper.rs b/src/libm_helper.rs index 52d0c4c2a..f087267e4 100644 --- a/src/libm_helper.rs +++ b/src/libm_helper.rs @@ -30,7 +30,7 @@ macro_rules! libm_helper { } }; - ({$($func:tt);*}) => { + ({$($func:tt;)*}) => { $( libm_helper! { $func } )* @@ -103,7 +103,7 @@ libm_helper! { (fn trunc(x: f32) -> (f32); => truncf); (fn y0(x: f32) -> (f32); => y0f); (fn y1(x: f32) -> (f32); => y1f); - (fn yn(n: i32, x: f32) -> (f32); => ynf) + (fn yn(n: i32, x: f32) -> (f32); => ynf); } } @@ -166,6 +166,24 @@ libm_helper! { (fn trunc(x: f64) -> (f64); => trunc); (fn y0(x: f64) -> (f64); => y0); (fn y1(x: f64) -> (f64); => y1); - (fn yn(n: i32, x: f64) -> (f64); => yn) + (fn yn(n: i32, x: f64) -> (f64); => yn); + } +} + +#[cfg(f16_enabled)] +libm_helper! { + f16, + funcs: { + (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); + (fn fabs(x: f16) -> (f16); => fabsf16); + } +} + +#[cfg(f128_enabled)] +libm_helper! { + f128, + funcs: { + (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); + (fn fabs(x: f128) -> (f128); => fabsf128); } } diff --git a/src/math/copysignf128.rs b/src/math/copysignf128.rs new file mode 100644 index 000000000..7bd81d42b --- /dev/null +++ b/src/math/copysignf128.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} diff --git a/src/math/copysignf16.rs b/src/math/copysignf16.rs new file mode 100644 index 000000000..820658686 --- /dev/null +++ b/src/math/copysignf16.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} diff --git a/src/math/fabs.rs b/src/math/fabs.rs index 6687fdcc3..46c0d88a5 100644 --- a/src/math/fabs.rs +++ b/src/math/fabs.rs @@ -1,4 +1,5 @@ /// Absolute value (magnitude) (f64) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/src/math/fabsf.rs b/src/math/fabsf.rs index 99bb5b5f1..d5775b600 100644 --- a/src/math/fabsf.rs +++ b/src/math/fabsf.rs @@ -1,4 +1,5 @@ /// Absolute value (magnitude) (f32) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/src/math/fabsf128.rs b/src/math/fabsf128.rs new file mode 100644 index 000000000..ef531bd91 --- /dev/null +++ b/src/math/fabsf128.rs @@ -0,0 +1,37 @@ +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, + } + + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf128(-1.0), 1.0); + assert_eq!(fabsf128(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf128(f128::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf128(f), 0.0); + } + for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf128(f), f128::INFINITY); + } + } +} diff --git a/src/math/fabsf16.rs b/src/math/fabsf16.rs new file mode 100644 index 000000000..eb41f7391 --- /dev/null +++ b/src/math/fabsf16.rs @@ -0,0 +1,37 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, + } + + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf16(-1.0), 1.0); + assert_eq!(fabsf16(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf16(f16::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf16(f), 0.0); + } + for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf16(f), f16::INFINITY); + } + } +} diff --git a/src/math/mod.rs b/src/math/mod.rs index 9003a8342..5baf35e42 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -339,6 +339,26 @@ pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; +cfg_if! { + if #[cfg(f16_enabled)] { + mod copysignf16; + mod fabsf16; + + pub use self::copysignf16::copysignf16; + pub use self::fabsf16::fabsf16; + } +} + +cfg_if! { + if #[cfg(f128_enabled)] { + mod copysignf128; + mod fabsf128; + + pub use self::copysignf128::copysignf128; + pub use self::fabsf128::fabsf128; + } +} + #[inline] fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32