#include "src/math/hypotf16.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/sqrt.h"
#include "src/__support/common.h"
#include "src/__support/macros/optimization.h"
#include "src/__support/macros/properties/types.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, hypotf16, (float16 x, float16 y)) {
using FloatBits = fputil::FPBits<float>;
using FPBits = fputil::FPBits<float16>;
FPBits x_abs = FPBits(x).abs();
FPBits y_abs = FPBits(y).abs();
bool x_abs_larger = x_abs.uintval() >= y_abs.uintval();
FPBits a_bits = x_abs_larger ? x_abs : y_abs;
FPBits b_bits = x_abs_larger ? y_abs : x_abs;
uint16_t a_u = a_bits.uintval();
uint16_t b_u = b_bits.uintval();
if (LIBC_UNLIKELY(a_u >= FPBits::EXP_MASK)) {
if (a_bits.is_signaling_nan() || b_bits.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
}
if (a_bits.is_inf() || b_bits.is_inf())
return FPBits::inf().get_val();
return a_bits.get_val();
}
float af = fputil::cast<float>(a_bits.get_val());
float bf = fputil::cast<float>(b_bits.get_val());
if (LIBC_UNLIKELY(a_u - b_u >=
static_cast<uint16_t>((FPBits::FRACTION_LEN + 2)
<< FPBits::FRACTION_LEN)))
return fputil::cast<float16>(af + bf);
float a_sq = af * af;
float sum_sq = fputil::multiply_add(bf, bf, a_sq);
FloatBits result(fputil::sqrt<float>(sum_sq));
uint32_t r_u = result.uintval();
if (LIBC_UNLIKELY(((r_u + 1) & 0x0000'0FFE) == 0)) {
float r_d = result.get_val();
float sum_sq_lo = fputil::multiply_add(bf, bf, a_sq - sum_sq);
float err = sum_sq_lo - fputil::multiply_add(r_d, r_d, -sum_sq);
if (err > 0) {
r_u |= 1;
} else if ((err < 0) && (r_u & 1) == 0) {
r_u -= 1;
} else if ((r_u & 0x0000'1FFF) == 0) {
fputil::clear_except_if_required(FE_INEXACT);
}
return fputil::cast<float16>(FloatBits(r_u).get_val());
}
return fputil::cast<float16>(result.get_val());
}
}