use super::sos::sum_squares;
use crate::big_uint::{BigUInt, HiLo};
use crate::math::sqrt::square_root;
use crate::{
abs_bits, abs_bits_sticky, f256, signif, BinEncAnySpecial, EMAX, EMIN,
EXP_BIAS, EXP_MAX, FRACTION_BITS, HI_EXP_MASK, HI_FRACTION_BITS,
};
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_sign_loss)]
pub(crate) fn hypot(x: &f256, y: &f256) -> f256 {
let mut abs_bits_x = abs_bits(x);
let mut abs_bits_y = abs_bits(y);
let abs_bits_sticky_x = abs_bits_sticky(&abs_bits_x);
let abs_bits_sticky_y = abs_bits_sticky(&abs_bits_y);
if (abs_bits_sticky_x, abs_bits_sticky_y).any_special() {
if abs_bits_sticky_x > HI_EXP_MASK || abs_bits_sticky_y > HI_EXP_MASK
{
return f256::NAN;
}
if abs_bits_sticky_x == 0 {
return f256 { bits: abs_bits_y };
}
if abs_bits_sticky_y == 0 {
return f256 { bits: abs_bits_x };
}
return f256::INFINITY;
}
let (signif, exp) = sum_squares(&mut abs_bits_x, &mut abs_bits_y);
let (mut p, mut q) = square_root(&signif.hi, exp);
if p > EMAX {
return f256::INFINITY;
}
if p < EMIN {
let shr = (EMIN - p + 1) as u32;
return f256 {
bits: q.rounding_div_pow2(shr),
};
}
let exp_bits_minus_1 = (EXP_BIAS as i32 + p - 1) as u128;
let r = q.lo_t().lo_t() & 1;
let mut bits = q >> 1;
debug_assert_eq!(bits.hi.msb(), HI_FRACTION_BITS);
bits.hi.0 += exp_bits_minus_1 << HI_FRACTION_BITS;
bits.incr_if(r == 1);
f256 { bits }
}