use crate::common::EXP_MASK_F32;
pub fn f_cathetusf(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 x_bits = x_abs.to_bits();
let y_bits = y_abs.to_bits();
let a_u = x_bits.max(y_bits);
if a_u >= EXP_MASK_F32 {
if f32::from_bits(x_bits).is_nan() || f32::from_bits(y_bits).is_nan() {
return f32::NAN;
}
if f32::from_bits(x_bits).is_infinite() || f32::from_bits(y_bits).is_infinite() {
if f32::from_bits(x_bits).is_infinite() && f32::from_bits(y_bits).is_infinite() {
return f32::NAN;
}
return f32::INFINITY;
}
return f32::from_bits(x_bits);
}
if x_abs < y_abs {
return f32::NAN;
}
if x_abs == y_abs {
return 0.0;
}
let dx = x as f64;
let dy = y as f64;
#[cfg(any(
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "fma"
),
target_arch = "aarch64"
))]
{
use crate::common::f_fmla;
let w = dy * dy; let e = f_fmla(-dy, dy, w); let f = f_fmla(dx, dx, -w); let r = e + f; let cath = r.sqrt(); cath as f32
}
#[cfg(not(any(
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "fma"
),
target_arch = "aarch64"
)))]
{
use crate::double_double::DoubleDouble;
let dy2 = DoubleDouble::from_exact_mult(dy, dy);
let fdx = DoubleDouble::from_exact_mult(dx, dx);
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_cathetusf_edge() {
assert_eq!(f_cathetusf(5., 3.), 4.);
assert_eq!(f_cathetusf(5., 4.), 3.);
assert_eq!(f_cathetusf(13., 12.), 5.);
assert_eq!(f_cathetusf(65., 16.), 63.);
assert_eq!(f_cathetusf(25., 24.), 7.);
assert!(f_cathetusf(24., 25.).is_nan());
}
#[test]
fn test_cathetusf_edge_cases() {
assert_eq!(f_cathetusf(0.0, 0.0), 0.0);
assert_eq!(f_cathetusf(f32::INFINITY, 0.0), f32::INFINITY);
assert_eq!(f_cathetusf(0.0, f32::INFINITY), f32::INFINITY);
assert!(f_cathetusf(f32::INFINITY, f32::INFINITY).is_nan());
assert_eq!(f_cathetusf(f32::NEG_INFINITY, 0.0), f32::INFINITY);
assert_eq!(f_cathetusf(0.0, f32::NEG_INFINITY), f32::INFINITY);
assert!(f_cathetusf(f32::NEG_INFINITY, f32::NEG_INFINITY).is_nan());
assert!(f_cathetusf(f32::NAN, 1.0).is_nan());
assert!(f_cathetusf(1.0, f32::NAN).is_nan());
}
}