[libc-commits] [libc] [llvm] [libc][math][c23] Add exp10bf16 math function (PR #193299)
via libc-commits
libc-commits at lists.llvm.org
Mon May 4 02:14:05 PDT 2026
================
@@ -0,0 +1,147 @@
+//===-- Implementation header for exp10bf16 ---------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP10BF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP10BF16_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/optimization.h"
+
+// This is an algorithm for exp10(x) in bfloat16 which is correctly rounded for
+// all rounding modes, based on the implementation of exp10bf16(x)
+// from the RLIBM project at: https://people.cs.rutgers.edu/~sn349/rlibm
+
+// Step 1 - Range reduction of edge cases:
+// Find the largest value x for which exp10bf16(x) = +0.0
+// x < log10(min subnormal bfloat16)
+// Find the smallest value x for which exp10bf16(x) = +INF
+// x > log10(max normal bfloat16)
+
+// Step 2 - Range reduction to subnormal range:
+// exp10(x) = exp2(x * log2(10)) and further decompose x * log2(10) into
+// sum of two parts - closest integer i and a fraction f
+// exp10(x) = exp2(x * log2(10)) = exp2(i + f) = exp2(i) * exp2(f)
+
+// Step 4 - Polynomial approximation:
+// Approximate the range reduced function exp2(f) on a domain (-0.5, 0.5)
+// using a fourth degree polynomial P
+// Generated by Sollya with the following command:
+// > display = hexadecimal;
+// > exp2 = 2^x;
+// > I = [-0.5, 0.5];
+// > P = fpminimax(exp2, 4, [|1, SG...|], I);
+// > E = infnorm(exp2 - P, I);
+
+// Step 4 - Output compensation:
+// exp10(x) = exp2(i) * P(f)
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+
+// Generated by Sollya with the following command:
+// round(log2(10), SG, RN);
+LIBC_INLINE_VAR constexpr float LOG2F_10 = 0x1.a934fp1;
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+constexpr fputil::ExceptValues<bfloat16, 4> EXP10BF16_EXCEPTS{
+ {// {inputs, RZ output, RU offset, RD offset, RN offset}
+ // x = -0x1.6ep-7, exp10bf16(x) = 0x1.f2p-1 (RN)
+ {0xBC37U, 0x3F79U, 1U, 0U, 0U},
+ // x = -0x1.2ap-6, exp10bf16(x) = 0x1.eap-1 (RN)
+ {0xBC95U, 0x3F75U, 1U, 0U, 0U},
+ // x = -0x1.74p-3, exp10bf16(x) = 0x1.5p-1 (RN)
+ {0xBE3AU, 0x3F28U, 1U, 0U, 0U},
+ // x = -0x1.44p-1, exp10bf16(x) = 0x1.dcp-3 (RN)
+ {0xBF22U, 0x3E6EU, 1U, 0U, 0U}}};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+LIBC_INLINE constexpr bfloat16 exp10bf16(bfloat16 x) {
+ using FPBits = typename fputil::FPBits<bfloat16>;
+ FPBits x_bits(x);
+
+ uint16_t x_u = x_bits.uintval();
+
+ // special case where exp10bf16(NaN) = NaN
+ if (LIBC_UNLIKELY(x_bits.is_nan())) {
+ if (x_bits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ return x;
+ }
+
+ // exp10bf16(x) = +0.0
+ if (x_bits.is_neg() && x_u >= 0xc222U) { // x <= -0x1.44p+5
+ return FPBits::zero().get_val();
+ }
+
+ // exp10bf16(x) = +INF
+ if (x_bits.is_pos() && x_u >= 0x421bU) { // x >= 0x1.36p+5
+ if (x_bits.is_inf()) {
+ return FPBits::inf().get_val();
----------------
ProfessionalMenace wrote:
Thank you for your feedback! Fixed
https://github.com/llvm/llvm-project/pull/193299
More information about the libc-commits
mailing list