blob: 3f78041f9dea43422c08675fe23c6fb7a06a9b92 [file]
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Double-precision evaluation implementation for powf(x, y).
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_POWF_DOUBLE_EVAL_H
#define LLVM_LIBC_SRC___SUPPORT_MATH_POWF_DOUBLE_EVAL_H
#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/double_double.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/nearest_integer.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
#include "src/__support/macros/properties/cpu_features.h"
#include "src/__support/math/common_constants.h"
#include "src/__support/math/exp_constants.h"
#include "src/__support/math/powf_utils.h"
namespace LIBC_NAMESPACE_DECL {
namespace math {
namespace double_eval {
namespace powf_internal = LIBC_NAMESPACE::math::powf_internal;
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
// Accurate evaluation in DoubleDouble precision when Ziv's test fails.
LIBC_INLINE double powf_accurate(float x, float y, double e_x, uint64_t sign) {
using FloatBits = fputil::FPBits<float>;
using DoubleBits = fputil::FPBits<double>;
using fputil::DoubleDouble;
uint32_t x_u = FloatBits(x).uintval();
uint32_t x_mant = x_u & FloatBits::FRACTION_MASK;
int idx_x = static_cast<int>(x_mant >> (FloatBits::FRACTION_LEN - 7));
// Append hidden bit.
float m_x = cpp::bit_cast<float>(x_mant | 0x3f80'0000);
double dx = fputil::multiply_add(
static_cast<double>(m_x),
static_cast<double>(common_constants_internal::R[idx_x]), -1.0);
// Degree-11 minimax polynomial for log2(1 + x)/x on [-2^-8, 2^-7] in
// double-double, generated by Sollya with:
// > display = hexadecimal;
// > prec = 256;
// > P = fpminimax(log2(1 + x)/x, 11, [|DD...|], [-2^(-8), 2^(-7)]);
// > for i from 0 to 11 do {
// c = coeff(P, i);
// hi = round(c, D, RN);
// lo = round(c - hi, D, RN);
// print("{", lo, ", ", hi, "},");
// };
// > dirtyinfnorm((log2(1 + x) - x * P) / x, [-2^(-8), 2^(-7)]);
// 0x1.c598...p-104 < 2^-103.
constexpr DoubleDouble LOG2_COEFFS[] = {
{0x1.777d0ffda0d34p-56, 0x1.71547652b82fep0},
{-0x1.777d0ffd88ca8p-57, -0x1.71547652b82fep-1},
{0x1.d27f052d9d41dp-56, 0x1.ec709dc3a03fdp-2},
{-0x1.777f259c6c0ap-58, -0x1.71547652b82fep-2},
{0x1.e5c055599afdbp-56, 0x1.2776c50ef9bfep-2},
{0x1.e923056eef156p-58, -0x1.ec709dc3a03fdp-3},
{0x1.1f24e26b5ad0dp-57, 0x1.a61762a7add76p-3},
{0x1.16d9b5013b55ep-58, -0x1.71547652bf304p-3},
{-0x1.1551148c3d1d8p-57, 0x1.484b13f00425ep-3},
{-0x1.a1cf327c6703p-60, -0x1.2776ca937f335p-3},
{-0x1.d24f6254c2e6ap-57, 0x1.0c9211efe6d7ep-3},
{0x1.a81cff2946d7cp-59, -0x1.e1f45baaf7f1dp-4},
};
// Evaluate P(dx) ~ log2(1 + dx) / dx using Horner's scheme.
DoubleDouble p = LOG2_COEFFS[11];
for (int i = 10; i >= 0; --i)
p = fputil::add(LOG2_COEFFS[i], fputil::quick_mult(dx, p));
// log2(1 + dx) = dx * P(dx) in DoubleDouble.
DoubleDouble log2_1p = fputil::quick_mult(dx, p);
// -log2(r) is represented in TripleDouble as {lo, mid, hi}.
// We decompose log2(x) = e_x - log2(r) + log2(1 + dx) into:
// log2(x) = (e_x + hi) + (log2_1p + mid + lo)
// = (e_x + hi) + log2_tail.
// The lower part log2_tail accumulates log2_1p, mid, and lo in DoubleDouble:
DoubleDouble log2_tail =
fputil::add<false>(log2_1p, powf_internal::LOG2_R_TD[idx_x].mid);
log2_tail = fputil::add<false>(log2_tail, powf_internal::LOG2_R_TD[idx_x].lo);
// Range reduction for 2^(y * log2(x)):
// Scale by 2^6 = 64 to use the 64-entry EXP2_MID1 table:
// 64 * y * log2(x) = y6 * (e_x + hi) + y6 * log2_tail.
//
// Since e_x + hi has at most 8 + 20 = 28 bits of precision and y has 24 bits,
// the product y6 * (e_x + hi) has at most 28 + 24 = 52 bits, making y6_hi
// exact in double precision.
constexpr double SCALE = 0x1.0p6;
double y6 = static_cast<double>(y) * SCALE;
DoubleDouble prod = fputil::quick_mult(y6, log2_tail);
double e_x_hi = e_x + powf_internal::LOG2_R_TD[idx_x].hi;
DoubleDouble y6_hi = fputil::exact_mult(y6, e_x_hi);
// hm = round(64 * y * log2(x)) is the nearest integer index.
double hm_d = y6_hi.hi + prod.hi;
double hm = fputil::nearest_integer(hm_d);
// lo6 = 64 * y * log2(x) - hm = (y6_hi - hm) + prod:
DoubleDouble lo6_hi = fputil::exact_add<false>(y6_hi.hi, -hm);
lo6_hi.lo += y6_hi.lo;
DoubleDouble lo6 = fputil::add<false>(prod, lo6_hi);
// lo = lo6 / 64, with |lo| <= 2^-7.
DoubleDouble lo = fputil::quick_mult(0x1.0p-6, lo6);
int64_t hm_i = static_cast<int64_t>(hm);
int idx_y = static_cast<int>(hm_i & 0x3f);
int hi = static_cast<int>(hm_i >> 6);
int64_t exp_hi_i = static_cast<int64_t>(static_cast<uint64_t>(hi)
<< DoubleBits::FRACTION_LEN);
// Degree-8 minimax polynomial for (2^x - 1)/x on [-2^-7, 2^-7] in
// double-double, generated by Sollya with:
// > display = hexadecimal;
// > prec = 256;
// > P = fpminimax((2^x - 1)/x, 8, [|DD...|], [-2^(-7), 2^(-7)]);
// > for i from 0 to 8 do {
// c = coeff(P, i);
// hi = round(c, D, RN);
// lo = round(c - hi, D, RN);
// print("{", lo, ", ", hi, "},");
// };
// > dirtyinfnorm((2^x - (1 + x * P)) / (2^x), [-2^(-7), 2^(-7)]);
// 0x1.e62d...p-106 < 2^-105.
constexpr DoubleDouble EXP2_COEFFS_DD[] = {
{0x1.abc9e3b39803ep-56, 0x1.62e42fefa39efp-1},
{-0x1.5e43a54066432p-57, 0x1.ebfbdff82c58fp-3},
{-0x1.d331626e9fe04p-59, 0x1.c6b08d704a0cp-5},
{0x1.4f492022eeb74p-62, 0x1.3b2ab6fba4e77p-7},
{0x1.035733b00abdp-66, 0x1.5d87fe78a6731p-10},
{0x1.9e4f81ec951dep-68, 0x1.430912f86c123p-13},
{0x1.7be627c299948p-74, 0x1.ffcbfc588b997p-17},
{-0x1.c8a006d5b39acp-74, 0x1.62c03345a64f6p-20},
{-0x1.fd14495e4b96p-81, 0x1.b5253eef8c0a9p-24},
};
DoubleDouble exp2_p = EXP2_COEFFS_DD[8];
for (int i = 7; i >= 0; --i)
exp2_p = fputil::add(EXP2_COEFFS_DD[i], fputil::quick_mult(lo, exp2_p));
DoubleDouble p_lo = fputil::quick_mult(lo, exp2_p);
DoubleDouble exp2_lo = fputil::exact_add(1.0, p_lo.hi);
exp2_lo.lo += p_lo.lo;
DoubleDouble exp2_hi_mid_dd;
exp2_hi_mid_dd.hi = cpp::bit_cast<double>(
exp_hi_i + cpp::bit_cast<int64_t>(EXP2_MID1[idx_y].hi) + sign);
exp2_hi_mid_dd.lo =
(idx_y != 0)
? cpp::bit_cast<double>(
exp_hi_i + cpp::bit_cast<int64_t>(EXP2_MID1[idx_y].mid) + sign)
: 0.0;
DoubleDouble rr = fputil::quick_mult(exp2_hi_mid_dd, exp2_lo);
DoubleDouble r = fputil::exact_add(rr.hi, rr.lo);
// Round to odd to avoid double rounding when converting to float.
uint64_t r_bits = cpp::bit_cast<uint64_t>(r.hi);
if (LIBC_UNLIKELY(((r_bits & 0x0fff'ffffULL) == 0) && (r.lo != 0.0))) {
if (DoubleBits(r.hi).sign() == DoubleBits(r.lo).sign()) {
++r_bits;
} else if ((r_bits & DoubleBits::FRACTION_MASK) > 0) {
--r_bits;
}
}
return cpp::bit_cast<double>(r_bits);
}
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
#if !defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \
!defined(LIBC_MATH_HAS_SMALL_TABLES)
// Check if x^y is an exact rounding boundary.
// When x^y = exact_m * 2^exact_exp with exact_m <= 2^25:
// - exact_m has at most 26 bits, so it fits in double precision without
// rounding.
// - For single precision, exact_exp is in [-200, 127], well within the normal
// range [-1022, 1023] of double precision.
// We compute exact_d = exact_m * 2^exact_exp in double precision and cast to
// float for the final rounded result.
LIBC_INLINE cpp::optional<float>
check_exact_boundary(float x, float y, uint64_t sign,
Sign out_sign = Sign::POS) {
uint32_t exact_m = 0;
int exact_exp = 0;
if (LIBC_UNLIKELY(powf_internal::is_exact_rounding_boundary(x, y, exact_m,
exact_exp))) {
// Number of bits in exact_m: 2^(l - 1) <= exact_m < 2^l.
int l = 32 - cpp::countl_zero(exact_m);
// Unbiased exponent of exact_m * 2^exact_exp.
int unbiased_exp = exact_exp + l - 1;
if (LIBC_UNLIKELY(unbiased_exp > 127))
return powf_internal::set_overflow(out_sign);
// Below the minimum subnormal float (2^-149).
if (LIBC_UNLIKELY(unbiased_exp < -149)) {
fputil::set_errno_if_required(ERANGE);
fputil::raise_underflow_except_if_required<float>();
}
// Scale factor = sign * 2^exact_exp.
using DoubleBits = fputil::FPBits<double>;
double scale = cpp::bit_cast<double>(
(static_cast<uint64_t>(exact_exp + DoubleBits::EXP_BIAS)
<< DoubleBits::FRACTION_LEN) |
sign);
double exact_d = static_cast<double>(exact_m) * scale;
return static_cast<float>(exact_d);
}
return cpp::nullopt;
}
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS && !LIBC_MATH_HAS_SMALL_TABLES
// Overview of powf(x, y) = x^y computation in double precision:
//
// Let x = 2^(e_x) * m_x > 0. Then:
// x^y = 2^( y * log2(x) )
// = 2^( y * ( e_x + log2(m_x) ) )
// = 2^( k + f )
// = 2^k * 2^f,
// where:
// k = round(y * log2(x)),
// f = y * log2(x) - k.
//
// In particular, k is an integer, and |f| <= 0.5.
// For the final result to fit in single precision:
// -150 <= y * log2(x) <= 128,
// and anything outside that range overflows or underflows.
//
// Fast pass:
// 1. Range reduction for log2(m_x) using a 32-entry lookup table:
// dx = r * m_x - 1 in [-2^-6, 2^-5],
// log2(m_x) = log2(1 + dx) - log2(r),
// where -log2(r) is retrieved from LOG2_R_32[idx_x], and log2(1 + dx)/dx is
// approximated by a degree-6 polynomial in double precision with Estrin's
// scheme.
// 2. Exponent reduction:
// z = y * log2(x),
// k = round(z),
// f = z - k in [-0.5, 0.5].
// 3. 2^f is evaluated using a degree-7 polynomial.
// Absorbing +-ERR into the constant term 1.0 +- ERR of the final FMA allows
// computing the upper and lower bounds for Ziv's rounding test in parallel.
// 4. If upper == lower in single precision, return upper.
// 5. If Ziv's test fails, fall back to check_exact_boundary and powf_accurate
// (DoubleDouble / 128-entry table).
//
// Accurate pass:
// 1. Range reduction using a 128-entry table: -log2(r) = {lo, mid, hi}.
// log2(1 + dx) is evaluated using a degree-11 polynomial in DoubleDouble.
// 2. Decompose: log2(x) = (e_x + hi) + log2_tail, where:
// log2_tail = log2(1 + dx) + mid + lo.
// Because e_x + hi has <= 28 bits of precision and y has 24 bits,
// y * (e_x + hi) is exact in double precision.
// 3. Exponent reduction with 64-entry EXP2_MID1 table and degree-8 polynomial
// in DoubleDouble.
LIBC_INLINE float powf(float x, float y) {
using FloatBits = fputil::FPBits<float>;
using DoubleBits = fputil::FPBits<double>;
using fputil::DoubleDouble;
using namespace common_constants_internal;
FloatBits xbits(x), ybits(y);
uint32_t x_u = xbits.uintval();
uint32_t y_u = ybits.uintval();
uint32_t y_a = ybits.abs().uintval();
// Quick filter for special inputs:
// - x: 0, +-1, 2^k, +-Inf, NaN.
// - y: 0, +-1, +-2, +-0.5, +-Inf, NaN.
if (LIBC_UNLIKELY((x_u & 0x001F'FFFF) == 0 || (y_u & 0x007F'FFFF) == 0)) {
if (auto r = powf_internal::check_special_inputs(x, y);
LIBC_UNLIKELY(r.has_value()))
return r.value();
}
#if !defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \
!defined(LIBC_MATH_HAS_SMALL_TABLES)
float orig_x_abs = xbits.abs().get_val();
float orig_y = y;
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS && !LIBC_MATH_HAS_SMALL_TABLES
int ex = -FloatBits::EXP_BIAS;
uint64_t sign = 0;
// Check for exceptional cases:
// - |y| <= 2^-40 or |y| >= 2^40.
// - x < 0, x is subnormal, zero, Inf, or NaN.
if (LIBC_UNLIKELY(y_a <= powf_internal::Y_LOWER_BOUND ||
y_a >= powf_internal::Y_UPPER_BOUND ||
x_u >= FloatBits::inf().uintval() ||
x_u < FloatBits::min_normal().uintval())) {
if (auto r = powf_internal::check_exceptional_cases(x, y, ex, sign);
LIBC_UNLIKELY(r.has_value()))
return r.value();
}
Sign out_sign = (sign == 0) ? Sign::POS : Sign::NEG;
// x^y = 2^( y * log2(x) ) = 2^( y * ( e_x + log2(m_x) ) )
// Compute log2(x) = e_x + log2(m_x)
x_u = FloatBits(x).uintval();
// Extract exponent field of x.
ex += (x_u >> FloatBits::FRACTION_LEN);
double e_x = static_cast<double>(ex);
uint32_t x_mant = x_u & FloatBits::FRACTION_MASK;
// Top 5 bits of mantissa for 32-entry table lookup.
int idx_x = static_cast<int>(x_mant >> (FloatBits::FRACTION_LEN - 5));
// Embed mantissa into double format: m_x in [1.0, 2.0).
uint64_t m_x_u =
(static_cast<uint64_t>(x_mant) << 29) | 0x3ff0'0000'0000'0000ULL;
double m_x = cpp::bit_cast<double>(m_x_u);
// Range reduction: dx = m_x * r - 1.0 in [-2^-6, 2^-5].
// Since r has <= 7 bits and m_x has 24 bits, m_x * r - 1.0 is exact in
// double.
double dx =
fputil::multiply_add(m_x, powf_internal::R_32_D[idx_x], -1.0); // Exact
// Degree-6 minimax polynomial approximation for log2(1 + dx)/dx on
// [-2^-6, 2^-5]. Generated by Sollya with:
// > display = hexadecimal;
// > p6 = fpminimax(log2(1 + x)/x, 6, [|D...|], [-2^-6, 2^-5]);
// > for i from 0 to 6 do print(round(coeff(p6, i), D, RN), ",");
// > dirtyinfnorm((log2(1 + x) - x * p6) / log2(1 + x), [-2^-6, 2^-5]);
// 0x1.050a...p-47
// > dirtyinfnorm(log2(1 + x) - x * p6, [-2^-6, 2^-5]);
// 0x1.712b...p-52
constexpr double COEFFS[] = {
0x1.71547652b831fp0, -0x1.71547652b2ff5p-1, 0x1.ec709dbd02463p-2,
-0x1.7154787f73adep-2, 0x1.2777b7f57b29fp-2, -0x1.ec55ea50eaba7p-3,
0x1.92c78e7d5a931p-3,
};
// Evaluate P(dx) ~ log2(1 + dx)/dx with Estrin's scheme:
double dx2 = dx * dx;
double lp0 = fputil::multiply_add(dx, COEFFS[1], COEFFS[0]);
double lp1 = fputil::multiply_add(dx, COEFFS[3], COEFFS[2]);
double lp2 = fputil::multiply_add(dx, COEFFS[5], COEFFS[4]);
double dx4 = dx2 * dx2;
double lq0 = fputil::multiply_add(dx2, lp1, lp0);
double lq1 = fputil::multiply_add(dx2, COEFFS[6], lp2);
double p = fputil::multiply_add(dx4, lq1, lq0);
// log2(x) = e_x - log2(r) + dx * P(dx).
double log2_r_ex = powf_internal::LOG2_R_32[idx_x] + e_x;
double s = fputil::multiply_add(dx, p, log2_r_ex);
double y_d = static_cast<double>(y);
double z = y_d * s;
// y * log2(x) = k + f, with k integer and |f| <= 0.5.
double kd = fputil::nearest_integer(z);
int64_t k = static_cast<int64_t>(kd);
double f = fputil::multiply_add(y_d, s, -kd);
// Degree-7 polynomial approximation P(f) ~ (2^f - 1)/f on [-0.5, 0.5]
// Generated by Sollya with:
// > display = hexadecimal;
// > p = fpminimax((2^x - 1)/x, 7, [|D...|], [-0.5, 0.5]);
// > for i from 0 to 7 do print(round(coeff(p, i), D, RN), ",");
// > dirtyinfnorm(2^x - (1 + x * p), [-0.5, 0.5]);
// 0x1.0496...p-39
// > dirtyinfnorm((2^x - (1 + x * p)) / 2^x, [-0.5, 0.5]);
// 0x1.0496...p-39
constexpr double EXP2_COEFFS[] = {
0x1.62e42fef9cdf7p-1, 0x1.ebfbdff85f49p-3, 0x1.c6b08da69c963p-5,
0x1.3b2ab6a0e1172p-7, 0x1.5d87762dfc134p-10, 0x1.43099b4e829a9p-13,
0x1.00c080f7699bep-16, 0x1.62c0108a065d8p-20,
};
// Evaluate P(f) ~ (2^f - 1)/f on [-0.5, 0.5] with Estrin's scheme:
double f2 = f * f;
double f4 = f2 * f2;
double p0 = fputil::multiply_add(f, EXP2_COEFFS[1], EXP2_COEFFS[0]);
double p1 = fputil::multiply_add(f, EXP2_COEFFS[3], EXP2_COEFFS[2]);
double p2 = fputil::multiply_add(f, EXP2_COEFFS[5], EXP2_COEFFS[4]);
double p3 = fputil::multiply_add(f, EXP2_COEFFS[7], EXP2_COEFFS[6]);
double q0 = fputil::multiply_add(f2, p1, p0);
double q1 = fputil::multiply_add(f2, p3, p2);
double poly = fputil::multiply_add(f4, q1, q0);
// Normal range: -125 <= k <= 128.
// (k + 125) as unsigned <= 253 covers all normal outputs.
uint64_t k_u = static_cast<uint64_t>(k + 125);
if (LIBC_LIKELY(k_u <= 253)) {
// Scale by 2^k.
uint64_t exp2_k_i =
(static_cast<uint64_t>(static_cast<int>(k) + DoubleBits::EXP_BIAS)
<< DoubleBits::FRACTION_LEN) |
sign;
double exp2_k = cpp::bit_cast<double>(exp2_k_i);
#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
double pp = fputil::multiply_add(f, poly, 1.0);
double r_d = pp * exp2_k;
return static_cast<float>(r_d);
#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
#ifdef LIBC_TARGET_CPU_HAS_FMA
// Absorbing +-ERR into 1.0 computes both bounds using two parallel FMAs.
constexpr double ERR = 0x1.5p-39;
double pp_hi = fputil::multiply_add(f, poly, 1.0 + ERR);
double pp_lo = fputil::multiply_add(f, poly, 1.0 - ERR);
double r_d = pp_hi * exp2_k;
#else // !LIBC_TARGET_CPU_HAS_FMA
// Without FMA, compute unbiased pp = f * poly + 1.0 directly.
double pp = fputil::multiply_add(f, poly, 1.0);
double r_d = pp * exp2_k;
#endif // LIBC_TARGET_CPU_HAS_FMA
float res = static_cast<float>(r_d);
// Since 2^k is an exact power of 2, testing if the bounds round to the same
// float is equivalent to testing the fully scaled bounds.
#ifdef LIBC_TARGET_CPU_HAS_FMA
float upper = static_cast<float>(pp_hi);
float lower = static_cast<float>(pp_lo);
#else // !LIBC_TARGET_CPU_HAS_FMA
constexpr double ERR = 0x1.5p-39;
float upper = static_cast<float>(pp + ERR);
float lower = static_cast<float>(pp - ERR);
#endif // LIBC_TARGET_CPU_HAS_FMA
if (LIBC_LIKELY(upper == lower))
return res;
// Accurate fallback when Ziv's test fails:
#ifndef LIBC_MATH_HAS_SMALL_TABLES
if (auto r = check_exact_boundary(orig_x_abs, orig_y, sign, out_sign);
LIBC_UNLIKELY(r.has_value()))
return r.value();
#endif // !LIBC_MATH_HAS_SMALL_TABLES
double r_dd = powf_accurate(x, y, e_x, sign);
res = static_cast<float>(r_dd);
if (LIBC_UNLIKELY(FloatBits(res).is_inf()))
return powf_internal::set_overflow(out_sign);
return res;
#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
}
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
// Exceptional path: k > 128 (overflow), k < -155 (underflow), or denormal.
if (k > 128)
return powf_internal::set_overflow(out_sign);
if (k < -155)
return powf_internal::set_underflow(out_sign);
// Denormal and underflow path for -155 <= k <= -126:
#ifndef LIBC_MATH_HAS_SMALL_TABLES
if (auto r = check_exact_boundary(orig_x_abs, orig_y, sign, out_sign);
LIBC_UNLIKELY(r.has_value()))
return r.value();
#endif // !LIBC_MATH_HAS_SMALL_TABLES
int64_t exp2_k_i = (static_cast<uint64_t>(k + DoubleBits::EXP_BIAS)
<< DoubleBits::FRACTION_LEN) |
sign;
double exp2_k = cpp::bit_cast<double>(exp2_k_i);
// Add +-2^(-126 + (53 - 24)) = +-2^-97 to mimic single precision denormal
// rounding in double precision.
// For -155 <= k <= -126, the least significant bit of the double precision
// sum (r_d + denorm_bias) is aligned at 2^(-97 - 52) = 2^-149, matching the
// least significant bit of single precision denormals 2^(-126 - 23) = 2^-149.
// This keeps the values in the double precision normal range while performing
// rounding according to the current rounding mode.
double denorm_bias = cpp::bit_cast<double>(0x39e0'0000'0000'0000ULL | sign);
constexpr double ERR = 0x1.5p-39;
#ifdef LIBC_TARGET_CPU_HAS_FMA
// Absorbing +-ERR into 1.0 computes both bounds using two parallel FMAs.
double pp_hi = fputil::multiply_add(f, poly, 1.0 + ERR);
double pp_lo = fputil::multiply_add(f, poly, 1.0 - ERR);
double u_hi = fputil::multiply_add(pp_hi, exp2_k, denorm_bias);
double u_lo = fputil::multiply_add(pp_lo, exp2_k, denorm_bias);
#else // !LIBC_TARGET_CPU_HAS_FMA
// Without FMA, compute unbiased pp = f * poly + 1.0 directly.
double pp = fputil::multiply_add(f, poly, 1.0);
double r_d = pp * exp2_k;
double err = ERR * r_d;
double u_hi = (r_d + err) + denorm_bias;
double u_lo = (r_d - err) + denorm_bias;
#endif // LIBC_TARGET_CPU_HAS_FMA
if (LIBC_LIKELY(u_hi == u_lo)) {
if (LIBC_UNLIKELY(u_hi == denorm_bias))
return powf_internal::set_underflow(out_sign);
float res = static_cast<float>(u_hi - denorm_bias);
if (LIBC_UNLIKELY(FloatBits(res).is_normal())) {
#ifdef LIBC_TARGET_CPU_HAS_FMA
double pp = fputil::multiply_add(f, poly, 1.0);
#endif // LIBC_TARGET_CPU_HAS_FMA
if (static_cast<float>(pp) < 1.0f)
fputil::raise_underflow_except_if_required<float>();
return res;
}
fputil::set_errno_if_required(ERANGE);
fputil::raise_underflow_except_if_required<float>();
return res;
}
// Ziv's test failed for denormal input, fall back to accurate pass.
double r_dd = powf_accurate(x, y, e_x, sign);
float res = static_cast<float>(r_dd);
if (LIBC_UNLIKELY(FloatBits(res).is_normal())) {
if (static_cast<float>(r_dd * 0x1.0p126) < 1.0f)
fputil::raise_underflow_except_if_required<float>();
return res;
}
fputil::set_errno_if_required(ERANGE);
fputil::raise_underflow_except_if_required<float>();
return res;
#else // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
if (k > 128)
return powf_internal::set_overflow(out_sign);
return powf_internal::set_underflow(out_sign);
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
}
} // namespace double_eval
} // namespace math
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_MATH_POWF_DOUBLE_EVAL_H