| use super::generic; |
| use crate::support::Round; |
| |
| /// The square root of `x` (f16). |
| #[cfg(f16_enabled)] |
| #[cfg_attr(assert_no_panic, no_panic::no_panic)] |
| pub fn sqrtf16(x: f16) -> f16 { |
| select_implementation! { |
| name: sqrtf16, |
| use_arch: all(target_arch = "aarch64", target_feature = "fp16"), |
| args: x, |
| } |
| |
| return generic::sqrt_round(x, Round::Nearest).val; |
| } |
| |
| /// The square root of `x` (f32). |
| #[cfg_attr(assert_no_panic, no_panic::no_panic)] |
| pub fn sqrtf(x: f32) -> f32 { |
| select_implementation! { |
| name: sqrtf, |
| use_arch: any( |
| all(target_arch = "aarch64", target_feature = "neon"), |
| all(target_arch = "wasm32", intrinsics_enabled), |
| target_feature = "sse2" |
| ), |
| args: x, |
| } |
| |
| generic::sqrt_round(x, Round::Nearest).val |
| } |
| |
| /// The square root of `x` (f64). |
| #[cfg_attr(assert_no_panic, no_panic::no_panic)] |
| pub fn sqrt(x: f64) -> f64 { |
| select_implementation! { |
| name: sqrt, |
| use_arch: any( |
| all(target_arch = "aarch64", target_feature = "neon"), |
| all(target_arch = "wasm32", intrinsics_enabled), |
| target_feature = "sse2" |
| ), |
| args: x, |
| } |
| |
| generic::sqrt_round(x, Round::Nearest).val |
| } |
| |
| /// The square root of `x` (f128). |
| #[cfg(f128_enabled)] |
| #[cfg_attr(assert_no_panic, no_panic::no_panic)] |
| pub fn sqrtf128(x: f128) -> f128 { |
| return generic::sqrt_round(x, Round::Nearest).val; |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use generic::SqrtHelper; |
| |
| use super::*; |
| use crate::support::{CastInto, Float, FpResult, HInt, Status}; |
| |
| /// Test behavior specified in IEEE 754 `squareRoot`. |
| fn spec_test<F>() |
| where |
| F: Float + SqrtHelper, |
| F::Int: HInt, |
| F::Int: From<u8>, |
| F::Int: From<F::ISet2>, |
| F::Int: CastInto<F::ISet1>, |
| F::Int: CastInto<F::ISet2>, |
| u32: CastInto<F::Int>, |
| { |
| // Values that should return a NaN and raise invalid |
| let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; |
| |
| // Values that return unaltered |
| let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; |
| |
| for x in nan { |
| let FpResult { val, status } = generic::sqrt_round(x, Round::Nearest); |
| assert!(val.is_nan()); |
| assert!(status == Status::INVALID); |
| } |
| |
| for x in roundtrip { |
| let FpResult { val, status } = generic::sqrt_round(x, Round::Nearest); |
| assert_biteq!(val, x); |
| assert!(status == Status::OK); |
| } |
| } |
| |
| #[test] |
| #[cfg(f16_enabled)] |
| fn sanity_check_f16() { |
| assert_biteq!(sqrtf16(100.0f16), 10.0); |
| assert_biteq!(sqrtf16(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), |
| (10000.0_f16, 0x5640_u16), |
| (f16::from_bits(0x0000000f), 0x13bf_u16), |
| (f16::INFINITY, f16::INFINITY.to_bits()), |
| ]; |
| |
| for (input, output) in cases { |
| assert_biteq!( |
| sqrtf16(input), |
| f16::from_bits(output), |
| "input: {input:?} ({:#018x})", |
| input.to_bits() |
| ); |
| } |
| } |
| |
| #[test] |
| fn sanity_check_f32() { |
| assert_biteq!(sqrtf(100.0f32), 10.0); |
| assert_biteq!(sqrtf(4.0f32), 2.0); |
| } |
| |
| #[test] |
| fn spec_tests_f32() { |
| spec_test::<f32>(); |
| } |
| |
| #[test] |
| #[allow(clippy::approx_constant)] |
| fn conformance_tests_f32() { |
| let cases = [ |
| (f32::PI, 0x3fe2dfc5_u32), |
| (10000.0f32, 0x42c80000_u32), |
| (f32::from_bits(0x0000000f), 0x1b2f456f_u32), |
| (f32::INFINITY, f32::INFINITY.to_bits()), |
| ]; |
| |
| for (input, output) in cases { |
| assert_biteq!( |
| sqrtf(input), |
| f32::from_bits(output), |
| "input: {input:?} ({:#018x})", |
| input.to_bits() |
| ); |
| } |
| } |
| |
| #[test] |
| fn sanity_check_f64() { |
| assert_biteq!(sqrt(100.0f64), 10.0); |
| assert_biteq!(sqrt(4.0f64), 2.0); |
| } |
| |
| #[test] |
| fn spec_tests_f64() { |
| spec_test::<f64>(); |
| } |
| |
| #[test] |
| #[allow(clippy::approx_constant)] |
| fn conformance_tests_f64() { |
| let cases = [ |
| (f64::PI, 0x3ffc5bf891b4ef6a_u64), |
| (10000.0, 0x4059000000000000_u64), |
| (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), |
| (f64::INFINITY, f64::INFINITY.to_bits()), |
| ]; |
| |
| for (input, output) in cases { |
| assert_biteq!( |
| sqrt(input), |
| f64::from_bits(output), |
| "input: {input:?} ({:#018x})", |
| input.to_bits() |
| ); |
| } |
| } |
| |
| #[test] |
| #[cfg(f128_enabled)] |
| fn sanity_check_f128() { |
| assert_biteq!(sqrtf128(100.0f128), 10.0); |
| assert_biteq!(sqrtf128(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!( |
| sqrtf128(input), |
| f128::from_bits(output), |
| "input: {input:?} ({:#018x})", |
| input.to_bits() |
| ); |
| } |
| } |
| } |