| |
| |
| |
| |
| |
| |
| |
|
|
| #include "src/math/atan.h" |
| #include "atan_utils.h" |
| #include "src/__support/FPUtil/FEnvImpl.h" |
| #include "src/__support/FPUtil/FPBits.h" |
| #include "src/__support/FPUtil/double_double.h" |
| #include "src/__support/FPUtil/multiply_add.h" |
| #include "src/__support/FPUtil/nearest_integer.h" |
| #include "src/__support/macros/config.h" |
| #include "src/__support/macros/optimization.h" |
|
|
| namespace LIBC_NAMESPACE_DECL { |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| LLVM_LIBC_FUNCTION(double, atan, (double x)) { |
| using FPBits = fputil::FPBits<double>; |
|
|
| constexpr double IS_NEG[2] = {1.0, -1.0}; |
| constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54, |
| 0x1.921fb54442d18p0}; |
| constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54, |
| -0x1.921fb54442d18p0}; |
|
|
| FPBits xbits(x); |
| bool x_sign = xbits.is_neg(); |
| xbits = xbits.abs(); |
| uint64_t x_abs = xbits.uintval(); |
| int x_exp = |
| static_cast<int>(x_abs >> FPBits::FRACTION_LEN) - FPBits::EXP_BIAS; |
|
|
| |
| if (x_exp < 0) { |
| if (LIBC_UNLIKELY(x_exp < -26)) { |
| #ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS |
| return x; |
| #else |
| if (x == 0.0) |
| return x; |
| |
| return fputil::multiply_add(-0x1.0p-54, x, x); |
| #endif |
| } |
|
|
| double x_d = xbits.get_val(); |
| |
| double k = fputil::nearest_integer(0x1.0p6 * x_d); |
| unsigned idx = static_cast<unsigned>(k); |
| k *= 0x1.0p-6; |
|
|
| |
| DoubleDouble num, den; |
| num.lo = 0.0; |
| num.hi = x_d - k; |
|
|
| |
| den.hi = fputil::multiply_add(x_d, k, 1.0); |
| DoubleDouble prod = fputil::exact_mult(x_d, k); |
| |
| den.lo = ((1.0 - den.hi) + prod.hi) + prod.lo; |
|
|
| |
| DoubleDouble x_r = fputil::div(num, den); |
|
|
| |
| DoubleDouble p = atan_eval(x_r); |
|
|
| |
| |
| #ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS |
| return IS_NEG[x_sign] * (ATAN_I[idx].hi + (p.hi + (p.lo + ATAN_I[idx].lo))); |
| #else |
|
|
| DoubleDouble c0 = fputil::exact_add(ATAN_I[idx].hi, p.hi); |
| double c1 = c0.lo + (ATAN_I[idx].lo + p.lo); |
| double r = IS_NEG[x_sign] * (c0.hi + c1); |
|
|
| return r; |
| #endif |
| } |
|
|
| |
| if (LIBC_UNLIKELY(x_exp >= 53)) { |
| |
| if (xbits.is_nan()) { |
| if (xbits.is_signaling_nan()) { |
| fputil::raise_except_if_required(FE_INVALID); |
| return FPBits::quiet_nan().get_val(); |
| } |
| return x; |
| } |
| |
| |
| if (x_exp >= 53) |
| #ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS |
| return IS_NEG[x_sign] * PI_OVER_2.hi; |
| #else |
| return fputil::multiply_add(IS_NEG[x_sign], PI_OVER_2.hi, |
| IS_NEG[x_sign] * PI_OVER_2.lo); |
| #endif |
| } |
|
|
| double x_d = xbits.get_val(); |
| double y = 1.0 / x_d; |
|
|
| |
| double k = fputil::nearest_integer(0x1.0p6 * y); |
| unsigned idx = static_cast<unsigned>(k); |
| k *= 0x1.0p-6; |
|
|
| |
| DoubleDouble den = fputil::exact_add(x_d, k); |
| |
| DoubleDouble num; |
| num.hi = fputil::multiply_add(-x_d, k, 1.0); |
| DoubleDouble prod = fputil::exact_mult(x_d, k); |
| |
| num.lo = ((1.0 - num.hi) - prod.hi) - prod.lo; |
|
|
| |
| |
| DoubleDouble x_r = fputil::div(num, den); |
|
|
| |
| DoubleDouble p = atan_eval(x_r); |
|
|
| |
| |
| |
| #ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS |
| double lo_part = p.lo + ATAN_I[idx].lo + MPI_OVER_2.lo; |
| return IS_NEG[!x_sign] * (MPI_OVER_2.hi + ATAN_I[idx].hi + (p.hi + lo_part)); |
| #else |
| DoubleDouble c0 = fputil::exact_add(MPI_OVER_2.hi, ATAN_I[idx].hi); |
| DoubleDouble c1 = fputil::exact_add(c0.hi, p.hi); |
| double c2 = c1.lo + (c0.lo + p.lo) + (ATAN_I[idx].lo + MPI_OVER_2.lo); |
|
|
| double r = IS_NEG[!x_sign] * (c1.hi + c2); |
|
|
| return r; |
| #endif |
| } |
|
|
| } |
|
|