[llvm-branch-commits] [libc] [llvm] [libc][math] Implement double precision cosh correctly rounded to all rounding modes. (PR #235181)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Oct 27 22:05:49 PDT 2026
https://github.com/lntue updated https://github.com/llvm/llvm-project/pull/235181
>From d09ce907988c029c97f5ed0e272f7c3b9f1c69bf Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Sat, 24 Oct 2026 02:17:10 +0000
Subject: [PATCH 1/2] [libc][math] Implement double precision cosh correctly
rounded to all rounding modes.
Use shared exp(x) +- exp(-x) evaluations with sinh from https://github.com/llvm/llvm-project/pull/235097.
Assisted-by: Gemini for analysis and refactoring.
---
libc/config/baremetal/aarch64/entrypoints.txt | 1 +
libc/config/baremetal/arm/entrypoints.txt | 1 +
libc/config/baremetal/riscv/entrypoints.txt | 1 +
libc/config/darwin/aarch64/entrypoints.txt | 1 +
libc/config/freebsd/x86_64/entrypoints.txt | 1 +
libc/config/gpu/amdgpu/entrypoints.txt | 1 +
libc/config/gpu/nvptx/entrypoints.txt | 1 +
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/arm/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/config/windows/entrypoints.txt | 1 +
libc/docs/headers/math/index.md | 2 +-
libc/include/math.yaml | 6 +
libc/shared/math.h | 1 +
libc/shared/math/cosh.h | 28 +++
libc/src/__support/math/CMakeLists.txt | 29 +++
libc/src/__support/math/cosh.h | 34 ++++
libc/src/__support/math/cosh_double_eval.h | 94 +++++++++
libc/src/math/generic/CMakeLists.txt | 10 +
libc/src/math/generic/cosh.cpp | 21 ++
libc/test/shared/CMakeLists.txt | 1 +
libc/test/shared/shared_math_test.cpp | 1 +
libc/test/src/math/CMakeLists.txt | 16 ++
libc/test/src/math/cosh_test.cpp | 187 ++++++++++++++++++
libc/test/src/math/smoke/CMakeLists.txt | 15 ++
libc/test/src/math/smoke/cosh_test.cpp | 125 ++++++++++++
.../llvm-project-overlay/libc/BUILD.bazel | 34 ++++
.../libc/test/src/math/BUILD.bazel | 8 +
.../libc/test/src/math/smoke/BUILD.bazel | 8 +
30 files changed, 631 insertions(+), 1 deletion(-)
create mode 100644 libc/shared/math/cosh.h
create mode 100644 libc/src/__support/math/cosh.h
create mode 100644 libc/src/__support/math/cosh_double_eval.h
create mode 100644 libc/src/math/generic/cosh.cpp
create mode 100644 libc/test/src/math/cosh_test.cpp
create mode 100644 libc/test/src/math/smoke/cosh_test.cpp
diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 4811e8b2667c0b..e8aa8dac843b07 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -386,6 +386,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.dfmal
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 50dc1bc0df7bb1..557f766bab9617 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -398,6 +398,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.dfmal
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 04ac30d013ddfd..52a8141b7af881 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -389,6 +389,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.dfmal
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 5f99b8120380df..79ed5415932c2e 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -207,6 +207,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.dfmal
diff --git a/libc/config/freebsd/x86_64/entrypoints.txt b/libc/config/freebsd/x86_64/entrypoints.txt
index 047ca0fd23f19b..726ca8a6b058af 100644
--- a/libc/config/freebsd/x86_64/entrypoints.txt
+++ b/libc/config/freebsd/x86_64/entrypoints.txt
@@ -141,6 +141,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.ceill
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.daddl
libc.src.math.ddivl
diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index 5858f85006a0e5..5d552b2b43be0a 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -332,6 +332,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.ddivl
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index f7fec6506ba726..bb5fa8fe21dfb8 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -328,6 +328,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.ddivl
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 4c503678b70c47..5215e9992b7bd8 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -630,6 +630,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.daddl
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index e5e2c321e4261f..bbbe33adae4356 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -426,6 +426,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.dfmal
libc.src.math.dsqrtl
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 164ef7c9822884..bbf2e288ada6b8 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -687,6 +687,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.daddl
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 7a2f7b1cd36ed6..821a5ab3d90d1d 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -709,6 +709,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.daddl
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index b419bd6d6e22d5..84931dbddc4fab 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -173,6 +173,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.ceill
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.daddl
libc.src.math.ddivl
diff --git a/libc/docs/headers/math/index.md b/libc/docs/headers/math/index.md
index a4596408ee5648..e0393075cd900b 100644
--- a/libc/docs/headers/math/index.md
+++ b/libc/docs/headers/math/index.md
@@ -180,7 +180,7 @@ log
| cbrt | {{ check }} | {{ check }} | | {{ check }} | | {{ check }} | 7.12.7.1 | F.10.4.1 |
| compoundn | | | | | | | 7.12.7.2 | F.10.4.2 |
| cos | {{ check }} | {{ check }} | | {{ check }} | | | 7.12.4.5 | F.10.1.5 |
-| cosh | {{ check }} | | | {{ check }} | | | 7.12.5.4 | F.10.2.4 |
+| cosh | {{ check }} | {{ check }} | | {{ check }} | | | 7.12.5.4 | F.10.2.4 |
| cospi | {{ check }} | | | {{ check }} | | | 7.12.4.12 | F.10.1.12 |
| dsqrt | N/A | N/A | {{ check }} | N/A | {{ check }}\* | | 7.12.14.6 | F.10.11 |
| erf | {{ check }} | | | | | | 7.12.8.1 | F.10.5.1 |
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index 89e0ab4f0dac60..09668300f9ea88 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -323,6 +323,12 @@ functions:
arguments:
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
+ - name: cosh
+ standards:
+ - stdc
+ return_type: double
+ arguments:
+ - type: double
- name: coshf
standards:
- stdc
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 76e2ff78bc69e6..e23967f6c4fbac 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -85,6 +85,7 @@
#include "math/cos.h"
#include "math/cosf.h"
#include "math/cosf16.h"
+#include "math/cosh.h"
#include "math/coshf.h"
#include "math/coshf16.h"
#include "math/cospif.h"
diff --git a/libc/shared/math/cosh.h b/libc/shared/math/cosh.h
new file mode 100644
index 00000000000000..7e21496ebcd9b4
--- /dev/null
+++ b/libc/shared/math/cosh.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Shared cosh function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SHARED_MATH_COSH_H
+#define LLVM_LIBC_SHARED_MATH_COSH_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/cosh.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::cosh;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_COSH_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index d8e1784254a59e..cd2d2fb90d8987 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -5798,6 +5798,35 @@ add_header_library(
libc.src.__support.macros.properties.cpu_features
)
+add_header_library(
+ cosh_double_eval
+ HDRS
+ cosh_double_eval.h
+ DEPENDS
+ .sinhcosh_utils
+ libc.hdr.errno_macros
+ libc.hdr.fenv_macros
+ libc.src.__support.FPUtil.except_value_utils
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.rounding_mode
+ libc.src.__support.common
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+)
+
+add_header_library(
+ cosh
+ HDRS
+ cosh.h
+ DEPENDS
+ .cosh_double_eval
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+)
+
add_header_library(
sinh_double_eval
HDRS
diff --git a/libc/src/__support/math/cosh.h b/libc/src/__support/math/cosh.h
new file mode 100644
index 00000000000000..07248d0b0023b3
--- /dev/null
+++ b/libc/src/__support/math/cosh.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Implementation header for cosh.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COSH_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_COSH_H
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+#include "src/__support/math/cosh_double_eval.h"
+#define LIBC_MATH_COSH_IMPL double_eval
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+
+using LIBC_MATH_COSH_IMPL::cosh;
+
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#undef LIBC_MATH_COSH_IMPL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_COSH_H
diff --git a/libc/src/__support/math/cosh_double_eval.h b/libc/src/__support/math/cosh_double_eval.h
new file mode 100644
index 00000000000000..0511cee00cdaa3
--- /dev/null
+++ b/libc/src/__support/math/cosh_double_eval.h
@@ -0,0 +1,94 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 implementation of cosh.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COSH_DOUBLE_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_COSH_DOUBLE_EVAL_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/math/sinhcosh_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace double_eval {
+
+// Handle tiny (|x| <= 2^-27), overflow (|x| >= 0x1.633ce8fb9f87ep+9), inf, and
+// nan for cosh(x):
+LIBC_NOINLINE LIBC_INLINE double cosh_exceptional(double x) {
+ using FPBits = fputil::FPBits<double>;
+ FPBits xbits(x);
+
+ // Tiny and subnormal range: |x| <= 2^-27.
+ // For 0 < |x| <= 2^-27:
+ // 0 < cosh(x) - 1 ~ x^2 / 2 < 2^-55 < 0.5 * ulp(1.0),
+ // so cosh(x) rounds to 1.0 + 2^-52 when rounding mode is FE_UPWARD and to
+ // 1.0 otherwise, with FE_INEXACT raised for all x != 0.
+ if (xbits.abs().uintval() <= 0x3e40'0000'0000'0000ULL) {
+ if (LIBC_UNLIKELY(x == 0.0))
+ return 1.0;
+ return fputil::round_result_slightly_up(1.0);
+ }
+
+ if (xbits.is_nan())
+ return x + 1.0;
+
+ if (xbits.is_inf())
+ return FPBits::inf().get_val();
+
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_overflow_except_if_required<double>();
+
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+ int rounding = fputil::quick_get_round();
+ if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO))
+ return FPBits::max_normal().get_val();
+#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+ return FPBits::inf().get_val();
+}
+
+LIBC_ALWAYS_INLINE double cosh(double x) {
+ using FPBits = fputil::FPBits<double>;
+ FPBits xbits(x);
+
+ uint64_t x_abs = xbits.abs().uintval();
+
+ // Bound constants (with biased exponent and mantissa bits):
+ // - Tiny bound: 2^-27 = 0x1.0p-27
+ constexpr uint64_t TINY_BOUND = 0x3e40'0000'0000'0000ULL;
+ // - Overflow bound:
+ // > round(acosh(2^1023 * (2 - 2^-52)), D, RU) = 0x1.633ce8fb9f87ep+9
+ // > round(acosh(2^1023 * (2 - 2^-52)), D, RD) = 0x1.633ce8fb9f87dp+9
+ // > round(cosh(0x1.633ce8fb9f87dp+9), D, RN) = 0x1.ffffffffffd3bp+1023
+ // > round(cosh(0x1.633ce8fb9f87ep+9), D, RN) = +inf
+ constexpr uint64_t OVERFLOW_BOUND = 0x4086'33ce'8fb9'f87eULL;
+
+ if (LIBC_UNLIKELY(x_abs <= TINY_BOUND || x_abs >= OVERFLOW_BOUND))
+ return cosh_exceptional(x);
+
+ return exp_pm_eval(xbits.abs().get_val(), /*is_sinh=*/false);
+}
+
+} // namespace double_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_COSH_DOUBLE_EVAL_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 46d5c9c491d782..8fb90a662bb8c0 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3760,6 +3760,16 @@ add_entrypoint_object(
libc.src.__support.math.ufromfpxbf16
)
+add_entrypoint_object(
+ cosh
+ SRCS
+ cosh.cpp
+ HDRS
+ ../cosh.h
+ DEPENDS
+ libc.src.__support.math.cosh
+)
+
add_entrypoint_object(
coshf
SRCS
diff --git a/libc/src/math/generic/cosh.cpp b/libc/src/math/generic/cosh.cpp
new file mode 100644
index 00000000000000..3d34c90f1a54ce
--- /dev/null
+++ b/libc/src/math/generic/cosh.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cosh(x) function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/math/cosh.h"
+#include "src/__support/math/cosh.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(double, cosh, (double x)) { return math::cosh(x); }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 0693846349eab9..228614ac51c441 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -95,6 +95,7 @@ else()
libc.src.__support.math.cos
libc.src.__support.math.cosf
libc.src.__support.math.cosf16
+ libc.src.__support.math.cosh
libc.src.__support.math.coshf
libc.src.__support.math.coshf16
libc.src.__support.math.cospif
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 8c258484686a7a..a80501eec07602 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -339,6 +339,7 @@ TEST(LlvmLibcSharedMathTest, AllDouble) {
EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::shared::atan2(0.0, 0.0));
EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::shared::cbrt(0.0));
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::shared::cos(0.0));
+ EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::shared::cosh(0.0));
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::shared::exp(0.0));
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::shared::exp2(0.0));
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::shared::exp10(0.0));
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 456c06a398906d..f35f4003bbeca2 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2613,6 +2613,22 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ cosh_test
+ NEED_MPFR
+ SUITE
+ libc-math-tests
+ SRCS
+ cosh_test.cpp
+ DEPENDS
+ libc.hdr.fenv_macros
+ libc.src.math.cosh
+ libc.src.__support.math.cosh_double_eval
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.optimization
+)
+
add_fp_unittest(
coshf_test
NEED_MPFR
diff --git a/libc/test/src/math/cosh_test.cpp b/libc/test/src/math/cosh_test.cpp
new file mode 100644
index 00000000000000..150528bb0e572d
--- /dev/null
+++ b/libc/test/src/math/cosh_test.cpp
@@ -0,0 +1,187 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 unittests for cosh.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/fenv_macros.h"
+#include "hdr/math_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/math/cosh_double_eval.h"
+#include "src/math/cosh.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 // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+#define TOLERANCE 0
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+#define ALL_ROUNDING false
+#else
+#define ALL_ROUNDING true
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+using LIBC_NAMESPACE::testing::tlog;
+
+LIBC_NOINLINE double cosh_double_eval(double x) {
+ return LIBC_NAMESPACE::math::double_eval::cosh(x);
+}
+
+class CoshTest : public LIBC_NAMESPACE::testing::FPTest<double> {
+public:
+ void test_special_numbers(double (*func)(double)) {
+ EXPECT_FP_EQ(aNaN, func(aNaN));
+ EXPECT_FP_EQ(inf, func(inf));
+ EXPECT_FP_EQ_ALL_ROUNDING(inf, func(neg_inf));
+ EXPECT_FP_EQ_ALL_ROUNDING(1.0, func(0.0));
+ EXPECT_FP_EQ_ALL_ROUNDING(1.0, func(-0.0));
+ }
+
+ void test_overflow(double (*func)(double)) {
+ EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(0x1.0p20), FE_OVERFLOW);
+ EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(-0x1.0p20), FE_OVERFLOW);
+ }
+
+ void test_tricky_inputs(double (*func)(double), double ulp_tolerance = 0.5,
+ bool all_rounding = true) {
+ constexpr int N = 20;
+ constexpr uint64_t INPUTS[N] = {
+ 0x3e40'0000'0000'0000ULL, // x = 0x1.0p-27
+ 0x3e40'0000'0000'0001ULL, // x = 0x1.0000000000001p-27
+ 0x3eb0'1fe0'3f61'baceULL, // x = 0x1.01fe03f61bacep-20
+ 0x3f10'1218'4c8c'9313ULL, // x = 0x1.012184c8c9313p-14
+ 0x3f80'1813'9e73'ee47ULL, // x = 0x1.018139e73ee47p-7
+ 0x3fa0'10b2'a872'e30bULL, // x = 0x1.010b2a872e30bp-5
+ 0x3fb9'a5e3'cbe1'985eULL, // x = 0x1.9a5e3cbe1985ep-4
+ 0x3fc5'2a11'832e'847dULL, // x = 0x1.52a11832e847dp-3
+ 0x3fcb'f030'5e2c'6c37ULL, // x = 0x1.bf0305e2c6c37p-3
+ 0x3fd1'7326'ffc0'9f68ULL, // x = 0x1.17326ffc09f68p-2
+ 0x3fd3'd27b'f16d'8bdbULL, // x = 0x1.3d27bf16d8bdbp-2
+ 0x3fe0'3923'f2b4'7c07ULL, // x = 0x1.03923f2b47c07p-1
+ 0x3fea'6031'cd5f'93baULL, // x = 0x1.a6031cd5f93bap-1
+ 0x3ff1'04b6'48f1'13a1ULL, // x = 0x1.104b648f113a1p+0
+ 0x3ff1'5857'20f3'5cd9ULL, // x = 0x1.1585720f35cd9p+0
+ 0x3ffe'9cc7'ed2e'1a7eULL, // x = 0x1.e9cc7ed2e1a7ep+0
+ 0x4004'3180'ea85'4696ULL, // x = 0x1.43180ea854696p+1
+ 0x4017'2581'1dcf'6782ULL, // x = 0x1.725811dcf6782p+2
+ 0x4086'33ce'8fb9'f87dULL, // x = 0x1.633ce8fb9f87dp+9
+ 0x4086'33ce'8fb9'f87eULL, // x = 0x1.633ce8fb9f87ep+9
+ };
+ for (int i = 0; i < N; ++i) {
+ double x = FPBits(INPUTS[i]).get_val();
+ if (all_rounding) {
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cosh, x, func(x),
+ ulp_tolerance);
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cosh, -x, func(-x),
+ ulp_tolerance);
+ } else {
+ EXPECT_MPFR_MATCH(mpfr::Operation::Cosh, x, func(x), ulp_tolerance);
+ EXPECT_MPFR_MATCH(mpfr::Operation::Cosh, -x, func(-x), ulp_tolerance);
+ }
+ }
+ }
+
+ void test_in_range(double (*func)(double), double ulp_tolerance = 0.5,
+ bool all_rounding = true) {
+ constexpr uint64_t COUNT = 1'231;
+ constexpr uint64_t START = FPBits(0x1.0p-30).uintval();
+ constexpr uint64_t STOP = FPBits(710.0).uintval();
+ constexpr uint64_t STEP = (STOP - START) / COUNT;
+
+ auto test = [&](mpfr::RoundingMode rounding_mode) {
+ mpfr::ForceRoundingMode __r(rounding_mode);
+ if (!__r.success)
+ return;
+
+ uint64_t fails = 0;
+ uint64_t count = 0;
+ uint64_t cc = 0;
+ double mx = 0.0, mr = 0.0;
+ double tol = 0.5;
+
+ for (uint64_t i = 0, v = START; i <= COUNT; ++i, v += STEP) {
+ double x = FPBits(v).get_val();
+ if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0)
+ continue;
+ double result = func(x);
+ ++cc;
+ if (FPBits(result).is_nan() || FPBits(result).is_inf())
+ continue;
+
+ ++count;
+ if (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Cosh, x, result,
+ ulp_tolerance, rounding_mode)) {
+ ++fails;
+ while (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(
+ mpfr::Operation::Cosh, x, result, tol, rounding_mode)) {
+ mx = x;
+ mr = result;
+
+ if (tol > 1000.0)
+ break;
+
+ tol *= 2.0;
+ }
+ }
+ }
+ if (fails) {
+ tlog << " Cosh failed: " << fails << "/" << count << "/" << cc
+ << " tests.\n";
+ tlog << " Max ULPs is at most: " << static_cast<uint64_t>(tol)
+ << ".\n";
+ EXPECT_MPFR_MATCH(mpfr::Operation::Cosh, mx, mr, ulp_tolerance,
+ rounding_mode);
+ }
+ };
+
+ tlog << " Test Rounding To Nearest...\n";
+ test(mpfr::RoundingMode::Nearest);
+
+ if (all_rounding) {
+ tlog << " Test Rounding Downward...\n";
+ test(mpfr::RoundingMode::Downward);
+
+ tlog << " Test Rounding Upward...\n";
+ test(mpfr::RoundingMode::Upward);
+
+ tlog << " Test Rounding Toward Zero...\n";
+ test(mpfr::RoundingMode::TowardZero);
+ }
+ }
+};
+
+#define LIST_COSH_TESTS(suffix, func, ulp_tolerance, all_rounding) \
+ using LlvmLibcCoshTest##suffix = CoshTest; \
+ TEST_F(LlvmLibcCoshTest##suffix, SpecialNumbers) { \
+ test_special_numbers(&func); \
+ } \
+ TEST_F(LlvmLibcCoshTest##suffix, Overflow) { test_overflow(&func); } \
+ TEST_F(LlvmLibcCoshTest##suffix, TrickyInputs) { \
+ test_tricky_inputs(&func, ulp_tolerance, all_rounding); \
+ } \
+ TEST_F(LlvmLibcCoshTest##suffix, InDoubleRange) { \
+ test_in_range(&func, ulp_tolerance, all_rounding); \
+ } \
+ static_assert(true, "Require semicolon.")
+
+LIST_COSH_TESTS(Default, LIBC_NAMESPACE::cosh,
+ /*ulp_tolerance=*/TOLERANCE + 0.5,
+ /*all_rounding=*/ALL_ROUNDING);
+LIST_COSH_TESTS(DoubleEval, cosh_double_eval,
+ /*ulp_tolerance=*/TOLERANCE + 0.5,
+ /*all_rounding=*/ALL_ROUNDING);
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 310ad0f57abf5d..df4c263ba48a3a 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -4766,6 +4766,21 @@ add_fp_unittest(
libc.src.__support.FPUtil.fenv_impl
)
+add_fp_unittest(
+ cosh_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ cosh_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fenv_macros
+ libc.src.math.cosh
+ libc.src.__support.math.cosh_double_eval
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.macros.attributes
+)
+
add_fp_unittest(
coshf_test
SUITE
diff --git a/libc/test/src/math/smoke/cosh_test.cpp b/libc/test/src/math/smoke/cosh_test.cpp
new file mode 100644
index 00000000000000..757a6d2feb3c16
--- /dev/null
+++ b/libc/test/src/math/smoke/cosh_test.cpp
@@ -0,0 +1,125 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 smoke tests for cosh.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "hdr/math_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/math/cosh_double_eval.h"
+#include "src/math/cosh.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+LIBC_NOINLINE double cosh_double_eval(double x) {
+ return LIBC_NAMESPACE::math::double_eval::cosh(x);
+}
+
+class CoshTest : public LIBC_NAMESPACE::testing::FPTest<double> {
+public:
+ void test_special_numbers(double (*func)(double),
+ bool check_snan_invalid = false) {
+ if (check_snan_invalid) {
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(sNaN), FE_INVALID);
+ } else {
+ EXPECT_FP_EQ(aNaN, func(sNaN));
+ }
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(inf, func(neg_inf));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(1.0, func(0.0));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(1.0, func(-0.0));
+ EXPECT_MATH_ERRNO(0);
+ }
+
+ void test_overflow(double (*func)(double)) {
+ // x = 0x1.fffffffffffffp+1023 (max_normal)
+ EXPECT_FP_EQ_WITH_EXCEPTION(
+ inf, func(FPBits(uint64_t(0x7fef'ffff'ffff'ffff)).get_val()),
+ FE_OVERFLOW);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ // x = 0x1.633ce8fb9f87ep+9 (smallest positive input that overflows)
+ EXPECT_FP_EQ_WITH_EXCEPTION(
+ inf, func(FPBits(uint64_t(0x4086'33ce'8fb9'f87e)).get_val()),
+ FE_OVERFLOW);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ // x = -0x1.633ce8fb9f87ep+9 (largest negative input that overflows)
+ EXPECT_FP_EQ_WITH_EXCEPTION(
+ inf, func(FPBits(uint64_t(0xc086'33ce'8fb9'f87e)).get_val()),
+ FE_OVERFLOW);
+ EXPECT_MATH_ERRNO(ERANGE);
+ }
+
+ void test_tiny(double (*func)(double)) {
+ EXPECT_FP_EQ(1.0, func(min_denormal));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ(1.0, func(-min_denormal));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ(1.0, func(0x1.0p-27));
+ EXPECT_MATH_ERRNO(0);
+ }
+
+#ifdef LIBC_TEST_FTZ_DAZ
+ void test_denormals(double (*func)(double)) {
+ EXPECT_FP_EQ(1.0, func(min_denormal));
+ EXPECT_FP_EQ(1.0, func(max_denormal));
+ }
+#endif // LIBC_TEST_FTZ_DAZ
+};
+
+#ifdef LIBC_TEST_FTZ_DAZ
+#define LIST_COSH_FTZ_DAZ_TESTS(suffix, func) \
+ TEST_F(LlvmLibcCoshTest##suffix, FTZMode) { \
+ LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ); \
+ test_denormals(&func); \
+ } \
+ TEST_F(LlvmLibcCoshTest##suffix, DAZMode) { \
+ LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::DAZ); \
+ test_denormals(&func); \
+ } \
+ TEST_F(LlvmLibcCoshTest##suffix, FTZDAZMode) { \
+ LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ | \
+ LIBC_NAMESPACE::testing::DAZ); \
+ test_denormals(&func); \
+ }
+#else // !LIBC_TEST_FTZ_DAZ
+#define LIST_COSH_FTZ_DAZ_TESTS(suffix, func)
+#endif // LIBC_TEST_FTZ_DAZ
+
+#define LIST_COSH_TESTS(suffix, func, check_snan_invalid) \
+ using LlvmLibcCoshTest##suffix = CoshTest; \
+ TEST_F(LlvmLibcCoshTest##suffix, SpecialNumbers) { \
+ test_special_numbers(&func, check_snan_invalid); \
+ } \
+ TEST_F(LlvmLibcCoshTest##suffix, Overflow) { test_overflow(&func); } \
+ TEST_F(LlvmLibcCoshTest##suffix, Tiny) { test_tiny(&func); } \
+ LIST_COSH_FTZ_DAZ_TESTS(suffix, func) \
+ static_assert(true, "Require semicolon.")
+
+LIST_COSH_TESTS(Default, LIBC_NAMESPACE::cosh, /*check_snan_invalid=*/true);
+LIST_COSH_TESTS(DoubleEval, cosh_double_eval, /*check_snan_invalid=*/false);
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 85ae3445e4eb70..ac2496a7080f85 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -8793,6 +8793,35 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "__support_math_cosh_double_eval",
+ hdrs = ["src/__support/math/cosh_double_eval.h"],
+ deps = [
+ ":__support_common",
+ ":__support_fputil_except_value_utils",
+ ":__support_fputil_fenv_impl",
+ ":__support_fputil_fp_bits",
+ ":__support_fputil_rounding_mode",
+ ":__support_macros_attributes",
+ ":__support_macros_config",
+ ":__support_macros_optimization",
+ ":__support_math_sinhcosh_utils",
+ ":hdr_errno_macros",
+ ":hdr_fenv_macros",
+ ],
+)
+
+libc_support_library(
+ name = "__support_math_cosh",
+ hdrs = ["src/__support/math/cosh.h"],
+ deps = [
+ ":__support_common",
+ ":__support_macros_config",
+ ":__support_macros_optimization",
+ ":__support_math_cosh_double_eval",
+ ],
+)
+
libc_support_library(
name = "__support_math_coshf",
hdrs = ["src/__support/math/coshf.h"],
@@ -13149,6 +13178,11 @@ libc_math_function(
],
)
+libc_math_function(
+ name = "cosh",
+ additional_deps = [":__support_math_cosh"],
+)
+
libc_math_function(
name = "coshf",
additional_deps = [":__support_math_coshf"],
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel
index e356b8548a1b2b..6fb4c7a52bcda5 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel
@@ -129,6 +129,14 @@ math_mpfr_test(
],
)
+math_mpfr_test(
+ name = "cosh",
+ deps = [
+ "//libc:__support_macros_attributes",
+ "//libc:__support_math_cosh_double_eval",
+ ],
+)
+
math_mpfr_test(
name = "coshf",
deps = [
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/math/smoke/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/math/smoke/BUILD.bazel
index bde4161cf09d8d..3a6603795970b4 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/math/smoke/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/math/smoke/BUILD.bazel
@@ -307,6 +307,14 @@ math_test(name = "cos")
math_test(name = "cosf")
+math_test(
+ name = "cosh",
+ deps = [
+ "//libc:__support_macros_attributes",
+ "//libc:__support_math_cosh_double_eval",
+ ],
+)
+
math_test(
name = "coshf",
deps = [
>From c9f05f10ab2f71477a165664fdccf7168f5c22b0 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Wed, 28 Oct 2026 05:02:26 +0000
Subject: [PATCH 2/2] Address review comments: reuse COSH_TINY_BOUND and add
hexagon entrypoint.
---
libc/config/baremetal/hexagon/entrypoints.txt | 1 +
libc/src/__support/math/cosh_double_eval.h | 25 ++++++++++---------
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/libc/config/baremetal/hexagon/entrypoints.txt b/libc/config/baremetal/hexagon/entrypoints.txt
index e549eea197bdc5..379f99a6579e44 100644
--- a/libc/config/baremetal/hexagon/entrypoints.txt
+++ b/libc/config/baremetal/hexagon/entrypoints.txt
@@ -384,6 +384,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.copysignl
libc.src.math.cos
libc.src.math.cosf
+ libc.src.math.cosh
libc.src.math.coshf
libc.src.math.cospif
libc.src.math.dfmal
diff --git a/libc/src/__support/math/cosh_double_eval.h b/libc/src/__support/math/cosh_double_eval.h
index 0511cee00cdaa3..c4a84258ff47f8 100644
--- a/libc/src/__support/math/cosh_double_eval.h
+++ b/libc/src/__support/math/cosh_double_eval.h
@@ -30,6 +30,17 @@ namespace LIBC_NAMESPACE_DECL {
namespace math {
namespace double_eval {
+// Bound constants (with biased exponent and mantissa bits):
+// - Tiny bound: 2^-27 = 0x1.0p-27
+LIBC_INLINE_VAR constexpr uint64_t COSH_TINY_BOUND = 0x3e40'0000'0000'0000ULL;
+// - Overflow bound:
+// > round(acosh(2^1023 * (2 - 2^-52)), D, RU) = 0x1.633ce8fb9f87ep+9
+// > round(acosh(2^1023 * (2 - 2^-52)), D, RD) = 0x1.633ce8fb9f87dp+9
+// > round(cosh(0x1.633ce8fb9f87dp+9), D, RN) = 0x1.ffffffffffd3bp+1023
+// > round(cosh(0x1.633ce8fb9f87ep+9), D, RN) = +inf
+LIBC_INLINE_VAR constexpr uint64_t COSH_OVERFLOW_BOUND =
+ 0x4086'33ce'8fb9'f87eULL;
+
// Handle tiny (|x| <= 2^-27), overflow (|x| >= 0x1.633ce8fb9f87ep+9), inf, and
// nan for cosh(x):
LIBC_NOINLINE LIBC_INLINE double cosh_exceptional(double x) {
@@ -41,7 +52,7 @@ LIBC_NOINLINE LIBC_INLINE double cosh_exceptional(double x) {
// 0 < cosh(x) - 1 ~ x^2 / 2 < 2^-55 < 0.5 * ulp(1.0),
// so cosh(x) rounds to 1.0 + 2^-52 when rounding mode is FE_UPWARD and to
// 1.0 otherwise, with FE_INEXACT raised for all x != 0.
- if (xbits.abs().uintval() <= 0x3e40'0000'0000'0000ULL) {
+ if (xbits.abs().uintval() <= COSH_TINY_BOUND) {
if (LIBC_UNLIKELY(x == 0.0))
return 1.0;
return fputil::round_result_slightly_up(1.0);
@@ -71,17 +82,7 @@ LIBC_ALWAYS_INLINE double cosh(double x) {
uint64_t x_abs = xbits.abs().uintval();
- // Bound constants (with biased exponent and mantissa bits):
- // - Tiny bound: 2^-27 = 0x1.0p-27
- constexpr uint64_t TINY_BOUND = 0x3e40'0000'0000'0000ULL;
- // - Overflow bound:
- // > round(acosh(2^1023 * (2 - 2^-52)), D, RU) = 0x1.633ce8fb9f87ep+9
- // > round(acosh(2^1023 * (2 - 2^-52)), D, RD) = 0x1.633ce8fb9f87dp+9
- // > round(cosh(0x1.633ce8fb9f87dp+9), D, RN) = 0x1.ffffffffffd3bp+1023
- // > round(cosh(0x1.633ce8fb9f87ep+9), D, RN) = +inf
- constexpr uint64_t OVERFLOW_BOUND = 0x4086'33ce'8fb9'f87eULL;
-
- if (LIBC_UNLIKELY(x_abs <= TINY_BOUND || x_abs >= OVERFLOW_BOUND))
+ if (LIBC_UNLIKELY(x_abs <= COSH_TINY_BOUND || x_abs >= COSH_OVERFLOW_BOUND))
return cosh_exceptional(x);
return exp_pm_eval(xbits.abs().get_val(), /*is_sinh=*/false);
More information about the llvm-branch-commits
mailing list