[libc-commits] [libc] 77e1d9b - [libc][math] Added atanf function.

Kirill Okhotnikov via libc-commits libc-commits at lists.llvm.org
Tue Aug 30 13:40:47 PDT 2022


Author: Kirill Okhotnikov
Date: 2022-08-30T22:39:54+02:00
New Revision: 77e1d9beedeccfc0e368b3f34956e12f78d0faa2

URL: https://github.com/llvm/llvm-project/commit/77e1d9beedeccfc0e368b3f34956e12f78d0faa2
DIFF: https://github.com/llvm/llvm-project/commit/77e1d9beedeccfc0e368b3f34956e12f78d0faa2.diff

LOG: [libc][math] Added atanf function.

Performance by core-math (core-math/glibc 2.31/current llvm-14):
28.879/20.843/20.15

Differential Revision: https://reviews.llvm.org/D132842

Added: 
    libc/src/math/atanf.h
    libc/src/math/generic/atanf.cpp
    libc/src/math/generic/inv_trigf_utils.cpp
    libc/src/math/generic/inv_trigf_utils.h
    libc/test/src/math/atanf_test.cpp
    libc/test/src/math/exhaustive/atanf_test.cpp
    libc/test/src/math/inv_trigf_utils_test.cpp

Modified: 
    libc/config/darwin/arm/entrypoints.txt
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/config/windows/entrypoints.txt
    libc/spec/stdc.td
    libc/src/__support/FPUtil/FPBits.h
    libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
    libc/src/math/CMakeLists.txt
    libc/src/math/generic/CMakeLists.txt
    libc/src/math/generic/explogxf.h
    libc/test/src/math/CMakeLists.txt
    libc/test/src/math/exhaustive/CMakeLists.txt
    libc/test/src/math/explogxf_test.cpp
    libc/utils/MPFRWrapper/MPFRUtils.cpp
    libc/utils/MPFRWrapper/MPFRUtils.h

Removed: 
    


################################################################################
diff  --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt
index 08c3a2e098ec8..0b5e21984a3f9 100644
--- a/libc/config/darwin/arm/entrypoints.txt
+++ b/libc/config/darwin/arm/entrypoints.txt
@@ -105,6 +105,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.fenv.feupdateenv
 
     # math.h entrypoints
+    libc.src.math.atanf
     libc.src.math.atanhf
     libc.src.math.copysign
     libc.src.math.copysignf

diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 3dd0a16cb4188..0e8e8df8326d4 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -149,6 +149,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.fenv.feupdateenv
 
     # math.h entrypoints
+    libc.src.math.atanf
     libc.src.math.atanhf    
     libc.src.math.copysign
     libc.src.math.copysignf

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 0a64077f5e4bb..80e178aeaa1b5 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -149,7 +149,8 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.fenv.feupdateenv
 
     # math.h entrypoints
-    libc.src.math.atanhf    
+    libc.src.math.atanf
+    libc.src.math.atanhf
     libc.src.math.copysign
     libc.src.math.copysignf
     libc.src.math.copysignl

diff  --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 28298f30155ba..bf13a5c082c08 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -106,6 +106,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.fenv.feupdateenv
 
     # math.h entrypoints
+    libc.src.math.atanf    
     libc.src.math.atanhf
     libc.src.math.copysign
     libc.src.math.copysignf

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 7224ddee0eed2..d7daa1d26b05c 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -480,7 +480,9 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"sinhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
           FunctionSpec<"tanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
           
-          FunctionSpec<"atanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,          
+          FunctionSpec<"atanf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
+          
+          FunctionSpec<"atanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
       ]
   >;
 

diff  --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 4b2c5132abdf6..4833bdb750134 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -196,6 +196,15 @@ template <typename T> struct FPBits {
     }
     return result;
   }
+
+  inline static FPBits<T> create_value(bool sign, UIntType unbiased_exp,
+                                       UIntType mantissa) {
+    FPBits<T> result;
+    result.set_sign(sign);
+    result.set_unbiased_exponent(unbiased_exp);
+    result.set_mantissa(mantissa);
+    return result;
+  }
 };
 
 } // namespace fputil

diff  --git a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
index 4e6493e1b3615..6992000d0615b 100644
--- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
+++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
@@ -184,6 +184,15 @@ template <> struct FPBits<long double> {
     bits.set_mantissa(v);
     return bits;
   }
