[libc-commits] [libc] [libc][math] Reduce memory usage for single precision inverse hyperbolic functions for LIBC_MATH_HAS_SMALL_TABLES option. (PR #188110)
via libc-commits
libc-commits at lists.llvm.org
Mon Mar 23 12:53:41 PDT 2026
https://github.com/lntue created https://github.com/llvm/llvm-project/pull/188110
None
>From 9ff7708c79c062de76f936a49a219b1042d58542 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Mon, 23 Mar 2026 19:46:51 +0000
Subject: [PATCH] [libc][math] Reduce memory usage for single precision inverse
hyperbolic functions for LIBC_MATH_HAS_SMALL_TABLES option.
---
libc/src/__support/math/acoshf_utils.h | 51 +++++++++++++++++++++++++-
libc/test/src/math/acoshf_test.cpp | 2 +-
libc/test/src/math/asinhf_test.cpp | 4 +-
libc/test/src/math/atanhf_test.cpp | 11 +++++-
4 files changed, 62 insertions(+), 6 deletions(-)
diff --git a/libc/src/__support/math/acoshf_utils.h b/libc/src/__support/math/acoshf_utils.h
index a0002f404a19f..dc6fd9af8218e 100644
--- a/libc/src/__support/math/acoshf_utils.h
+++ b/libc/src/__support/math/acoshf_utils.h
@@ -13,12 +13,59 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/macros/optimization.h"
namespace LIBC_NAMESPACE_DECL {
namespace acoshf_internal {
-// x should be positive, normal finite value
+// Compute log(|x|), use for float functions, so the error requirements are not
+// as strict as for double precision, and x is assumed to be normal.
+
+#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \
+ defined(LIBC_MATH_HAS_SMALL_TABLES)
+
+LIBC_INLINE double log_eval(double x) {
+ using FPBits = fputil::FPBits<double>;
+ FPBits x_bits(x);
+ uint64_t x_u = x_bits.uintval();
+ // Extract exponent and remove sign bit.
+ double ex = static_cast<double>(
+ (static_cast<int>(x_u >> FPBits::FRACTION_LEN) & 0x7ff) -
+ FPBits::EXP_BIAS);
+ // Reduce to 1.m
+ double x_r =
+ FPBits((x_u & FPBits::FRACTION_MASK) | FPBits::one().uintval()).get_val();
+ // x_r = 1 + dx
+ double dx = x_r - 1.0;
+ // Minimax polynomial of log(1 + x) generated by Sollya with:
+ // > P = fpminimax(log(1 + x)/x, 8, [|1, D...|], [0, 1]);
+ // > dirtyinfnorm((log(1 + x) - x*P)/log(1 + x), [0, 1]);
+ // 0x1.2d5f0a5f66124e3afefa7a66251d1530e07301ed8p-25
+ constexpr double COEFFS[8] = {
+ -0x1.ffff09a15a555p-2, 0x1.55350257eb492p-2, -0x1.fd0649c8116b3p-3,
+ 0x1.8814186a6a587p-3, -0x1.194a9c269ae3p-3, 0x1.4389c5fa07e93p-4,
+ -0x1.ea7bb4f18dbccp-6, 0x1.5d864e41667eep-8,
+ };
+ constexpr double LOG_2 = 0x1.62e42fefa39efp-1;
+
+ double dx2 = dx * dx;
+ double c0 = fputil::multiply_add(dx, COEFFS[1], COEFFS[0]);
+ double c1 = fputil::multiply_add(dx, COEFFS[3], COEFFS[2]);
+ double c2 = fputil::multiply_add(dx, COEFFS[5], COEFFS[4]);
+ double c3 = fputil::multiply_add(dx, COEFFS[7], COEFFS[6]);
+ double dx4 = dx2 * dx2;
+ double d0 = fputil::multiply_add(dx2, c1, c0);
+ double d1 = fputil::multiply_add(dx2, c3, c2);
+ double p = fputil::multiply_add(dx4, d1, d0);
+
+ double r_hi = fputil::multiply_add(ex, LOG_2, dx);
+ double r = fputil::multiply_add(dx2, p, r_hi);
+ return r;
+}
+
+#else // Accurate evaluation.
+
LIBC_INLINE double log_eval(double x) {
// For x = 2^ex * (1 + mx)
// log(x) = ex * log(2) + log(1 + mx)
@@ -53,6 +100,8 @@ LIBC_INLINE double log_eval(double x) {
return result;
}
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS && LIBC_MATH_HAS_SMALL_TABLES
+
} // namespace acoshf_internal
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/math/acoshf_test.cpp b/libc/test/src/math/acoshf_test.cpp
index a0e9b390b58de..d846e484a3d6e 100644
--- a/libc/test/src/math/acoshf_test.cpp
+++ b/libc/test/src/math/acoshf_test.cpp
@@ -51,7 +51,7 @@ TEST_F(LlvmLibcAcoshfTest, InFloatRange) {
if (FPBits(v).is_nan() || FPBits(v).is_inf())
continue;
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acosh, x,
- LIBC_NAMESPACE::acoshf(x), 0.5);
+ LIBC_NAMESPACE::acoshf(x), TOLERANCE + 0.5);
}
}
diff --git a/libc/test/src/math/asinhf_test.cpp b/libc/test/src/math/asinhf_test.cpp
index 9d9c042208d28..c3c43eb931c0c 100644
--- a/libc/test/src/math/asinhf_test.cpp
+++ b/libc/test/src/math/asinhf_test.cpp
@@ -50,9 +50,9 @@ TEST_F(LlvmLibcAsinhfTest, InFloatRange) {
if (FPBits(v).is_nan() || FPBits(v).is_inf())
continue;
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinh, x,
- LIBC_NAMESPACE::asinhf(x), 0.5);
+ LIBC_NAMESPACE::asinhf(x), TOLERANCE + 0.5);
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinh, -x,
- LIBC_NAMESPACE::asinhf(-x), 0.5);
+ LIBC_NAMESPACE::asinhf(-x), TOLERANCE + 0.5);
}
}
diff --git a/libc/test/src/math/atanhf_test.cpp b/libc/test/src/math/atanhf_test.cpp
index 43bde8c5cb0a8..87391383752be 100644
--- a/libc/test/src/math/atanhf_test.cpp
+++ b/libc/test/src/math/atanhf_test.cpp
@@ -10,11 +10,18 @@
#include "hdr/math_macros.h"
#include "hdr/stdint_proxy.h"
#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/optimization.h"
#include "src/math/atanhf.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+#define TOLERANCE 1
+#else
+#define TOLERANCE 0
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest<float>;
using LIBC_NAMESPACE::Sign;
@@ -99,9 +106,9 @@ TEST_F(LlvmLibcAtanhfTest, InFloatRange) {
for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
float x = FPBits(v).get_val();
ASSERT_MPFR_MATCH(mpfr::Operation::Atanh, x, LIBC_NAMESPACE::atanhf(x),
- 0.5);
+ TOLERANCE + 0.5);
ASSERT_MPFR_MATCH(mpfr::Operation::Atanh, -x, LIBC_NAMESPACE::atanhf(-x),
- 0.5);
+ TOLERANCE + 0.5);
}
}
More information about the libc-commits
mailing list