[libc-commits] [libc] [llvm] [libc][math] Implement double-precision acosh (PR #199953)

via libc-commits libc-commits at lists.llvm.org
Sun May 31 02:14:29 PDT 2026


================
@@ -0,0 +1,149 @@
+//===-- Implementation header for acosh -------------------------*- 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_ACOSH_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ACOSH_H
+
+#include "log1p.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/multiply_add.h"
+#include "src/__support/FPUtil/sqrt.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+#include "src/__support/macros/properties/cpu_features.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+// Compute log1p(u_hi + u_lo) using log1p's step-1 range reduction and
+// polynomial, with the Float128 accurate path for correct rounding.
+LIBC_INLINE double acosh_log1p_dd(double u_hi, double u_lo) {
+  using FPBits_t = fputil::FPBits<double>;
+  using namespace log1p_internal;
+  using namespace common_constants_internal;
+
+  constexpr int EXP_BIAS = FPBits_t::EXP_BIAS;
+  constexpr int FRACTION_LEN = FPBits_t::FRACTION_LEN;
+
+  // Knuth's 2Sum (exact_add<false>) is correct for all rounding modes.
+  fputil::DoubleDouble x_dd = fputil::exact_add<false>(u_hi, 1.0);
+  x_dd.lo += u_lo;
+
+  // Step-1 range reduction (identical to log1p's fast path).
+  FPBits_t xhi_bits(x_dd.hi);
+  uint64_t xhi_frac = xhi_bits.get_mantissa();
+  uint64_t xdd_u = xhi_bits.uintval();
+
+  int idx = static_cast<int>((xhi_frac + (1ULL << (FRACTION_LEN - 8))) >>
+                             (FRACTION_LEN - 7));
+  int x_e = xhi_bits.get_exponent() + (idx >> 7);
+
+  int64_t s_u = static_cast<int64_t>(xdd_u & FPBits_t::EXP_MASK) -
+                (static_cast<int64_t>(EXP_BIAS) << FRACTION_LEN);
+
+  uint64_t m_hi_bits = FPBits_t::one().uintval() | xhi_frac;
+  uint64_t m_lo_bits =
+      FPBits_t(x_dd.lo).abs().get_val() > x_dd.hi * 0x1.0p-127
+          ? static_cast<uint64_t>(cpp::bit_cast<int64_t>(x_dd.lo) - s_u)
+          : 0;
+
+  fputil::DoubleDouble m_dd{FPBits_t(m_lo_bits).get_val(),
+                            FPBits_t(m_hi_bits).get_val()};
+
+  double r = R1[idx];
+  fputil::DoubleDouble v_lo_p = fputil::exact_mult(m_dd.lo, r);
+  double v_hi_p;
+#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
+  v_hi_p = fputil::multiply_add(r, m_dd.hi, -1.0);
+#else
+  double c = FPBits_t((static_cast<uint64_t>(idx) << (FRACTION_LEN - 7)) +
+                      uint64_t(0x3FF0'0000'0000'0000ULL))
+                 .get_val();
+  v_hi_p = fputil::multiply_add(r, m_dd.hi - c, RCM1[idx]);
+#endif
+
+  fputil::DoubleDouble v_dd_red = fputil::exact_add(v_hi_p, v_lo_p.hi);
+  v_dd_red.lo += v_lo_p.lo;
+
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  // Fast path: polynomial only (no correct-rounding guarantee).
+  double e_x = static_cast<double>(x_e);
+  double hi = fputil::multiply_add(e_x, LOG_2_HI, LOG_R1_DD[idx].hi);
+  double lo = fputil::multiply_add(e_x, LOG_2_LO, LOG_R1_DD[idx].lo);
+  fputil::DoubleDouble r1 = fputil::exact_add(hi, v_dd_red.hi);
+  double v_sq = v_dd_red.hi * v_dd_red.hi;
+  double p0 = fputil::multiply_add(v_dd_red.hi, P_COEFFS[1], P_COEFFS[0]);
+  double p1 = fputil::multiply_add(v_dd_red.hi, P_COEFFS[3], P_COEFFS[2]);
+  double p2 = fputil::multiply_add(v_dd_red.hi, P_COEFFS[5], P_COEFFS[4]);
+  double p = fputil::polyeval(v_sq, (v_dd_red.lo + r1.lo) + lo, p0, p1, p2);
+  return r1.hi + p;
+#else
+  // Always use the Float128 accurate path for correct rounding.
+  // The Ziv fast-path is not used here because for some large-x inputs
+  // err << ULP(result), so the Ziv test always passes even when the
+  // polynomial is 1 ULP off.
+  return log1p_accurate(x_e, idx, v_dd_red);
+#endif
+}
+
+LIBC_INLINE double acosh(double x) {
+  using FPBits = fputil::FPBits<double>;
+  using DoubleDouble = fputil::DoubleDouble;
----------------
Sukumarsawant wrote:

I was talking about alias 'DoubleDouble' since it was used in one and not in other , not about FPBits . Also are you using any AI in this @iamaayushrivastava; including responses?

https://github.com/llvm/llvm-project/pull/199953


More information about the libc-commits mailing list