+
+  inline static FPBits<long double>
+  create_value(bool sign, UIntType unbiased_exp, UIntType mantissa) {
+    FPBits<long double> result;
+    result.set_sign(sign);
+    result.set_unbiased_exponent(unbiased_exp);
+    result.set_mantissa(mantissa);
+    return result;
+  }
 };
 
 static_assert(

diff  --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 46565ed6ee69d..373e4ae0db0c5 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -66,6 +66,7 @@ add_entrypoint_object(
     -O3
 )
 
+add_math_entrypoint_object(atanf)
 add_math_entrypoint_object(atanhf)
 
 add_math_entrypoint_object(ceil)

diff  --git a/libc/src/math/atanf.h b/libc/src/math/atanf.h
new file mode 100644
index 0000000000000..9b264e84a3a2f
--- /dev/null
+++ b/libc/src/math/atanf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for atanf -------------------------*- 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_ATANF_H
+#define LLVM_LIBC_SRC_MATH_ATANF_H
+
+namespace __llvm_libc {
+
+float atanf(float x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_ATANF_H

diff  --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index fa55a75187489..42f8b1922da08 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1242,3 +1242,28 @@ add_entrypoint_object(
     -O3
 )
 
+add_object_library(
+  inv_trigf_utils
+  HDRS
+    inv_trigf_utils.h
+  SRCS
+    inv_trigf_utils.cpp
+)
+
+add_entrypoint_object(
+  atanf
+  SRCS
+    atanf.cpp
+  HDRS
+    ../atanf.h
+  DEPENDS
+    .inv_trigf_utils
+    libc.src.__support.FPUtil.fputil
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.FPUtil.nearest_integer
+    libc.src.__support.FPUtil.polyeval
+    libc.include.math
+  COMPILE_OPTIONS
+    -O3
+)
+

diff  --git a/libc/src/math/generic/atanf.cpp b/libc/src/math/generic/atanf.cpp
new file mode 100644
index 0000000000000..490a77c61b91a
--- /dev/null
+++ b/libc/src/math/generic/atanf.cpp
@@ -0,0 +1,57 @@
+//===-- Single-precision atan 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/atanf.h"
+#include "math_utils.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/math/generic/inv_trigf_utils.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(float, atanf, (float x)) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+  bool sign = xbits.get_sign();
+  xbits.set_sign(false);
+
+  if (unlikely(xbits.is_inf_or_nan())) {
+    if (xbits.is_inf())
+      return opt_barrier(sign ? -M_MATH_PI_2 : M_MATH_PI_2);
+    else
+      return x + 1.0f;
+  }
+  // |x| == 0.06905200332403183
+  if (unlikely(xbits.uintval() == 0x3d8d6b23U)) {
+    if (fputil::get_round() == FE_TONEAREST) {
+      // 0.06894256919622421
+      FPBits br(0x3d8d31c3U);
+      br.set_sign(sign);
+      return br.get_val();
+    }
+  }
+
+  // |x| == 1.8670953512191772
+  if (unlikely(xbits.uintval() == 0x3feefcfbU)) {
+    int rounding_mode = fputil::get_round();
+    if (sign) {
+      if (rounding_mode == FE_DOWNWARD) {
+        // -1.0790828466415405
+        return FPBits(0xbf8a1f63U).get_val();
+      }
+    } else {
+      if (rounding_mode == FE_UPWARD) {
+        // 1.0790828466415405
+        return FPBits(0x3f8a1f63U).get_val();
+      }
+    }
+  }
+
+  return atan_eval(x);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/generic/explogxf.h b/libc/src/math/generic/explogxf.h
index 5f79f57fdfa7d..0e3cf9eecbdaa 100644
--- a/libc/src/math/generic/explogxf.h
+++ b/libc/src/math/generic/explogxf.h
@@ -9,7 +9,6 @@
 #ifndef LLVM_LIBC_SRC_MATH_GENERIC_EXPLOGXF_H
 #define LLVM_LIBC_SRC_MATH_GENERIC_EXPLOGXF_H
 
-#include "common_constants.h" // Lookup tables EXP_M
 #include "math_utils.h"
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/FPUtil/FPBits.h"

diff  --git a/libc/src/math/generic/inv_trigf_utils.cpp b/libc/src/math/generic/inv_trigf_utils.cpp
new file mode 100644
index 0000000000000..d88fe6097a6f5
--- /dev/null
+++ b/libc/src/math/generic/inv_trigf_utils.cpp
@@ -0,0 +1,28 @@
+//===-- Single-precision general exp/log functions ------------------------===//
+//
+// 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 "inv_trigf_utils.h"
+
+namespace __llvm_libc {
+
+// N[Table[ArcTan[x], {x, 1/16, 16/16, 1/16}], 40]
+alignas(64) const double ATAN_T[ATAN_T_SIZE] = {
+    0x1.ff55bb72cfdeap-5, 0x1.fd5ba9aac2f6ep-4, 0x1.7b97b4bce5b02p-3,
+    0x1.f5b75f92c80ddp-3, 0x1.362773707ebccp-2, 0x1.6f61941e4def1p-2,
+    0x1.a64eec3cc23fdp-2, 0x1.dac670561bb4fp-2, 0x1.0657e94db30d0p-1,
+    0x1.1e00babdefeb4p-1, 0x1.345f01cce37bbp-1, 0x1.4978fa3269ee1p-1,
+    0x1.5d58987169b18p-1, 0x1.700a7c5784634p-1, 0x1.819d0b7158a4dp-1,
+    0x1.921fb54442d18p-1};
+
+// for(int i = 0; i < 5; i++)
+//     printf("%.13a,\n", (-2 * (i % 2) + 1) * 1.0 / (2 * i + 1));
+alignas(64) const double ATAN_K[5] = {
+    0x1.0000000000000p+0, -0x1.5555555555555p-2, 0x1.999999999999ap-3,
+    -0x1.2492492492492p-3, 0x1.c71c71c71c71cp-4};
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/generic/inv_trigf_utils.h b/libc/src/math/generic/inv_trigf_utils.h
new file mode 100644
index 0000000000000..350d6be58d870
--- /dev/null
+++ b/libc/src/math/generic/inv_trigf_utils.h
@@ -0,0 +1,94 @@
+//===-- Single-precision general inverse trigonometric functions ----------===//
+//
+// 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_GENERIC_INV_TRIGF_UTILS_H
+#define LLVM_LIBC_SRC_MATH_GENERIC_INV_TRIGF_UTILS_H
+
+#include "math_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/common.h"
+#include <src/__support/FPUtil/NearestIntegerOperations.h>
+
+#include <errno.h>
+
+namespace __llvm_libc {
+
+// PI / 2
+constexpr double M_MATH_PI_2 = 0x1.921fb54442d18p+0;
+
+// atan table size
+constexpr int ATAN_T_BITS = 4;
+constexpr int ATAN_T_SIZE = 1 << ATAN_T_BITS;
+
+// N[Table[ArcTan[x], {x, 1/8, 8/8, 1/8}], 40]
+extern const double ATAN_T[ATAN_T_SIZE];
+extern const double ATAN_K[5];
+
+// The main idea of the function is to use formula
+// atan(u) + atan(v) = atan((u+v)/(1-uv))
+
+// x should be positive, normal finite value
+inline static double atan_eval(double x) {
+  using FPB = fputil::FPBits<double>;
+  // Added some small value to umin and umax mantissa to avoid possible rounding
+  // errors.
+  FPB::UIntType umin =
+      FPB::create_value(false, FPB::EXPONENT_BIAS - ATAN_T_BITS - 1,
+                        0x100000000000UL)
+          .uintval();
+  FPB::UIntType umax =
+      FPB::create_value(false, FPB::EXPONENT_BIAS + ATAN_T_BITS,
+                        0xF000000000000UL)
+          .uintval();
+
+  FPB bs(x);
+  bool sign = bs.get_sign();
+  auto x_abs = bs.uintval() & FPB::FloatProp::EXP_MANT_MASK;
+
+  if (x_abs <= umin) {
+    double pe = __llvm_libc::fputil::polyeval(x * x, 0.0, ATAN_K[1], ATAN_K[2],
+                                              ATAN_K[3], ATAN_K[4]);
+    return fputil::multiply_add(pe, x, x);
+  }
+
+  if (x_abs >= umax) {
+    double one_over_x_m = -1.0 / x;
+    double one_over_x2 = one_over_x_m * one_over_x_m;
+    double pe = __llvm_libc::fputil::polyeval(one_over_x2, ATAN_K[0], ATAN_K[1],
+                                              ATAN_K[2], ATAN_K[3]);
+    return fputil::multiply_add(pe, one_over_x_m, sign ? (-M_MATH_PI_2) : (M_MATH_PI_2));
+  }
+
+  double pos_x = FPB(x_abs).get_val();
+  bool one_over_x = pos_x > 1.0;
+  if (one_over_x) {
+    pos_x = 1.0 / pos_x;
+  }
+
+  double near_x = fputil::nearest_integer(pos_x * ATAN_T_SIZE);
+  int val = static_cast<int>(near_x);
+  near_x *= 1.0 / ATAN_T_SIZE;
+
+  double v = (pos_x - near_x) / fputil::multiply_add(near_x, pos_x, 1.0);
+  double v2 = v * v;
+  double pe = __llvm_libc::fputil::polyeval(v2, ATAN_K[0], ATAN_K[1], ATAN_K[2],
+                                            ATAN_K[3], ATAN_K[4]);
+  double result;
+  if (one_over_x)
+    result = M_PI_2 - fputil::multiply_add(pe, v, ATAN_T[val - 1]);
+  else
+    result = fputil::multiply_add(pe, v, ATAN_T[val - 1]);
+  return sign ? -result : result;
+}
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_GENERIC_INV_TRIGF_UTILS_H

diff  --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 28a5a3c27f09b..6c4ca22ca9219 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1388,6 +1388,32 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fputil
 )
 
+add_fp_unittest(
+  atanf_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    atanf_test.cpp
+  DEPENDS
+    libc.src.math.atanf
+    libc.src.__support.FPUtil.fputil
+)
+
+add_fp_unittest(
+  inv_trigf_utils_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  HDRS
+    in_float_range_test_helper.h
+  SRCS
+    inv_trigf_utils_test.cpp
+  DEPENDS
+    libc.src.math.generic.inv_trigf_utils
+    libc.src.__support.FPUtil.fputil
+)
+
 add_subdirectory(generic)
 add_subdirectory(exhaustive)
 add_subdirectory(
diff erential_testing)

diff  --git a/libc/test/src/math/atanf_test.cpp b/libc/test/src/math/atanf_test.cpp
new file mode 100644
index 0000000000000..8dc61bb55a4c6
--- /dev/null
+++ b/libc/test/src/math/atanf_test.cpp
@@ -0,0 +1,65 @@
+//===-- Unittests for atanf -----------------------------------------------===//
+//
+// 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/FPUtil/FPBits.h"
+#include "src/math/atanf.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/FPMatcher.h"
+#include "utils/UnitTest/Test.h"
+#include <math.h>
+
+#include <errno.h>
+#include <stdint.h>
+
+#include <initializer_list>
+
+using FPBits = __llvm_libc::fputil::FPBits<float>;
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+DECLARE_SPECIAL_CONSTANTS(float)
+
+TEST(LlvmLibcAtanfTest, SpecialNumbers) {
+  errno = 0;
+  __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
+  EXPECT_FP_EQ(aNaN, __llvm_libc::atanf(aNaN));
+  EXPECT_FP_EXCEPTION(FE_INVALID);
+  EXPECT_MATH_ERRNO(0);
+
+  __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
+  EXPECT_FP_EQ(0.0f, __llvm_libc::atanf(0.0f));
+  EXPECT_FP_EXCEPTION(0);
+  EXPECT_MATH_ERRNO(0);
+
+  __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
+  EXPECT_FP_EQ(-0.0f, __llvm_libc::atanf(-0.0f));
+  EXPECT_FP_EXCEPTION(0);
+  EXPECT_MATH_ERRNO(0);
+}
+
+TEST(LlvmLibcAtanfTest, InFloatRange) {
+  constexpr uint32_t COUNT = 1000000;
+  const uint32_t STEP = FPBits(inf).uintval() / COUNT;
+  for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
+    float x = float(FPBits(v));
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
+                                   __llvm_libc::atanf(x), 0.5);
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, -x,
+                                   __llvm_libc::atanf(-x), 0.5);
+  }
+}
+
+// For small values, tanh(x) is x.
+TEST(LlvmLibcAtanfTest, SpecialValues) {
+  for (uint32_t v : {0x3d8d6b23U, 0x3feefcfbU, 0xbd8d6b23U, 0xbfeefcfbU,
+                     0x7F800000U, 0xFF800000U}) {
+    float x = float(FPBits(v));
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
+                                   __llvm_libc::atanf(x), 0.5);
+  }
+}

diff  --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index b3d3efa41cb4a..287b5651a12b1 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -307,3 +307,21 @@ add_fp_unittest(
   LINK_LIBRARIES
     -lpthread
 )
+
+add_fp_unittest(
+  atanf_test
+  NO_RUN_POSTBUILD
+  NEED_MPFR
+  SUITE
+    libc_math_exhaustive_tests
+  SRCS
+    atanf_test.cpp
+  DEPENDS
+    .exhaustive_test
+    libc.include.math
+    libc.src.math.atanf
+    libc.src.__support.FPUtil.fputil
+  LINK_LIBRARIES
+    -lpthread
+)
+

diff  --git a/libc/test/src/math/exhaustive/atanf_test.cpp b/libc/test/src/math/exhaustive/atanf_test.cpp
new file mode 100644
index 0000000000000..e8a10e159a30f
--- /dev/null
+++ b/libc/test/src/math/exhaustive/atanf_test.cpp
@@ -0,0 +1,76 @@
+//===-- Exhaustive test for atanf -----------------------------------------===//
+//
+// 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/__support/FPUtil/FPBits.h"
+#include "src/math/atanf.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+#include <thread>
+
+using FPBits = __llvm_libc::fputil::FPBits<float>;
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+struct LlvmLibcAtanfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
+  bool check(uint32_t start, uint32_t stop,
+             mpfr::RoundingMode rounding) override {
+    mpfr::ForceRoundingMode r(rounding);
+    uint32_t bits = start;
+    bool result = true;
+    do {
+      FPBits xbits(bits);
+      float x = float(xbits);
+      result &= EXPECT_MPFR_MATCH(mpfr::Operation::Atan, x,
+                                  __llvm_libc::atanf(x), 0.5, rounding);
+    } while (bits++ < stop);
+    return result;
+  }
+};
+
+static const int NUM_THREADS = std::thread::hardware_concurrency();
+
+// Range: [0, 1.0];
+static const uint32_t POS_START = 0x0000'0000U;
+static const uint32_t POS_STOP = FPBits::inf().uintval();
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
+  test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
+}
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundUp) {
+  test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
+}
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundDown) {
+  test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
+}
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundTowardZero) {
+  test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
+}
+
+// Range: [-1.0, 0];
+static const uint32_t NEG_START = 0x8000'0000U;
+static const uint32_t NEG_STOP = FPBits::neg_inf().uintval();
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundNearestTieToEven) {
+  test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Nearest);
+}
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundUp) {
+  test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Upward);
+}
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundDown) {
+  test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Downward);
+}
+
+TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundTowardZero) {
+  test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::TowardZero);
+}

diff  --git a/libc/test/src/math/explogxf_test.cpp b/libc/test/src/math/explogxf_test.cpp
index acaaacacc98c3..599d005804039 100644
--- a/libc/test/src/math/explogxf_test.cpp
+++ b/libc/test/src/math/explogxf_test.cpp
@@ -1,4 +1,4 @@
-//===-- Unittests for explogxf --------------------------------------------===//
+//===-- Unittests for supfuncf --------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/libc/test/src/math/inv_trigf_utils_test.cpp b/libc/test/src/math/inv_trigf_utils_test.cpp
new file mode 100644
index 0000000000000..ad2d89c40408f
--- /dev/null
+++ b/libc/test/src/math/inv_trigf_utils_test.cpp
@@ -0,0 +1,32 @@
+//===-- Unittests for supfuncf --------------------------------------------===//
+//
+// 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 "in_float_range_test_helper.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/math/generic/inv_trigf_utils.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/FPMatcher.h"
+#include "utils/UnitTest/Test.h"
+#include <math.h>
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+DECLARE_SPECIAL_CONSTANTS(float)
+
+constexpr int def_count = 100003;
+constexpr float def_prec = 0.500001f;
+
+TEST(LlvmLibcAtanfPosTest, InFloatRange) {
+  CHECK_DATA(0.0f, inf, mpfr::Operation::Atan, __llvm_libc::atan_eval, isfinite,
+             def_count, def_prec);
+}
+
+TEST(LlvmLibcAtanfNegTest, InFloatRange) {
+  CHECK_DATA(-0.0f, neg_inf, mpfr::Operation::Atan, __llvm_libc::atan_eval,
+             isfinite, def_count, def_prec);
+}

diff  --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 720c966fb6a39..22d056b699526 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -182,6 +182,12 @@ class MPFRNumber {
     return result;
   }
 
+  MPFRNumber atan() const {
+    MPFRNumber result(*this);
+    mpfr_atan(result.value, value, mpfr_rounding);
+    return result;
+  }
+
   MPFRNumber atanh() const {
     MPFRNumber result(*this);
     mpfr_atanh(result.value, value, mpfr_rounding);
@@ -506,6 +512,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
   switch (op) {
   case Operation::Abs:
     return mpfrInput.abs();
+  case Operation::Atan:
+    return mpfrInput.atan();
   case Operation::Atanh:
     return mpfrInput.atanh();
   case Operation::Ceil:

diff  --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index 4aa3eea6562b4..f098c29138877 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -25,6 +25,7 @@ enum class Operation : int {
   // and output floating point numbers are of the same kind.
   BeginUnaryOperationsSingleOutput,
   Abs,
+  Atan,
   Atanh,
   Ceil,
   Cos,


        


More information about the libc-commits mailing list