Merge pull request rust-lang/libm#389 from rust-lang/tgross35/f16-f128-copysign-fabs
Add `copysignf16`, `copysignf128`, `fabsf16`, and `fabsf128`
This commit is contained in:
commit
d9aee94763
22 changed files with 344 additions and 49 deletions
|
|
@ -4,6 +4,13 @@ use std::fmt;
|
|||
use std::sync::LazyLock;
|
||||
|
||||
const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&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<Signature>, &[&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<Signature>, &[&str])]
|
|||
"remainder",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f128, f128) -> f128`
|
||||
FloatTy::F128,
|
||||
Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] },
|
||||
None,
|
||||
&["copysignf128"],
|
||||
),
|
||||
(
|
||||
// `(f32, f32, f32) -> f32`
|
||||
FloatTy::F32,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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<Op>),
|
||||
skip_on_i586: $skip_on_i586
|
||||
let musl_extra = MuslExtra::<libm_test::OpCFn<Op>> {
|
||||
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::<Op>(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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ libm_macros::for_each_function! {
|
|||
atan2f,
|
||||
copysign,
|
||||
copysignf,
|
||||
copysignf16,
|
||||
copysignf128,
|
||||
fdim,
|
||||
fdimf,
|
||||
fma,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from pathlib import Path
|
|||
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 @@ class Crate:
|
|||
"--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 @@ class Crate:
|
|||
|
||||
# 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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
8
library/compiler-builtins/libm/src/math/copysignf128.rs
Normal file
8
library/compiler-builtins/libm/src/math/copysignf128.rs
Normal file
|
|
@ -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)
|
||||
}
|
||||
8
library/compiler-builtins/libm/src/math/copysignf16.rs
Normal file
8
library/compiler-builtins/libm/src/math/copysignf16.rs
Normal file
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
37
library/compiler-builtins/libm/src/math/fabsf128.rs
Normal file
37
library/compiler-builtins/libm/src/math/fabsf128.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
library/compiler-builtins/libm/src/math/fabsf16.rs
Normal file
37
library/compiler-builtins/libm/src/math/fabsf16.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue