[libc-commits] [libc] [libc][math] fix rounding issue in tanhf (PR #197260)

via libc-commits libc-commits at lists.llvm.org
Tue May 12 10:55:58 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

<details>
<summary>Changes</summary>

This PR fixes the rounding issue in tanhf. The compiler assumes nearest rounding of `SIGNS[sign_index][0] + SIGNS[sign_index][1]` in the special case of finite `|x| >= 15`, which causes FE_DOWNWARD and FE_TOWARDZERO to return 1.0f instead of the next float below 1.0f for positive inputs. Use fputil::round_result_slightly_down/up to work around the problem. The helpers force the tiny adjustment to be evaluated under the active rounding mode while preserving exact +/-1.0f for infinities.

Assisted-by: Codex with gpt-5.5 high fast
Co-authored-by: lntue <lntue@<!-- -->google.com>


---
Full diff: https://github.com/llvm/llvm-project/pull/197260.diff


1 Files Affected:

- (modified) libc/src/__support/math/tanhf.h (+6-6) 


``````````diff
diff --git a/libc/src/__support/math/tanhf.h b/libc/src/__support/math/tanhf.h
index 15c86c6b25f5f..b42b9ae263ffc 100644
--- a/libc/src/__support/math/tanhf.h
+++ b/libc/src/__support/math/tanhf.h
@@ -12,6 +12,7 @@
 #include "exp10f_utils.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/except_value_utils.h"
 #include "src/__support/FPUtil/multiply_add.h"
 #include "src/__support/FPUtil/nearest_integer.h"
 #include "src/__support/macros/config.h"
@@ -30,8 +31,6 @@ LIBC_INLINE float tanhf(float x) {
   FPBits xbits(x);
   uint32_t x_abs = xbits.abs().uintval();
 
-  const int sign_index = xbits.is_neg() ? 1 : 0;
-
   // When |x| >= 15, or x is inf or nan, or |x| <= 0.078125
   if (LIBC_UNLIKELY((x_abs >= 0x4170'0000U) || (x_abs <= 0x3da0'0000U))) {
     if (x_abs <= 0x3da0'0000U) {
@@ -62,12 +61,13 @@ LIBC_INLINE float tanhf(float x) {
     if (LIBC_UNLIKELY(xbits.is_nan()))
       return x + 1.0f; // sNaN to qNaN + signal
 
-    constexpr float SIGNS[2][2] = {{1.0f, -0x1.0p-25f}, {-1.0f, 0x1.0p-25f}};
-
     if (LIBC_UNLIKELY(xbits.is_inf()))
-      return SIGNS[sign_index][0];
+      return xbits.is_neg() ? -1.0f : 1.0f;
+
+    if (xbits.is_pos())
+      return fputil::round_result_slightly_down(1.0f);
 
-    return SIGNS[sign_index][0] + SIGNS[sign_index][1];
+    return fputil::round_result_slightly_up(-1.0f);
   }
 
   // Range reduction: e^(2x) = 2^(hi + mid) * e^lo

``````````

</details>


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


More information about the libc-commits mailing list