blob: 5da1e7310948883d3e166d4d5bf1cea730d360da [file] [log] [blame] [edit]
//===-- Implementation header for rsqrtf ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_RSQRTF_H
#define LLVM_LIBC_SRC___SUPPORT_MATH_RSQRTF_H
#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/sqrt.h"
#include "src/__support/macros/optimization.h"
namespace LIBC_NAMESPACE_DECL {
namespace math {
LIBC_INLINE static constexpr float rsqrtf(float x) {
using FPBits = fputil::FPBits<float>;
FPBits xbits(x);
uint32_t x_u = xbits.uintval();
uint32_t x_abs = x_u & 0x7fff'ffffU;
constexpr uint32_t INF_BITS = FPBits::inf().uintval();
// x is 0, inf/nan, or negative.
if (LIBC_UNLIKELY(x_u == 0 || x_u >= INF_BITS)) {
// x is NaN
if (x_abs > INF_BITS) {
if (xbits.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
}
return x;
}
// |x| = 0
if (x_abs == 0) {
fputil::raise_except_if_required(FE_DIVBYZERO);
fputil::set_errno_if_required(ERANGE);
return FPBits::inf(xbits.sign()).get_val();
}
// -inf <= x < 0
if (x_u > 0x7fff'ffffU) {
fputil::raise_except_if_required(FE_INVALID);
fputil::set_errno_if_required(EDOM);
return FPBits::quiet_nan().get_val();
}
// x = +inf => rsqrt(x) = 0
return FPBits::zero(xbits.sign()).get_val();
}
// TODO: add float based approximation when
// LIBC_TARGET_CPU_HAS_FPU_DOUBLE is not defined
double result = 1.0 / fputil::sqrt<double>(fputil::cast<double>(x));
return fputil::cast<float>(result);
}
} // namespace math
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_MATH_RSQRTF_H