diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt --- a/libc/config/darwin/arm/entrypoints.txt +++ b/libc/config/darwin/arm/entrypoints.txt @@ -105,6 +105,7 @@ 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 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -149,6 +149,7 @@ 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 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -149,7 +149,8 @@ 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 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -106,6 +106,7 @@ 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 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -480,7 +480,9 @@ FunctionSpec<"sinhf", RetValSpec, [ArgSpec]>, FunctionSpec<"tanhf", RetValSpec, [ArgSpec]>, - FunctionSpec<"atanhf", RetValSpec, [ArgSpec]>, + FunctionSpec<"atanf", RetValSpec, [ArgSpec]>, + + FunctionSpec<"atanhf", RetValSpec, [ArgSpec]>, ] >; diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -196,6 +196,15 @@ } return result; } + + inline static FPBits create_value(bool sign, UIntType unbiased_exp, + UIntType mantissa) { + FPBits 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 --- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h +++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h @@ -184,6 +184,15 @@ bits.set_mantissa(v); return bits; } + + inline static FPBits + create_value(bool sign, UIntType unbiased_exp, UIntType mantissa) { + FPBits 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 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -66,6 +66,7 @@ -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 --- /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 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -1242,3 +1242,28 @@ -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 --- /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; + 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 --- 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.h b/libc/src/math/generic/inv_trigf_utils.h new file mode 100644 --- /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 + +#include + +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; + // 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(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/src/math/generic/inv_trigf_utils.cpp b/libc/src/math/generic/inv_trigf_utils.cpp new file mode 100644 --- /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/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -1388,6 +1388,32 @@ 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(differential_testing) diff --git a/libc/test/src/math/atanf_test.cpp b/libc/test/src/math/atanf_test.cpp new file mode 100644 --- /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 + +#include +#include + +#include + +using FPBits = __llvm_libc::fputil::FPBits; + +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 --- a/libc/test/src/math/exhaustive/CMakeLists.txt +++ b/libc/test/src/math/exhaustive/CMakeLists.txt @@ -307,3 +307,21 @@ 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 --- /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 + +using FPBits = __llvm_libc::fputil::FPBits; + +namespace mpfr = __llvm_libc::testing::mpfr; + +struct LlvmLibcAtanfExhaustiveTest : public LlvmLibcExhaustiveTest { + 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 --- 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 --- /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 + +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.h b/libc/utils/MPFRWrapper/MPFRUtils.h --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -25,6 +25,7 @@ // and output floating point numbers are of the same kind. BeginUnaryOperationsSingleOutput, Abs, + Atan, Atanh, Ceil, Cos, diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -182,6 +182,12 @@ 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 @@ switch (op) { case Operation::Abs: return mpfrInput.abs(); + case Operation::Atan: + return mpfrInput.atan(); case Operation::Atanh: return mpfrInput.atanh(); case Operation::Ceil: