Skip to content

[libc][math] Refactor atan implementation to header-only in src/__support/math folder. #150852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

bassiounix
Copy link
Contributor

@bassiounix bassiounix commented Jul 27, 2025

Copy link
Contributor Author

bassiounix commented Jul 27, 2025

@bassiounix bassiounix requested a review from lntue July 27, 2025 20:47
@bassiounix bassiounix added bazel "Peripheral" support tier build system: utils/bazel cmake Build system in general and CMake in particular libc labels Jul 27, 2025 — with Graphite App
@bassiounix bassiounix marked this pull request as ready for review July 27, 2025 20:47
@llvmbot
Copy link
Member

llvmbot commented Jul 27, 2025

@llvm/pr-subscribers-libc

Author: Muhammad Bassiouni (bassiounix)

Changes

Part of #147386

in preparation for: https://discourse.llvm.org/t/rfc-make-clang-builtin-math-functions-constexpr-with-llvm-libc-to-support-c-23-constexpr-math-functions/86450


Patch is 24.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150852.diff

12 Files Affected:

  • (modified) libc/shared/math.h (+1)
  • (added) libc/shared/math/atan.h (+23)
  • (modified) libc/src/__support/math/CMakeLists.txt (+27)
  • (added) libc/src/__support/math/atan.h (+190)
  • (renamed) libc/src/__support/math/atan_utils.h (+7-7)
  • (modified) libc/src/math/generic/CMakeLists.txt (+3-22)
  • (modified) libc/src/math/generic/atan.cpp (+2-165)
  • (modified) libc/src/math/generic/atan2.cpp (+2-1)
  • (modified) libc/src/math/generic/atan2f128.cpp (+2-1)
  • (modified) libc/test/shared/CMakeLists.txt (+1)
  • (modified) libc/test/shared/shared_math_test.cpp (+1)
  • (modified) utils/bazel/llvm-project-overlay/libc/BUILD.bazel (+26-18)
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 26e33ecd45d73..70b1b7b0bef09 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -22,6 +22,7 @@
 #include "math/asinf16.h"
 #include "math/asinhf.h"
 #include "math/asinhf16.h"
+#include "math/atan.h"
 #include "math/erff.h"
 #include "math/exp.h"
 #include "math/exp10.h"
diff --git a/libc/shared/math/atan.h b/libc/shared/math/atan.h
new file mode 100644
index 0000000000000..b9ba89b7e6225
--- /dev/null
+++ b/libc/shared/math/atan.h
@@ -0,0 +1,23 @@
+//===-- Shared atan function ------------------------------------*- 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_SHARED_MATH_ATAN_H
+#define LLVM_LIBC_SHARED_MATH_ATAN_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/atan.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::atan;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_ATAN_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index be208f946024a..cc02920c2a1ef 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -172,6 +172,33 @@ DEPENDS
     libc.src.__support.macros.optimization
 )
 
+add_header_library(
+  atan_utils
+  HDRS
+    atan_utils.h
+DEPENDS
+    libc.src.__support.integer_literals
+    libc.src.__support.FPUtil.double_double
+    libc.src.__support.FPUtil.dyadic_float
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.FPUtil.polyeval
+    libc.src.__support.macros.optimization
+)
+
+add_header_library(
+  atan
+  HDRS
+    atan.h
+DEPENDS
+    .atan_utils
+    libc.src.__support.FPUtil.double_double
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.FPUtil.nearest_integer
+    libc.src.__support.macros.optimization
+)
+
 add_header_library(
   asinf
   HDRS
diff --git a/libc/src/__support/math/atan.h b/libc/src/__support/math/atan.h
new file mode 100644
index 0000000000000..4f42b2948aea8
--- /dev/null
+++ b/libc/src/__support/math/atan.h
@@ -0,0 +1,190 @@
+//===-- Implementation header for atan --------------------------*- 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_ATAN_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ATAN_H
+
+#include "atan_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+// To compute atan(x), we divided it into the following cases:
+// * |x| < 2^-26:
+//      Since |x| > atan(|x|) > |x| - |x|^3/3, and |x|^3/3 < ulp(x)/2, we simply
+//      return atan(x) = x - sign(x) * epsilon.
+// * 2^-26 <= |x| < 1:
+//      We perform range reduction mod 2^-6 = 1/64 as follow:
+//      Let k = 2^(-6) * round(|x| * 2^6), then
+//        atan(x) = sign(x) * atan(|x|)
+//                = sign(x) * (atan(k) + atan((|x| - k) / (1 + |x|*k)).
+//      We store atan(k) in a look up table, and perform intermediate steps in
+//      double-double.
+// * 1 < |x| < 2^53:
+//      First we perform the transformation y = 1/|x|:
+//        atan(x) = sign(x) * (pi/2 - atan(1/|x|))
+//                = sign(x) * (pi/2 - atan(y)).
+//      Then we compute atan(y) using range reduction mod 2^-6 = 1/64 as the
+//      previous case:
+//      Let k = 2^(-6) * round(y * 2^6), then
+//        atan(y) = atan(k) + atan((y - k) / (1 + y*k))
+//                = atan(k) + atan((1/|x| - k) / (1 + k/|x|)
+//                = atan(k) + atan((1 - k*|x|) / (|x| + k)).
+// * |x| >= 2^53:
+//      Using the reciprocal transformation:
+//        atan(x) = sign(x) * (pi/2 - atan(1/|x|)).
+//      We have that:
+//        atan(1/|x|) <= 1/|x| <= 2^-53,
+//      which is smaller than ulp(pi/2) / 2.
+//      So we can return:
+//        atan(x) = sign(x) * (pi/2 - epsilon)
+
+LIBC_INLINE static constexpr double atan(double x) {
+
+  using namespace atan_internal;
+  using FPBits = fputil::FPBits<double>;
+
+  constexpr double IS_NEG[2] = {1.0, -1.0};
+  constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54,
+                                      0x1.921fb54442d18p0};
+  constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54,
+                                       -0x1.921fb54442d18p0};
+
+  FPBits xbits(x);
+  bool x_sign = xbits.is_neg();
+  xbits = xbits.abs();
+  uint64_t x_abs = xbits.uintval();
+  int x_exp =
+      static_cast<int>(x_abs >> FPBits::FRACTION_LEN) - FPBits::EXP_BIAS;
+
+  // |x| < 1.
+  if (x_exp < 0) {
+    if (LIBC_UNLIKELY(x_exp < -26)) {
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+      return x;
+#else
+      if (x == 0.0)
+        return x;
+      // |x| < 2^-26
+      return fputil::multiply_add(-0x1.0p-54, x, x);
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+    }
+
+    double x_d = xbits.get_val();
+    // k = 2^-6 * round(2^6 * |x|)
+    double k = fputil::nearest_integer(0x1.0p6 * x_d);
+    unsigned idx = static_cast<unsigned>(k);
+    k *= 0x1.0p-6;
+
+    // numerator = |x| - k
+    DoubleDouble num, den;
+    num.lo = 0.0;
+    num.hi = x_d - k;
+
+    // denominator = 1 - k * |x|
+    den.hi = fputil::multiply_add(x_d, k, 1.0);
+    DoubleDouble prod = fputil::exact_mult(x_d, k);
+    // Using Dekker's 2SUM algorithm to compute the lower part.
+    den.lo = ((1.0 - den.hi) + prod.hi) + prod.lo;
+
+    // x_r = (|x| - k) / (1 + k * |x|)
+    DoubleDouble x_r = fputil::div(num, den);
+
+    // Approximating atan(x_r) using Taylor polynomial.
+    DoubleDouble p = atan_eval(x_r);
+
+    // atan(x) = sign(x) * (atan(k) + atan(x_r))
+    //         = sign(x) * (atan(k) + atan( (|x| - k) / (1 + k * |x|) ))
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+    return IS_NEG[x_sign] * (ATAN_I[idx].hi + (p.hi + (p.lo + ATAN_I[idx].lo)));
+#else
+
+    DoubleDouble c0 = fputil::exact_add(ATAN_I[idx].hi, p.hi);
+    double c1 = c0.lo + (ATAN_I[idx].lo + p.lo);
+    double r = IS_NEG[x_sign] * (c0.hi + c1);
+
+    return r;
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  }
+
+  // |x| >= 2^53 or x is NaN.
+  if (LIBC_UNLIKELY(x_exp >= 53)) {
+    // x is nan
+    if (xbits.is_nan()) {
+      if (xbits.is_signaling_nan()) {
+        fputil::raise_except_if_required(FE_INVALID);
+        return FPBits::quiet_nan().get_val();
+      }
+      return x;
+    }
+    // |x| >= 2^53
+    // atan(x) ~ sign(x) * pi/2.
+    if (x_exp >= 53)
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+      return IS_NEG[x_sign] * PI_OVER_2.hi;
+#else
+      return fputil::multiply_add(IS_NEG[x_sign], PI_OVER_2.hi,
+                                  IS_NEG[x_sign] * PI_OVER_2.lo);
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  }
+
+  double x_d = xbits.get_val();
+  double y = 1.0 / x_d;
+
+  // k = 2^-6 * round(2^6 / |x|)
+  double k = fputil::nearest_integer(0x1.0p6 * y);
+  unsigned idx = static_cast<unsigned>(k);
+  k *= 0x1.0p-6;
+
+  // denominator = |x| + k
+  DoubleDouble den = fputil::exact_add(x_d, k);
+  // numerator = 1 - k * |x|
+  DoubleDouble num;
+  num.hi = fputil::multiply_add(-x_d, k, 1.0);
+  DoubleDouble prod = fputil::exact_mult(x_d, k);
+  // Using Dekker's 2SUM algorithm to compute the lower part.
+  num.lo = ((1.0 - num.hi) - prod.hi) - prod.lo;
+
+  // x_r = (1/|x| - k) / (1 - k/|x|)
+  //     = (1 - k * |x|) / (|x| - k)
+  DoubleDouble x_r = fputil::div(num, den);
+
+  // Approximating atan(x_r) using Taylor polynomial.
+  DoubleDouble p = atan_eval(x_r);
+
+  // atan(x) = sign(x) * (pi/2 - atan(1/|x|))
+  //         = sign(x) * (pi/2 - atan(k) - atan(x_r))
+  //         = (-sign(x)) * (-pi/2 + atan(k) + atan((1 - k*|x|)/(|x| - k)))
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  double lo_part = p.lo + ATAN_I[idx].lo + MPI_OVER_2.lo;
+  return IS_NEG[!x_sign] * (MPI_OVER_2.hi + ATAN_I[idx].hi + (p.hi + lo_part));
+#else
+  DoubleDouble c0 = fputil::exact_add(MPI_OVER_2.hi, ATAN_I[idx].hi);
+  DoubleDouble c1 = fputil::exact_add(c0.hi, p.hi);
+  double c2 = c1.lo + (c0.lo + p.lo) + (ATAN_I[idx].lo + MPI_OVER_2.lo);
+
+  double r = IS_NEG[!x_sign] * (c1.hi + c2);
+
+  return r;
+#endif
+
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATAN_H
diff --git a/libc/src/math/generic/atan_utils.h b/libc/src/__support/math/atan_utils.h
similarity index 96%
rename from libc/src/math/generic/atan_utils.h
rename to libc/src/__support/math/atan_utils.h
index 24c7271b7e4ec..95613d38c413e 100644
--- a/libc/src/math/generic/atan_utils.h
+++ b/libc/src/__support/math/atan_utils.h
@@ -18,7 +18,7 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-namespace {
+namespace atan_internal {
 
 using DoubleDouble = fputil::DoubleDouble;
 using Float128 = fputil::DyadicFloat<128>;
@@ -29,7 +29,7 @@ using Float128 = fputil::DyadicFloat<128>;
 //     b = round(atan(i/64) - a, D, RN);
 //     print("{", b, ",", a, "},");
 //   };
-constexpr DoubleDouble ATAN_I[65] = {
+static constexpr DoubleDouble ATAN_I[65] = {
     {0.0, 0.0},
     {-0x1.220c39d4dff5p-61, 0x1.fff555bbb729bp-7},
     {-0x1.5ec431444912cp-60, 0x1.ffd55bba97625p-6},
@@ -110,7 +110,7 @@ constexpr DoubleDouble ATAN_I[65] = {
 //        + x_lo * (1 - x_hi^2 + x_hi^4)
 // Since p.lo is ~ x^3/3, the relative error from rounding is bounded by:
 //   |(atan(x) - P(x))/atan(x)| < ulp(x^2) <= 2^(-14-52) = 2^-66.
-[[maybe_unused]] DoubleDouble atan_eval(const DoubleDouble &x) {
+[[maybe_unused]] LIBC_INLINE static DoubleDouble atan_eval(const DoubleDouble &x) {
   DoubleDouble p;
   p.hi = x.hi;
   double x_hi_sq = x.hi * x.hi;
@@ -142,7 +142,7 @@ constexpr DoubleDouble ATAN_I[65] = {
 //     b = 2^ll + a;
 //     print("{Sign::POS, ", 2^(ll - 128), ",", b, "},");
 // };
-constexpr Float128 ATAN_I_F128[65] = {
+static constexpr Float128 ATAN_I_F128[65] = {
     {Sign::POS, 0, 0_u128},
     {Sign::POS, -134, 0xfffaaadd'db94d5bb'e78c5640'15f76048_u128},
     {Sign::POS, -133, 0xffeaaddd'4bb12542'779d776d'da8c6214_u128},
@@ -215,7 +215,7 @@ constexpr Float128 ATAN_I_F128[65] = {
 //                 [0, 2^-7]);
 // > dirtyinfnorm(atan(x) - P, [0, 2^-7]);
 // 0x1.26016ad97f323875760f869684c0898d7b7bb8bep-122
-constexpr Float128 ATAN_POLY_F128[] = {
+static constexpr Float128 ATAN_POLY_F128[] = {
     {Sign::NEG, -129, 0xaaaaaaaa'aaaaaaaa'aaaaaaa6'003c5d1d_u128},
     {Sign::POS, -130, 0xcccccccc'cccccccc'cca00232'8776b063_u128},
     {Sign::NEG, -130, 0x92492492'49249201'27f5268a'cb24aec0_u128},
@@ -225,7 +225,7 @@ constexpr Float128 ATAN_POLY_F128[] = {
 };
 
 // Approximate atan for |x| <= 2^-7.
-[[maybe_unused]] Float128 atan_eval(const Float128 &x) {
+[[maybe_unused]] LIBC_INLINE static constexpr Float128 atan_eval(const Float128 &x) {
   Float128 x_sq = fputil::quick_mul(x, x);
   Float128 x3 = fputil::quick_mul(x, x_sq);
   Float128 p = fputil::polyeval(x_sq, ATAN_POLY_F128[0], ATAN_POLY_F128[1],
@@ -234,7 +234,7 @@ constexpr Float128 ATAN_POLY_F128[] = {
   return fputil::multiply_add(x3, p, x);
 }
 
-} // anonymous namespace
+} // namespace atan_internal
 
 } // namespace LIBC_NAMESPACE_DECL
 
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 025b0290bfe70..ffb0d06c434fc 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -4007,19 +4007,6 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
-add_header_library(
-  atan_utils
-  HDRS
-    atan_utils.h
-  DEPENDS
-    libc.src.__support.integer_literals
-    libc.src.__support.FPUtil.double_double
-    libc.src.__support.FPUtil.dyadic_float
-    libc.src.__support.FPUtil.multiply_add
-    libc.src.__support.FPUtil.polyeval
-    libc.src.__support.macros.optimization
-)
-
 add_entrypoint_object(
   atanf
   SRCS
@@ -4066,13 +4053,7 @@ add_entrypoint_object(
   COMPILE_OPTIONS
     -O3
   DEPENDS
-    .atan_utils
-    libc.src.__support.FPUtil.double_double
-    libc.src.__support.FPUtil.fenv_impl
-    libc.src.__support.FPUtil.fp_bits
-    libc.src.__support.FPUtil.multiply_add
-    libc.src.__support.FPUtil.nearest_integer
-    libc.src.__support.macros.optimization
+    libc.src.__support.math.atan
 )
 
 add_entrypoint_object(
@@ -4102,7 +4083,7 @@ add_entrypoint_object(
   HDRS
     ../atan2.h
   DEPENDS
-    .atan_utils
+    libc.src.__support.math.atan_utils
     libc.src.__support.FPUtil.double_double
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
@@ -4128,7 +4109,7 @@ add_entrypoint_object(
   HDRS
     ../atan2f128.h
   DEPENDS
-    .atan_utils
+    libc.src.__support.math.atan_utils
     libc.src.__support.integer_literals
     libc.src.__support.uint128
     libc.src.__support.FPUtil.dyadic_float
diff --git a/libc/src/math/generic/atan.cpp b/libc/src/math/generic/atan.cpp
index cbca60536a3fd..93bf2e108e361 100644
--- a/libc/src/math/generic/atan.cpp
+++ b/libc/src/math/generic/atan.cpp
@@ -7,173 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/math/atan.h"
-#include "atan_utils.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/double_double.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/nearest_integer.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+#include "src/__support/math/atan.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-// To compute atan(x), we divided it into the following cases:
-// * |x| < 2^-26:
-//      Since |x| > atan(|x|) > |x| - |x|^3/3, and |x|^3/3 < ulp(x)/2, we simply
-//      return atan(x) = x - sign(x) * epsilon.
-// * 2^-26 <= |x| < 1:
-//      We perform range reduction mod 2^-6 = 1/64 as follow:
-//      Let k = 2^(-6) * round(|x| * 2^6), then
-//        atan(x) = sign(x) * atan(|x|)
-//                = sign(x) * (atan(k) + atan((|x| - k) / (1 + |x|*k)).
-//      We store atan(k) in a look up table, and perform intermediate steps in
-//      double-double.
-// * 1 < |x| < 2^53:
-//      First we perform the transformation y = 1/|x|:
-//        atan(x) = sign(x) * (pi/2 - atan(1/|x|))
-//                = sign(x) * (pi/2 - atan(y)).
-//      Then we compute atan(y) using range reduction mod 2^-6 = 1/64 as the
-//      previous case:
-//      Let k = 2^(-6) * round(y * 2^6), then
-//        atan(y) = atan(k) + atan((y - k) / (1 + y*k))
-//                = atan(k) + atan((1/|x| - k) / (1 + k/|x|)
-//                = atan(k) + atan((1 - k*|x|) / (|x| + k)).
-// * |x| >= 2^53:
-//      Using the reciprocal transformation:
-//        atan(x) = sign(x) * (pi/2 - atan(1/|x|)).
-//      We have that:
-//        atan(1/|x|) <= 1/|x| <= 2^-53,
-//      which is smaller than ulp(pi/2) / 2.
-//      So we can return:
-//        atan(x) = sign(x) * (pi/2 - epsilon)
-
-LLVM_LIBC_FUNCTION(double, atan, (double x)) {
-  using FPBits = fputil::FPBits<double>;
-
-  constexpr double IS_NEG[2] = {1.0, -1.0};
-  constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54,
-                                      0x1.921fb54442d18p0};
-  constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54,
-                                       -0x1.921fb54442d18p0};
-
-  FPBits xbits(x);
-  bool x_sign = xbits.is_neg();
-  xbits = xbits.abs();
-  uint64_t x_abs = xbits.uintval();
-  int x_exp =
-      static_cast<int>(x_abs >> FPBits::FRACTION_LEN) - FPBits::EXP_BIAS;
-
-  // |x| < 1.
-  if (x_exp < 0) {
-    if (LIBC_UNLIKELY(x_exp < -26)) {
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-      return x;
-#else
-      if (x == 0.0)
-        return x;
-      // |x| < 2^-26
-      return fputil::multiply_add(-0x1.0p-54, x, x);
-#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-    }
-
-    double x_d = xbits.get_val();
-    // k = 2^-6 * round(2^6 * |x|)
-    double k = fputil::nearest_integer(0x1.0p6 * x_d);
-    unsigned idx = static_cast<unsigned>(k);
-    k *= 0x1.0p-6;
-
-    // numerator = |x| - k
-    DoubleDouble num, den;
-    num.lo = 0.0;
-    num.hi = x_d - k;
-
-    // denominator = 1 - k * |x|
-    den.hi = fputil::multiply_add(x_d, k, 1.0);
-    DoubleDouble prod = fputil::exact_mult(x_d, k);
-    // Using Dekker's 2SUM algorithm to compute the lower part.
-    den.lo = ((1.0 - den.hi) + prod.hi) + prod.lo;
-
-    // x_r = (|x| - k) / (1 + k * |x|)
-    DoubleDouble x_r = fputil::div(num, den);
-
-    // Approximating atan(x_r) using Taylor polynomial.
-    DoubleDouble p = atan_eval(x_r);
-
-    // atan(x) = sign(x) * (atan(k) + atan(x_r))
-    //         = sign(x) * (atan(k) + atan( (|x| - k) / (1 + k * |x|) ))
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-    return IS_NEG[x_sign] * (ATAN_I[idx].hi + (p.hi + (p.lo + ATAN_I[idx].lo)));
-#else
-
-    DoubleDouble c0 = fputil::exact_add(ATAN_I[idx].hi, p.hi);
-    double c1 = c0.lo + (ATAN_I[idx].lo + p.lo);
-    double r = IS_NEG[x_sign] * (c0.hi + c1);
-
-    return r;
-#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-  }
-
-  // |x| >= 2^53 or x is NaN.
-  if (LIBC_UNLIKELY(x_exp >= 53)) {
-    // x is nan
-    if (xbits.is_nan()) {
-      if (xbits.is_signaling_nan()) {
-        fputil::raise_except_if_required(FE_INVALID);
-        return FPBits::quiet_nan().get_val();
-      }
-      return x;
-    }
-    // |x| >= 2^53
-    // atan(x) ~ sign(x) * pi/2.
-    if (x_exp >= 53)
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-      return IS_NEG[x_sign] * PI_OVER_2.hi;
-#else
-      return fputil::multiply_add(IS_NEG[x_sign], PI_OVER_2.hi,
-                                  IS_NEG[x_sign] * PI_OVER_2.lo);
-#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-  }
-
-  double x_d = xbits.get_val();
-  double y = 1.0 / x_d;
-
-  // k = 2^-6 * round(2^6 / |x|)
-  double k = fputil::nearest_integer(0x1.0p6 * y);
-  unsigned idx = static_cast<unsigned>(k);
-  k *= 0x1.0p-6;
-
-  // denominator = |x| + k
-  DoubleDouble den = fputil::exact_add(x_d, k);
-  // numerator = 1 - k * |x|
-  DoubleDouble num;
-  num.hi = fputil::multiply_add(-x_d, k, 1.0);
-  DoubleDouble prod = fputil::exact_mult(x_d, k);
-  // Using Dekker's 2SUM algorithm to compute the lower part.
-  num.lo = ((1.0 - num.hi) - prod.hi) - prod.lo;
-
-  // x_r = (1/|x| - k) / (1 - k/|x|)
-  //     = (1 - k * |x|) / (|x| - k)
-  DoubleDouble x_r = fputil::div(num, den);
-
-  // Approximating atan(x_r) using Taylor polynomial.
-  DoubleDouble p = atan_eval(x_r);
-
-  // atan(x) = sign(x) * (pi/2 - atan(1/|x|))
-  //         = sign(x) * (pi/2 - atan(k) - atan(x_r))
-  //         = (-sign(x)) * (-pi/2 + atan(k) + atan((1 - k*|x|)/(|x| - k)))
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-  double lo_part = p.lo + ATAN_I[idx].lo + MPI_OVER_2.lo;
-  return IS_NEG[!x_sign] * (MPI_OVER_2.hi + ATAN_I[idx].hi + (p.hi + lo_part));
-#else
-  DoubleDouble c0 = fputil::exact_add(MPI_OVER_2.hi, ATAN_I[idx].hi);
-  DoubleDouble c1 = fputil::exact_add(c0.hi, p.hi);
-  double c2 = c1.lo + (c0.lo + p.lo) + (ATAN_I[idx].lo + MPI_OVER_2.lo);
-
-  double r = IS_NEG[!x_sign] * (c1.hi + c2);
-
-  return r;
-#endif
-}
+LLVM_LIBC_FUNCTION(double, atan, (double x)) { return math::atan(x); }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/atan2.cpp b/libc/src/math/generic/atan2.cpp
index aa770de33fb1f..f60c30fc288aa 100644
--- a/libc/src/math/generic/atan2.cpp
+++ b/libc/src/math/generic/atan2.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/math/atan2.h"
-#include "atan_utils.h"
+#include "src/__support/math/atan_utils.h"
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/double_double.h"
@@ -72,6 +72,7 @@ namespace LIBC_NAMESP...
[truncated]

Copy link

github-actions bot commented Jul 27, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only07-27-_libc_math_refactor_atan_implementation_to_header-only_in_src___support_math_folder branch 3 times, most recently from 5c60818 to da6cf0f Compare July 27, 2025 21:04
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only-asinhf16 branch from 408c7a4 to ef0a9ce Compare July 27, 2025 21:04
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only-asinhf16 branch from ef0a9ce to cae5d05 Compare July 28, 2025 15:16
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only07-27-_libc_math_refactor_atan_implementation_to_header-only_in_src___support_math_folder branch 2 times, most recently from 41e35b0 to 8c60f83 Compare July 28, 2025 16:45
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only-asinhf16 branch from cae5d05 to 0138846 Compare July 28, 2025 16:46
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only07-27-_libc_math_refactor_atan_implementation_to_header-only_in_src___support_math_folder branch from 8c60f83 to 10fe025 Compare July 28, 2025 17:33
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only-asinhf16 branch from 0138846 to 66a1b22 Compare July 28, 2025 17:33
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only07-27-_libc_math_refactor_atan_implementation_to_header-only_in_src___support_math_folder branch from 10fe025 to ee67fee Compare July 28, 2025 18:21
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only-asinhf16 branch from 2aac58c to 041abc3 Compare July 29, 2025 17:10
Base automatically changed from users/bassiounix/spr/refactor-math-functions-to-header-only-asinhf16 to main July 29, 2025 17:19
@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only07-27-_libc_math_refactor_atan_implementation_to_header-only_in_src___support_math_folder branch 3 times, most recently from e60e02e to e03587c Compare July 29, 2025 17:57
Copy link
Contributor Author

bassiounix commented Jul 29, 2025

Merge activity

  • Jul 29, 6:09 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 29, 6:11 PM UTC: Graphite rebased this pull request as part of a merge.
  • Jul 29, 6:16 PM UTC: @bassiounix merged this pull request with Graphite.

@bassiounix bassiounix force-pushed the users/bassiounix/spr/refactor-math-functions-to-header-only07-27-_libc_math_refactor_atan_implementation_to_header-only_in_src___support_math_folder branch from e03587c to 884f616 Compare July 29, 2025 18:11
@bassiounix bassiounix merged commit 551dcc3 into main Jul 29, 2025
19 checks passed
@bassiounix bassiounix deleted the users/bassiounix/spr/refactor-math-functions-to-header-only07-27-_libc_math_refactor_atan_implementation_to_header-only_in_src___support_math_folder branch July 29, 2025 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bazel "Peripheral" support tier build system: utils/bazel cmake Build system in general and CMake in particular libc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants