#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_H
#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_H
#include "exp10f_utils.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
namespace LIBC_NAMESPACE_DECL {
namespace math {
LIBC_INLINE static constexpr float exp10f(float x) {
using FPBits = typename fputil::FPBits<float>;
FPBits xbits(x);
uint32_t x_u = xbits.uintval();
uint32_t x_abs = x_u & 0x7fff'ffffU;
if (LIBC_UNLIKELY(x_abs >= 0x421a'209bU)) {
if (x_u > 0xc234'9e35U) {
if (xbits.is_inf())
return 0.0f;
if (xbits.is_nan())
return x;
if (fputil::fenv_is_round_up())
return FPBits::min_subnormal().get_val();
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_UNDERFLOW);
return 0.0f;
}
if (xbits.is_pos() && (x_u >= 0x421a'209bU)) {
if (x_u < 0x7f80'0000U) {
int rounding = fputil::quick_get_round();
if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
return FPBits::max_normal().get_val();
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_OVERFLOW);
}
return x + FPBits::inf().get_val();
}
}
if (LIBC_UNLIKELY(x_abs <= 0x3b9a'209bU)) {
if (LIBC_UNLIKELY(x_u == 0xb25e'5bd9U)) {
if (fputil::fenv_is_round_to_nearest())
return 0x1.fffffep-1f;
}
if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
return fputil::multiply_add(x, 0x1.26bb1cp+1f, 1.0f);
}
return static_cast<float>(Exp10Base::powb_lo(x));
}
if (LIBC_UNLIKELY(x_u == 0x3d14'd956U)) {
if (fputil::fenv_is_round_up())
return 0x1.1657c4p+0f;
}
if (LIBC_UNLIKELY((x_u & 0x800f'ffffU) == 0)) {
switch (x_u) {
case 0x3f800000U:
return 10.0f;
case 0x40000000U:
return 100.0f;
case 0x40400000U:
return 1'000.0f;
case 0x40800000U:
return 10'000.0f;
case 0x40a00000U:
return 100'000.0f;
case 0x40c00000U:
return 1'000'000.0f;
case 0x40e00000U:
return 10'000'000.0f;
case 0x41000000U:
return 100'000'000.0f;
case 0x41100000U:
return 1'000'000'000.0f;
case 0x41200000U:
return 10'000'000'000.0f;
}
}
auto rr = exp_b_range_reduc<Exp10Base>(x);
using fputil::multiply_add;
double lo2 = rr.lo * rr.lo;
double c0 = multiply_add(rr.lo, Exp10Base::COEFFS[0], 1.0);
double c1 = multiply_add(rr.lo, Exp10Base::COEFFS[2], Exp10Base::COEFFS[1]);
double c2 = multiply_add(rr.lo, Exp10Base::COEFFS[4], Exp10Base::COEFFS[3]);
double p = multiply_add(lo2, c2, c1);
return static_cast<float>(multiply_add(p, lo2 * rr.mh, c0 * rr.mh));
}
}
}
#endif