Add sqrtf16 and sqrtf128

Use the generic algorithms to provide implementations for these
routines.
This commit is contained in:
Trevor Gross 2025-01-21 23:59:07 +00:00
parent 03041a0371
commit 186eac9227
11 changed files with 132 additions and 2 deletions

View file

@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
FloatTy::F16,
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
None,
&["fabsf16", "truncf16"],
&["fabsf16", "sqrtf16", "truncf16"],
),
(
// `fn(f32) -> f32`
@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
FloatTy::F128,
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
None,
&["fabsf128", "truncf128"],
&["fabsf128", "sqrtf128", "truncf128"],
),
(
// `(f16, f16) -> f16`

View file

@ -155,6 +155,8 @@ main!(
icount_bench_sinh_group,
icount_bench_sinhf_group,
icount_bench_sqrt_group,
icount_bench_sqrtf128_group,
icount_bench_sqrtf16_group,
icount_bench_sqrtf_group,
icount_bench_tan_group,
icount_bench_tanf_group,

View file

@ -123,6 +123,8 @@ libm_macros::for_each_function! {
| fabsf16
| fdimf128
| fdimf16
| sqrtf16
| sqrtf128
| truncf128
| truncf16 => (false, None),

View file

@ -87,5 +87,7 @@ libm_macros::for_each_function! {
fdimf16,
truncf128,
truncf16,
sqrtf16,
sqrtf128,
],
}

View file

@ -90,6 +90,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
| fabsf16
| fdimf128
| fdimf16
| sqrtf128
| sqrtf16
| truncf128
| truncf16 => None,
_ => Some(musl_math_sys::MACRO_FN_NAME)

View file

@ -718,6 +718,20 @@
],
"type": "f32"
},
"sqrtf128": {
"sources": [
"src/math/generic/sqrt.rs",
"src/math/sqrtf128.rs"
],
"type": "f128"
},
"sqrtf16": {
"sources": [
"src/math/generic/sqrt.rs",
"src/math/sqrtf16.rs"
],
"type": "f16"
},
"tan": {
"sources": [
"src/libm_helper.rs",

View file

@ -105,6 +105,8 @@ sinh
sinhf
sqrt
sqrtf
sqrtf128
sqrtf16
tan
tanf
tanh

View file

@ -294,6 +294,14 @@ pub trait SqrtHelper: Float {
const FINAL_ROUNDS: u32;
}
#[cfg(f16_enabled)]
impl SqrtHelper for f16 {
type ISet1 = u16; // unused
type ISet2 = u16; // unused
const FINAL_ROUNDS: u32 = 2;
}
impl SqrtHelper for f32 {
type ISet1 = u32; // unused
type ISet2 = u32; // unused
@ -309,6 +317,16 @@ impl SqrtHelper for f64 {
const FINAL_ROUNDS: u32 = 2;
}
#[cfg(f128_enabled)]
impl SqrtHelper for f128 {
type ISet1 = u32;
type ISet2 = u64;
const SET1_ROUNDS: u32 = 1;
const SET2_ROUNDS: u32 = 2;
const FINAL_ROUNDS: u32 = 2;
}
/// A U0.16 representation of `1/sqrt(x)`.
///
// / The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand.
@ -355,6 +373,42 @@ mod tests {
}
}
#[test]
#[cfg(f16_enabled)]
fn sanity_check_f16() {
assert_biteq!(sqrt(100.0f16), 10.0);
assert_biteq!(sqrt(4.0f16), 2.0);
}
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
spec_test::<f16>();
}
#[test]
#[cfg(f16_enabled)]
#[allow(clippy::approx_constant)]
fn conformance_tests_f16() {
let cases = [
(f16::PI, 0x3f17_u16),
// 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as
// part of the AST, so the `cfg` is irrelevant here).
(f16::from_bits(0x70e2), 0x5640_u16),
(f16::from_bits(0x0000000f), 0x13bf_u16),
(f16::INFINITY, f16::INFINITY.to_bits()),
];
for (input, output) in cases {
assert_biteq!(
sqrt(input),
f16::from_bits(output),
"input: {input:?} ({:#018x})",
input.to_bits()
);
}
}
#[test]
fn sanity_check_f32() {
assert_biteq!(sqrt(100.0f32), 10.0);
@ -416,4 +470,42 @@ mod tests {
);
}
}
#[test]
#[cfg(f128_enabled)]
fn sanity_check_f128() {
assert_biteq!(sqrt(100.0f128), 10.0);
assert_biteq!(sqrt(4.0f128), 2.0);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
spec_test::<f128>();
}
#[test]
#[cfg(f128_enabled)]
#[allow(clippy::approx_constant)]
fn conformance_tests_f128() {
let cases = [
(f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128),
// 10_000.0, see `f16` for reasoning.
(
f128::from_bits(0x400c3880000000000000000000000000),
0x40059000000000000000000000000000_u128,
),
(f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128),
(f128::INFINITY, f128::INFINITY.to_bits()),
];
for (input, output) in cases {
assert_biteq!(
sqrt(input),
f128::from_bits(output),
"input: {input:?} ({:#018x})",
input.to_bits()
);
}
}
}

View file

@ -344,11 +344,13 @@ cfg_if! {
mod copysignf16;
mod fabsf16;
mod fdimf16;
mod sqrtf16;
mod truncf16;
pub use self::copysignf16::copysignf16;
pub use self::fabsf16::fabsf16;
pub use self::fdimf16::fdimf16;
pub use self::sqrtf16::sqrtf16;
pub use self::truncf16::truncf16;
}
}
@ -358,11 +360,13 @@ cfg_if! {
mod copysignf128;
mod fabsf128;
mod fdimf128;
mod sqrtf128;
mod truncf128;
pub use self::copysignf128::copysignf128;
pub use self::fabsf128::fabsf128;
pub use self::fdimf128::fdimf128;
pub use self::sqrtf128::sqrtf128;
pub use self::truncf128::truncf128;
}
}

View file

@ -0,0 +1,5 @@
/// The square root of `x` (f128).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn sqrtf128(x: f128) -> f128 {
return super::generic::sqrt(x);
}

View file

@ -0,0 +1,5 @@
/// The square root of `x` (f16).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn sqrtf16(x: f16) -> f16 {
return super::generic::sqrt(x);
}