[libc-commits] [libc] [libc][math] Integer-only, statically rounded implementation of expf (PR #209406)
via libc-commits
libc-commits at lists.llvm.org
Mon Aug 17 21:07:25 PDT 2026
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?=,=?utf-8?q?Hoàng_Minh_Thiên?=,
=?utf-8?q?Hoàng_Minh_Thiên?Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/209406 at github.com>
================
@@ -0,0 +1,252 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// This file contains the statically rounded, integer-only implementation of
+/// expf(x)
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_INTEGER_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_INTEGER_EVAL_H
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/frac64.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/math/check/exp_exceptions.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace shared {
+
+namespace math {
+
+namespace static_rounding {
+
+// print(2+round(1/log(2), 64, RN));
+// LSB(INV_LN2) = 2^-63
+LIBC_INLINE_VAR constexpr Frac64 INV_LN2 = Frac64(0xb8aa'3b29'5c17'f0bc);
+
+// 64-bit polynomial approximation of 2^x coefficients generated with Sollya:
+// > P = fpminimax(2^x, 11, [|1, 64...|], [0, 1], absolute, fixed);
+// Store the fractional part of the coefficients below
+// > dirtyinfnorm(2^x - P(x), [0, 1]);
+// 0x1.6238...p-58
+// LSB(EXPF_COEFFS[i]) = 2^-64
+LIBC_INLINE_VAR constexpr Frac64 EXPF_COEFFS[] = {
+ Frac64(0xb172'17f7'd1cf'b7cf), // x
+ Frac64(0x3d7f'7bff'057d'4a5e), // x^2
+ Frac64(0x0e35'846b'8363'9484), // x^3
+ Frac64(0x0276'556d'ec97'dcd4), // x^4
+ Frac64(0x0057'61ff'dc04'c7ff), // x^5
+ Frac64(0x000a'1847'b6e7'92ec), // x^6
+ Frac64(0x0000'ffe8'14e5'7033), // x^7
+ Frac64(0x0000'1628'b6e9'70c8), // x^8
+ Frac64(0x0000'01b8'8ce7'4088), // x^9
+ Frac64(0x0000'001c'18d5'cb29), // x^10
+ Frac64(0x0000'0002'b43f'4490), // x^11
+};
+
+// Statically rounded, no except implementation of expf using integer-only
+// arithmetic.
+LIBC_INLINE float expf(float x, int rounding) {
+ using FPBits = typename fputil::FPBits<float>;
+ using FPBounds = LIBC_NAMESPACE::math::check::exp_internal::Bounds<float>;
+ FPBits xbits(x);
+
+ bool is_neg = xbits.is_neg();
+ uint32_t x_val = xbits.uintval();
+ uint32_t x_val_abs = x_val & 0x7fff'ffffU;
+
+ // When |x| >= smallest value that will cause overflow, |x| <= 2^-25, or x is
+ // NaN
+ if (LIBC_UNLIKELY(x_val_abs >= FPBounds::UPPER_BITS ||
+ x_val_abs <= 0x3300'0000U)) {
+ // |x| <= 2^-25
+ if (x_val_abs <= 0x3300'0000U) {
+#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+ return 1.0f;
+#else
+ if (x_val_abs == 0)
+ return 1.0f;
+
+ if (rounding == FE_UPWARD && !is_neg)
+ return 0x1.000002p0f;
+
+ if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && is_neg)
+ return 0x1.fffffep-1f;
+
+ return 1.0f;
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+ }
+
+ if (xbits.is_nan()) {
+ // Per conversation with lntue, we don't need to raise exception here,
+ // as we're assuming no FPUs/fenv in this kind of environment
+ if (xbits.is_signaling_nan()) {
+ // silencing
+ return FPBits::quiet_nan().get_val();
+ }
+
+ // quiet NaN
+ return x;
+ }
+
+ // e^-inf = 0
+ // e^+inf = +inf
+ if (xbits.is_inf()) {
+ return is_neg ? 0.0f : FPBits::inf().get_val();
+ }
+
+ // Large finite positive
+ if (!is_neg) {
+ if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
----------------
lntue wrote:
switch for `LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY`.
https://github.com/llvm/llvm-project/pull/209406
More information about the libc-commits
mailing list