#include "src/math/log1pf.h"
#include "common_constants.h"
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FMA.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/common.h"
namespace __llvm_libc {
namespace internal {
static inline float log(double x) {
constexpr double LOG_2 = 0x1.62e42fefa39efp-1;
using FPBits = typename fputil::FPBits<double>;
FPBits xbits(x);
if (xbits.is_zero()) {
return static_cast<float>(fputil::FPBits<float>::neg_inf());
}
if (xbits.uintval() > FPBits::MAX_NORMAL) {
if (xbits.get_sign() && !xbits.is_nan()) {
return fputil::FPBits<float>::build_nan(
1 << (fputil::MantissaWidth<float>::VALUE - 1));
}
return static_cast<float>(x);
}
double m = static_cast<double>(xbits.get_exponent());
xbits.set_unbiased_exponent(0x3FF);
int f_index =
xbits.get_mantissa() >> 45;
FPBits f = xbits;
f.bits &= ~0x0000'1FFF'FFFF'FFFFULL;
double d = static_cast<double>(xbits) - static_cast<double>(f);
d *= ONE_OVER_F[f_index];
double extra_factor = fputil::multiply_add(m, LOG_2, LOG_F[f_index]);
double r = fputil::polyeval(d, extra_factor, 0x1.fffffffffffacp-1,
-0x1.fffffffef9cb2p-2, 0x1.5555513bc679ap-2,
-0x1.fff4805ea441p-3, 0x1.930180dbde91ap-3);
return static_cast<float>(r);
}
}
LLVM_LIBC_FUNCTION(float, log1pf, (float x)) {
using FPBits = typename fputil::FPBits<float>;
FPBits xbits(x);
double xd = static_cast<double>(x);
if (xbits.get_exponent() >= -8) {
switch (xbits.uintval()) {
case 0x3b9315c8U:
if (fputil::get_round() != FE_UPWARD)
return 0x1.25830cp-8f;
break;
case 0x3c6eb7afU:
if (fputil::get_round() == FE_UPWARD)
return 0x1.d9fd86p-7f;
return 0x1.d9fd84p-7f;
case 0x41078febU:
if (fputil::get_round() != FE_UPWARD)
return 0x1.1fcbcep+1f;
break;
case 0x5cd69e88U:
if (fputil::get_round() != FE_UPWARD)
return 0x1.45c146p+5f;
break;
case 0x65d890d3U:
if (fputil::get_round() == FE_TONEAREST)
return 0x1.a9a3f2p+5f;
break;
case 0x6f31a8ecU:
if (fputil::get_round() == FE_TONEAREST)
return 0x1.08b512p+6f;
break;
case 0x7a17f30aU:
if (fputil::get_round() != FE_UPWARD)
return 0x1.451436p+6f;
break;
case 0xbc4d092cU:
if (fputil::get_round() == FE_TONEAREST)
return -0x1.9ca8bep-7f;
break;
case 0xbc657728U:
if (fputil::get_round() != FE_DOWNWARD)
return -0x1.ce2cccp-7f;
break;
case 0xbd1d20afU:
int round_mode = fputil::get_round();
if (round_mode == FE_UPWARD || round_mode == FE_TOWARDZERO)
return -0x1.40711p-5f;
return -0x1.407112p-5f;
}
return internal::log(xd + 1.0);
}
switch (xbits.uintval()) {
case 0x35400003U:
if (fputil::get_round() == FE_TONEAREST)
return 0x1.7ffffep-21f;
break;
case 0x3710001bU:
if (fputil::get_round() == FE_TONEAREST)
return 0x1.1fffe6p-17f;
break;
case 0xb53ffffdU:
if (fputil::get_round() != FE_DOWNWARD)
return -0x1.800002p-21f;
break;
case 0xb70fffe5U:
if (fputil::get_round() != FE_DOWNWARD)
return -0x1.20001ap-17f;
break;
case 0xbb0ec8c4U:
if (fputil::get_round() == FE_TONEAREST)
return -0x1.1de14ap-9f;
break;
}
double r;
r = fputil::polyeval(xd, -0x1p-1, 0x1.5555555515551p-2, -0x1.ffffffff82bdap-3,
0x1.999b33348d3aep-3, -0x1.5556cae3adcc3p-3);
return static_cast<float>(fputil::multiply_add(r, xd * xd, xd));
}
}