[libc-commits] [libc] [libc][math][c23] implement C23 math function `tanpif` (PR #147192)

Connector Switch via libc-commits libc-commits at lists.llvm.org
Fri Jul 11 20:19:49 PDT 2025


https://github.com/c8ef updated https://github.com/llvm/llvm-project/pull/147192

>From 8ef8dd4c801fd4abbec67a8b2ad68641826e3fdf Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Sun, 6 Jul 2025 22:14:06 +0800
Subject: [PATCH 1/4] implement tanpif

---
 libc/config/linux/aarch64/entrypoints.txt     |   1 +
 libc/config/linux/x86_64/entrypoints.txt      |   1 +
 libc/docs/headers/math/index.rst              |   2 +-
 libc/include/math.yaml                        |   6 +
 libc/src/math/CMakeLists.txt                  |   2 +
 libc/src/math/generic/CMakeLists.txt          |  15 +++
 libc/src/math/generic/tanpif.cpp              | 106 ++++++++++++++++++
 libc/src/math/tanpif.h                        |  20 ++++
 libc/test/src/math/exhaustive/CMakeLists.txt  |  16 +++
 libc/test/src/math/exhaustive/tanpif_test.cpp |  33 ++++++
 libc/test/src/math/smoke/CMakeLists.txt       |  11 ++
 libc/test/src/math/smoke/tanpif_test.cpp      |  36 ++++++
 12 files changed, 248 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/math/generic/tanpif.cpp
 create mode 100644 libc/src/math/tanpif.h
 create mode 100644 libc/test/src/math/exhaustive/tanpif_test.cpp
 create mode 100644 libc/test/src/math/smoke/tanpif_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 9e042cd4a8acb..cff5b7f8312d6 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -625,6 +625,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.tan
     libc.src.math.tanf
     libc.src.math.tanhf
+    libc.src.math.tanpif
     libc.src.math.totalorder
     libc.src.math.totalorderf
     libc.src.math.totalorderl
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 59c248871f83a..ea31d858dbc44 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -657,6 +657,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.tan
     libc.src.math.tanf
     libc.src.math.tanhf
+    libc.src.math.tanpif
     libc.src.math.totalorder
     libc.src.math.totalorderf
     libc.src.math.totalorderl
diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst
index 3cb41a6871b94..9679c4a6c807f 100644
--- a/libc/docs/headers/math/index.rst
+++ b/libc/docs/headers/math/index.rst
@@ -349,7 +349,7 @@ Higher Math Functions
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | tanh      | |check|          |                 |                        | |check|              |                        | 7.12.5.6               | F.10.2.6                   |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| tanpi     |                  |                 |                        | |check|              |                        | 7.12.4.14              | F.10.1.14                  |
+| tanpi     | |check|          |                 |                        | |check|              |                        | 7.12.4.14              | F.10.1.14                  |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | tgamma    |                  |                 |                        |                      |                        | 7.12.8.4               | F.10.5.4                   |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index 11bead0745954..3044ec3437ff8 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -2524,6 +2524,12 @@ functions:
     arguments:
       - type: _Float16
     guard: LIBC_TYPES_HAS_FLOAT16
+  - name: tanpif
+    standards:
+      - stdc
+    return_type: float
+    arguments:
+      - type: float
   - name: tanpif16
     standards:
       - stdc
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index b27b0d2b523f8..455ad3456573a 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -519,6 +519,8 @@ add_math_entrypoint_object(tanf16)
 add_math_entrypoint_object(tanh)
 add_math_entrypoint_object(tanhf)
 add_math_entrypoint_object(tanhf16)
+
+add_math_entrypoint_object(tanpif)
 add_math_entrypoint_object(tanpif16)
 
 add_math_entrypoint_object(tgamma)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index fd1e6c0d648aa..a379110853012 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -606,6 +606,21 @@ add_entrypoint_object(
     libc.src.__support.macros.properties.types
 )
 
+add_entrypoint_object(
+  tanpif
+  SRCS
+    tanpif.cpp
+  HDRS
+    ../tanpif.h
+  DEPENDS
+    .sincosf_utils
+    libc.src.__support.FPUtil.except_value_utils
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.macros.optimization
+)
+
 add_entrypoint_object(
   tanpif16
   SRCS
diff --git a/libc/src/math/generic/tanpif.cpp b/libc/src/math/generic/tanpif.cpp
new file mode 100644
index 0000000000000..ff1984d325d91
--- /dev/null
+++ b/libc/src/math/generic/tanpif.cpp
@@ -0,0 +1,106 @@
+//===-- Single-precision tanpi function -----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/tanpif.h"
+#include "sincosf_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+
+namespace LIBC_NAMESPACE_DECL {
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+constexpr size_t N_EXCEPTS = 3;
+
+constexpr fputil::ExceptValues<float, N_EXCEPTS> TANPIF_EXCEPTS{{
+    // (input, RZ output, RU offset, RD offset, RN offset)
+    {0x38F26685, 0x39BE6182, 1, 0, 0},
+    {0x3E933802, 0x3FA267DD, 1, 0, 0},
+    {0x3F3663FF, 0xBFA267DD, 0, 1, 0},
+}};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+LLVM_LIBC_FUNCTION(float, tanpif, (float x)) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+
+  uint32_t x_u = xbits.uintval();
+  uint32_t x_abs = x_u & 0x7fff'ffffU;
+  double xd = static_cast<double>(xbits.get_val());
+
+  // Handle exceptional values
+  if (LIBC_UNLIKELY(x_abs <= 0x3F3663FF)) {
+    if (LIBC_UNLIKELY(x_abs == 0U))
+      return x;
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+    bool x_sign = x_u >> 31;
+
+    if (auto r = TANPIF_EXCEPTS.lookup_odd(x_abs, x_sign);
+        LIBC_UNLIKELY(r.has_value()))
+      return r.value();
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  }
+
+  // Numbers greater or equal to 2^23 are always integers, or infinity, or NaN
+  if (LIBC_UNLIKELY(x_abs >= 0x4B00'0000)) {
+    // x is inf or NaN.
+    if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+      if (xbits.is_signaling_nan()) {
+        fputil::raise_except_if_required(FE_INVALID);
+        return FPBits::quiet_nan().get_val();
+      }
+
+      if (x_abs == 0x7f80'0000U) {
+        fputil::set_errno_if_required(EDOM);
+        fputil::raise_except_if_required(FE_INVALID);
+      }
+
+      return x + FPBits::quiet_nan().get_val();
+    }
+
+    return FPBits::zero(xbits.sign()).get_val();
+  }
+
+  // Range reduction:
+  // For |x| > 1/32, we perform range reduction as follows:
+  // Find k and y such that:
+  //   x = (k + y) * 1/32
+  //   k is an integer
+  //   |y| < 0.5
+  //
+  // This is done by performing:
+  //   k = round(x * 32)
+  //   y = x * 32 - k
+  //
+  // Once k and y are computed, we then deduce the answer by the formula:
+  // tan(x) = sin(x) / cos(x)
+  //        = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k)
+  double sin_k, cos_k, sin_y, cosm1_y;
+  sincospif_eval(xd, sin_k, cos_k, sin_y, cosm1_y);
+
+  if (LIBC_UNLIKELY(sin_y == 0 && cos_k == 0)) {
+    fputil::set_errno_if_required(EDOM);
+    fputil::raise_except_if_required(FE_DIVBYZERO);
+
+    int32_t x_mp5_u = static_cast<int32_t>(x - 0.5);
+    return ((x_mp5_u & 0x1) ? -1 : 1) * FPBits::inf().get_val();
+  }
+
+  using fputil::multiply_add;
+  return fputil::cast<float>(
+      multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) /
+      multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/tanpif.h b/libc/src/math/tanpif.h
new file mode 100644
index 0000000000000..59e6dcfa9ff73
--- /dev/null
+++ b/libc/src/math/tanpif.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for tanpif ------------------------*- 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_MATH_TANPIF_H
+#define LLVM_LIBC_SRC_MATH_TANPIF_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float tanpif(float x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_TANPIF_H
diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index 551f449c9c8db..1a23a335b2fff 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -122,6 +122,22 @@ add_fp_unittest(
     -lpthread
 )
 
+add_fp_unittest(
+  tanpif_test
+  NO_RUN_POSTBUILD
+  NEED_MPFR
+  SUITE
+    libc_math_exhaustive_tests
+  SRCS
+    tanpif_test.cpp
+  DEPENDS
+    .exhaustive_test
+    libc.src.math.tanpif
+    libc.src.__support.FPUtil.fp_bits
+  LINK_LIBRARIES
+    -lpthread
+)
+
 add_fp_unittest(
   erff_test
   NO_RUN_POSTBUILD
diff --git a/libc/test/src/math/exhaustive/tanpif_test.cpp b/libc/test/src/math/exhaustive/tanpif_test.cpp
new file mode 100644
index 0000000000000..44a8a06f52374
--- /dev/null
+++ b/libc/test/src/math/exhaustive/tanpif_test.cpp
@@ -0,0 +1,33 @@
+//===-- Exhaustive test for tanpif ----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "exhaustive_test.h"
+#include "src/math/tanpif.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+using LlvmLibcTanpifExhaustiveTest =
+    LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Tanpi,
+                                      LIBC_NAMESPACE::tanpif>;
+
+// Range: [0, Inf];
+static constexpr uint32_t POS_START = 0x0000'0000U;
+static constexpr uint32_t POS_STOP = 0x7f80'0000U;
+
+TEST_F(LlvmLibcTanpifExhaustiveTest, PostiveRange) {
+  test_full_range_all_roundings(POS_START, POS_STOP);
+}
+
+// Range: [-Inf, 0];
+static constexpr uint32_t NEG_START = 0xb000'0000U;
+static constexpr uint32_t NEG_STOP = 0xff80'0000U;
+
+TEST_F(LlvmLibcTanpifExhaustiveTest, NegativeRange) {
+  test_full_range_all_roundings(NEG_START, NEG_STOP);
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 599939cbec4b5..4aafe03d1d08b 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -134,6 +134,17 @@ add_fp_unittest(
     libc.src.math.tanf16
 )
 
+add_fp_unittest(
+  tanpif_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    tanpif_test.cpp
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.math.tanpif
+)
+
 add_fp_unittest(
   tanpif16_test
   SUITE
diff --git a/libc/test/src/math/smoke/tanpif_test.cpp b/libc/test/src/math/smoke/tanpif_test.cpp
new file mode 100644
index 0000000000000..e122f57a2fe0f
--- /dev/null
+++ b/libc/test/src/math/smoke/tanpif_test.cpp
@@ -0,0 +1,36 @@
+//===-- Unittests for tanpif ----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/libc_errno.h"
+#include "src/math/tanpif.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcTanpifTest = LIBC_NAMESPACE::testing::FPTest<float>;
+
+TEST_F(LlvmLibcTanpifTest, SpecialNumbers) {
+  libc_errno = 0;
+
+  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tanpif(sNaN), FE_INVALID);
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanpif(aNaN));
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ(zero, LIBC_NAMESPACE::tanpif(zero));
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::tanpif(neg_zero));
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanpif(inf));
+  EXPECT_MATH_ERRNO(EDOM);
+
+  EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanpif(neg_inf));
+  EXPECT_MATH_ERRNO(EDOM);
+}

>From dc3e101edcb45aad4aa830b89bc41bd40a10f304 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Sat, 12 Jul 2025 10:28:55 +0800
Subject: [PATCH 2/4] add more entrypoint

---
 libc/config/darwin/aarch64/entrypoints.txt | 1 +
 libc/config/linux/arm/entrypoints.txt      | 1 +
 libc/config/linux/riscv/entrypoints.txt    | 1 +
 libc/config/windows/entrypoints.txt        | 1 +
 4 files changed, 4 insertions(+)

diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 437eca79a76f6..4674a9309115b 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -363,6 +363,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.tan
     libc.src.math.tanf
     libc.src.math.tanhf
+    libc.src.math.tanpif
     libc.src.math.totalorder
     libc.src.math.totalorderf
     libc.src.math.totalorderl
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index fa62f4d290c3a..a1203cc4991af 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -437,6 +437,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.tan
     libc.src.math.tanf
     libc.src.math.tanhf
+    libc.src.math.tanpif
     libc.src.math.totalorder
     libc.src.math.totalorderf
     libc.src.math.totalorderl
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index db8f8a7cf0b74..14361f5b6beff 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -635,6 +635,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.tan
     libc.src.math.tanf
     libc.src.math.tanhf
+    libc.src.math.tanpif
     libc.src.math.totalorder
     libc.src.math.totalorderf
     libc.src.math.totalorderl
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 09021a08cf731..8898fd74c302f 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -295,6 +295,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.tan
     libc.src.math.tanf
     libc.src.math.tanhf
+    libc.src.math.tanpif
     libc.src.math.trunc
     libc.src.math.truncf
     libc.src.math.truncl

>From 78eb98014800c09116fd28e55d3faf8bef423b03 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Sat, 12 Jul 2025 10:32:03 +0800
Subject: [PATCH 3/4] avoid mixed precision

---
 libc/src/math/generic/tanpif.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/math/generic/tanpif.cpp b/libc/src/math/generic/tanpif.cpp
index ff1984d325d91..58d46c9481aa5 100644
--- a/libc/src/math/generic/tanpif.cpp
+++ b/libc/src/math/generic/tanpif.cpp
@@ -93,8 +93,8 @@ LLVM_LIBC_FUNCTION(float, tanpif, (float x)) {
     fputil::set_errno_if_required(EDOM);
     fputil::raise_except_if_required(FE_DIVBYZERO);
 
-    int32_t x_mp5_u = static_cast<int32_t>(x - 0.5);
-    return ((x_mp5_u & 0x1) ? -1 : 1) * FPBits::inf().get_val();
+    int32_t x_mp5_i = static_cast<int32_t>(xd - 0.5);
+    return FPBits::inf((x_mp5_i & 0x1) ? Sign::NEG : Sign::POS).get_val();
   }
 
   using fputil::multiply_add;

>From 89a92c0e1ef88c03521ba4f65b173a1c30044a1d Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Sat, 12 Jul 2025 10:46:13 +0800
Subject: [PATCH 4/4] add test in test/src/math

---
 libc/test/src/math/CMakeLists.txt  | 15 +++++
 libc/test/src/math/tanpif_test.cpp | 91 ++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+)
 create mode 100644 libc/test/src/math/tanpif_test.cpp

diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 0d0232335eb5f..43cde0d68873e 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -201,6 +201,21 @@ add_fp_unittest(
     libc.src.math.tanf16
 )
 
+add_fp_unittest(
+  tanpif_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    tanpif_test.cpp
+  HDRS
+    sdcomp26094.h
+  DEPENDS
+    libc.src.math.tanpif
+    libc.src.__support.CPP.array
+    libc.src.__support.FPUtil.fp_bits
+)
+
 add_fp_unittest(
   tanpif16_test
   NEED_MPFR
diff --git a/libc/test/src/math/tanpif_test.cpp b/libc/test/src/math/tanpif_test.cpp
new file mode 100644
index 0000000000000..47f794c4e1b37
--- /dev/null
+++ b/libc/test/src/math/tanpif_test.cpp
@@ -0,0 +1,91 @@
+//===-- Unittests for tanpif ----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/tanpif.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/src/math/sdcomp26094.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcTanpifTest = LIBC_NAMESPACE::testing::FPTest<float>;
+
+using LIBC_NAMESPACE::testing::SDCOMP26094_VALUES;
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+TEST_F(LlvmLibcTanpifTest, SpecificBitPatterns) {
+  constexpr int N = 38;
+  constexpr uint32_t INPUTS[N] = {
+      0x3f00'0000U, // x = 0.5
+      0x461d'd600U, // x = 10101.5
+      0x3f06'0a92U, // x = pi/6
+      0x3f3a'dc51U, // x = 0x1.75b8a2p-1f
+      0x3f49'0fdbU, // x = pi/4
+      0x3f86'0a92U, // x = pi/3
+      0x3fa7'832aU, // x = 0x1.4f0654p+0f
+      0x3fc9'0fdbU, // x = pi/2
+      0x4017'1973U, // x = 0x1.2e32e6p+1f
+      0x4049'0fdbU, // x = pi
+      0x4096'cbe4U, // x = 0x1.2d97c8p+2f
+      0x40c9'0fdbU, // x = 2*pi
+      0x433b'7490U, // x = 0x1.76e92p+7f
+      0x437c'e5f1U, // x = 0x1.f9cbe2p+7f
+      0x4619'9998U, // x = 0x1.33333p+13f
+      0x474d'246fU, // x = 0x1.9a48dep+15f
+      0x4afd'ece4U, // x = 0x1.fbd9c8p+22f
+      0x4c23'32e9U, // x = 0x1.4665d2p+25f
+      0x50a3'e87fU, // x = 0x1.47d0fep+34f
+      0x5239'47f6U, // x = 0x1.728fecp+37f
+      0x53b1'46a6U, // x = 0x1.628d4cp+40f
+      0x55ca'fb2aU, // x = 0x1.95f654p+44f
+      0x588e'f060U, // x = 0x1.1de0cp+50f
+      0x5c07'bcd0U, // x = 0x1.0f79ap+57f
+      0x5ebc'fddeU, // x = 0x1.79fbbcp+62f
+      0x5fa6'eba7U, // x = 0x1.4dd74ep+64f
+      0x61a4'0b40U, // x = 0x1.48168p+68f
+      0x6386'134eU, // x = 0x1.0c269cp+72f
+      0x6589'8498U, // x = 0x1.13093p+76f
+      0x6600'0001U, // x = 0x1.000002p+77f
+      0x664e'46e4U, // x = 0x1.9c8dc8p+77f
+      0x66b0'14aaU, // x = 0x1.602954p+78f
+      0x67a9'242bU, // x = 0x1.524856p+80f
+      0x6a19'76f1U, // x = 0x1.32ede2p+85f
+      0x6c55'da58U, // x = 0x1.abb4bp+89f
+      0x6f79'be45U, // x = 0x1.f37c8ap+95f
+      0x7276'69d4U, // x = 0x1.ecd3a8p+101f
+      0x7758'4625U, // x = 0x1.b08c4ap+111f
+  };
+
+  for (int i = 0; i < N; ++i) {
+    float x = FPBits(INPUTS[i]).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tanpi, x,
+                                   LIBC_NAMESPACE::tanpif(x), 0.5);
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tanpi, -x,
+                                   LIBC_NAMESPACE::tanpif(-x), 0.5);
+  }
+}
+
+// For small values, tanpi(x) is pi * x.
+TEST_F(LlvmLibcTanpifTest, SmallValues) {
+  float x = FPBits(0x1780'0000U).get_val();
+  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tanpi, x,
+                                 LIBC_NAMESPACE::tanpif(x), 0.5);
+
+  x = FPBits(0x0040'0000U).get_val();
+  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tanpi, x,
+                                 LIBC_NAMESPACE::tanpif(x), 0.5);
+}
+
+// SDCOMP-26094: check tanpif in the cases for which the range reducer
+// returns values furthest beyond its nominal upper bound of pi/4.
+TEST_F(LlvmLibcTanpifTest, SDCOMP_26094) {
+  for (uint32_t v : SDCOMP26094_VALUES) {
+    float x = FPBits((v)).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tanpi, x,
+                                   LIBC_NAMESPACE::tanpif(x), 0.5);
+  }
+}



More information about the libc-commits mailing list