//===-- Double-precision 2^x function -------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #include "src/math/exp2.h" #include "common_constants.h" // Lookup tables EXP2_MID1 and EXP_M2. #include "explogxf.h" // ziv_test_denorm. #include "src/__support/CPP/bit.h" #include "src/__support/CPP/optional.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/double_double.h" #include "src/__support/FPUtil/dyadic_float.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" #include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/FPUtil/triple_double.h" #include "src/__support/common.h" #include "src/__support/integer_literals.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY namespace LIBC_NAMESPACE_DECL { DoubleDouble; TripleDouble; Float128; operator""_u128; // Error bounds: // Errors when using double precision. #ifdef LIBC_TARGET_CPU_HAS_FMA constexpr double ERR_D = 0x1.0p-63; #else constexpr double ERR_D = …; #endif // LIBC_TARGET_CPU_HAS_FMA // Errors when using double-double precision. constexpr double ERR_DD = …; namespace { // Polynomial approximations with double precision. Generated by Sollya with: // > P = fpminimax((2^x - 1)/x, 3, [|D...|], [-2^-13 - 2^-30, 2^-13 + 2^-30]); // > P; // Error bounds: // | output - (2^dx - 1) / dx | < 1.5 * 2^-52. LIBC_INLINE double poly_approx_d(double dx) { … } // Polynomial approximation with double-double precision. Generated by Solya // with: // > P = fpminimax((2^x - 1)/x, 5, [|DD...|], [-2^-13 - 2^-30, 2^-13 + 2^-30]); // Error bounds: // | output - 2^(dx) | < 2^-101 DoubleDouble poly_approx_dd(const DoubleDouble &dx) { … } // Polynomial approximation with 128-bit precision: // Return exp(dx) ~ 1 + a0 * dx + a1 * dx^2 + ... + a6 * dx^7 // For |dx| < 2^-13 + 2^-30: // | output - exp(dx) | < 2^-126. Float128 poly_approx_f128(const Float128 &dx) { … } // Compute 2^(x) using 128-bit precision. // TODO(lntue): investigate triple-double precision implementation for this // step. Float128 exp2_f128(double x, int hi, int idx1, int idx2) { … } // Compute 2^x with double-double precision. DoubleDouble exp2_double_double(double x, const DoubleDouble &exp_mid) { … } // When output is denormal. double exp2_denorm(double x) { … } // Check for exceptional cases when: // * log2(1 - 2^-54) < x < log2(1 + 2^-53) // * x >= 1024 // * x <= -1022 // * x is inf or nan double set_exceptional(double x) { … } } // namespace LLVM_LIBC_FUNCTION(double, exp2, (double x)) { … } } // namespace LIBC_NAMESPACE_DECL