use crate::common::EXP_MASK_F32;
#[inline]
pub fn f_hypotf(x: f32, y: f32) -> f32 {
let x_abs = f32::from_bits(x.to_bits() & 0x7fff_ffffu32);
let y_abs = f32::from_bits(y.to_bits() & 0x7fff_ffffu32);
let a_bits = x_abs.to_bits().max(y_abs.to_bits());
let b_bits = x_abs.to_bits().min(y_abs.to_bits());
let a_u = a_bits;
let b_u = b_bits;
if a_u >= EXP_MASK_F32 {
if f32::from_bits(a_bits).is_nan() || f32::from_bits(b_bits).is_nan() {
return f32::NAN;
}
if f32::from_bits(a_bits).is_infinite() || f32::from_bits(b_bits).is_infinite() {
return f32::INFINITY;
}
return f32::from_bits(a_bits);
}
if a_u.wrapping_sub(b_u) >= ((23u32 + 2) << 23) {
return x_abs + y_abs;
}
#[cfg(any(
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "fma"
),
target_arch = "aarch64"
))]
{
let ad = x as f64;
let bd = y as f64;
use crate::common::f_fmla;
let w = bd * bd; let e = f_fmla(-bd, bd, w); let f = f_fmla(ad, ad, w); let r = e + f; let hyp = r.sqrt(); hyp as f32
}
#[cfg(not(any(
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "fma"
),
target_arch = "aarch64"
)))]
{
let ad = f32::from_bits(a_bits) as f64;
let bd = f32::from_bits(b_bits) as f64;
use crate::double_double::DoubleDouble;
let dy2 = DoubleDouble::from_exact_mult(bd, bd);
let fdx = DoubleDouble::from_exact_mult(ad, ad);
let f = DoubleDouble::add_f64(fdx, dy2.hi).to_f64();
let r = dy2.lo + f;
let cath = r.sqrt();
cath as f32
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hypotf() {
assert_eq!(
f_hypotf(
0.000000000000000000000000000000000000000091771,
0.000000000000000000000000000000000000011754585
),
0.000000000000000000000000000000000000011754944
);
assert_eq!(
f_hypotf(9.177e-41, 1.1754585e-38),
0.000000000000000000000000000000000000011754944
);
let dx = (f_hypotf(1f32, 1f32) - (1f32 * 1f32 + 1f32 * 1f32).sqrt()).abs();
assert!(dx < 1e-5);
let dx = (f_hypotf(5f32, 5f32) - (5f32 * 5f32 + 5f32 * 5f32).sqrt()).abs();
assert!(dx < 1e-5);
}
#[test]
fn test_hypotf_edge_cases() {
assert_eq!(f_hypotf(-1.0, -3.0), 3.1622777);
assert_eq!(f_hypotf(0.0, 0.0), 0.0);
assert_eq!(f_hypotf(f32::INFINITY, 0.0), f32::INFINITY);
assert_eq!(f_hypotf(0.0, f32::INFINITY), f32::INFINITY);
assert_eq!(f_hypotf(f32::INFINITY, f32::INFINITY), f32::INFINITY);
assert_eq!(f_hypotf(f32::NEG_INFINITY, 0.0), f32::INFINITY);
assert_eq!(f_hypotf(0.0, f32::NEG_INFINITY), f32::INFINITY);
assert_eq!(
f_hypotf(f32::NEG_INFINITY, f32::NEG_INFINITY),
f32::INFINITY
);
assert!(f_hypotf(f32::NAN, 1.0).is_nan());
assert!(f_hypotf(1.0, f32::NAN).is_nan());
}
}