From 1c1135b3fccf59537243fc365e83a568f77273ae Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 24 Jul 2025 11:49:03 +0300 Subject: [PATCH 01/20] feat: add the implementatio of `atanpif16` --- libc/src/math/CMakeLists.txt | 2 + libc/src/math/atanpif16.h | 22 ++++ libc/src/math/generic/CMakeLists.txt | 17 +++ libc/src/math/generic/atanpif16.cpp | 155 +++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 libc/src/math/atanpif16.h create mode 100644 libc/src/math/generic/atanpif16.cpp diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index d177ff79141c0..033aa2396b86b 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -67,6 +67,8 @@ add_math_entrypoint_object(atan2f128) add_math_entrypoint_object(atanh) add_math_entrypoint_object(atanhf) +add_math_entrypoint_object(atanpif16) + add_math_entrypoint_object(canonicalize) add_math_entrypoint_object(canonicalizef) add_math_entrypoint_object(canonicalizel) diff --git a/libc/src/math/atanpif16.h b/libc/src/math/atanpif16.h new file mode 100644 index 0000000000000..14dc150014578 --- /dev/null +++ b/libc/src/math/atanpif16.h @@ -0,0 +1,22 @@ +//===-- Implementation header for atanpif16 ---------------------*- 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_ATANPIF16_H +#define LLVM_LIBC_SRC_MATH_ATANPIF16_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float16 atanpif16(float16 x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_ASINF16_H + diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index adbed5b2de48c..421d8163ea792 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -4029,6 +4029,23 @@ add_entrypoint_object( libc.src.__support.macros.optimization ) +add_entrypoint_object( + atanpif16 + SRCS + atanpif16.cpp + HDRS + ../atanpif16.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.sqrt +) + add_object_library( inv_trigf_utils HDRS diff --git a/libc/src/math/generic/atanpif16.cpp b/libc/src/math/generic/atanpif16.cpp new file mode 100644 index 0000000000000..e7ab0a48ca2ab --- /dev/null +++ b/libc/src/math/generic/atanpif16.cpp @@ -0,0 +1,155 @@ +//===-- Half-precision atanpi 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/atanpif16.h" +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/sqrt.h" + +namespace LIBC_NAMESPACE_DECL { + +// Using Python's SymPy library, we can obtain the polynomial approximation of +// arctan(x)/pi. The steps are as follows: +// >>> from sympy import * +// >>> import math +// >>> x = symbols('x') +// >>> print(series(atan(x)/math.pi, x, 0, 21)) +// +// Output: +// 0.318309886183791*x - 0.106103295394597*x**3 + 0.0636619772367581*x**5 - +// 0.0454728408833987*x**7 + 0.0353677651315323*x**9 - 0.0289372623803446*x**11 +// + 0.0244853758602916*x**13 - 0.0212206590789194*x**15 + +// 0.0187241109519877*x**17 - 0.01675315190441*x**19 + O(x**21) +// +// We will assign this 19-degree Taylor polynomial as g(x). This polynomial +// approximation is accurate for arctan(x)/pi when |x| is in the range [0, 0.5]. +// +// +// To compute arctan(x) for all real x, we divide the domain into the following +// cases: +// +// * Case 1: |x| <= 0.5 +// In this range, the direct polynomial approximation is used: +// arctan(x)/pi = sign(x) * g(|x|) +// or equivalently, arctan(x) = sign(x) * pi * g(|x|). +// +// * Case 2: 0.5 < |x| <= 1 +// We use the double-angle identity for the tangent function, specifically: +// arctan(x) = 2 * arctan(x / (1 + sqrt(1 + x^2))). +// Applying this, we have: +// arctan(x)/pi = sign(x) * 2 * arctan(x')/pi, +// where x' = |x| / (1 + sqrt(1 + x^2)). +// Thus, arctan(x)/pi = sign(x) * 2 * g(x') +// +// When |x| is in (0.5, 1], the value of x' will always fall within the +// interval [0.207, 0.414], which is within the accurate range of g(x). +// +// * Case 3: |x| > 1 +// For values of |x| greater than 1, we use the reciprocal transformation +// identity: +// arctan(x) = pi/2 - arctan(1/x) for x > 0. +// For any x (real number), this generalizes to: +// arctan(x)/pi = sign(x) * (1/2 - arctan(1/|x|)/pi). +// Then, using g(x) for arctan(1/|x|)/pi: +// arctan(x)/pi = sign(x) * (1/2 - g(1/|x|)). +// +// Note that if 1/|x| still falls outside the +// g(x)'s primary range of accuracy (i.e., if 0.5 < 1/|x| <= 1), the rule +// from Case 2 must be applied recursively to 1/|x|. + +LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { + using FPBits = fputil::FPBits; + + FPBits xbits(x); + bool is_neg = xbits.is_neg(); + + auto signed_result = [is_neg](double r) -> float16 { + return fputil::cast(is_neg ? -r : r); + }; + + if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) { + if (xbits.is_nan()) { + return x; + } + // atanpi(±∞) = ±0.5 + return signed_result(0.5); + } + + if (LIBC_UNLIKELY(xbits.is_zero())) { + return x; // + } + + double x_abs = fputil::cast(xbits.abs().get_val()); + + // Polynomial coefficients for atan(x)/pi Taylor series + // Generated using SymPy: series(atan(x)/pi, x, 0, 21) + constexpr double POLY_COEFFS[] = { + 0x1.45f306dc9c889p-2, // x^1: 1/pi + -0x1.b2995e7b7b60bp-4, // x^3: -1/(3*pi) + 0x1.04c26be3b06ccp-4, // x^5: 1/(5*pi) + -0x1.7483758e69c08p-5, // x^7: -1/(7*pi) + 0x1.21bb945252403p-5, // x^9: 1/(9*pi) + -0x1.da1bace3cc68ep-6, // x^11: -1/(11*pi) + 0x1.912b1c2336cf2p-6, // x^13: 1/(13*pi) + -0x1.5bade52f95e7p-6, // x^15: -1/(15*pi) + 0x1.32c69d0bde9e8p-6, // x^17: 1/(17*pi) + -0x1.127bcfe232f8cp-6, // x^19: -1/(19*pi) + }; + + // evaluate atan(x)/pi using polynomial approximation, valid for |x| <= 0.5 + constexpr auto atanpi_eval = [](double x) -> double { + double xx = x * x; + return x * fputil::polyeval(xx, POLY_COEFFS[0], POLY_COEFFS[1], + POLY_COEFFS[2], POLY_COEFFS[3], POLY_COEFFS[4], + POLY_COEFFS[5], POLY_COEFFS[6], POLY_COEFFS[7], + POLY_COEFFS[8], POLY_COEFFS[9]); + }; + + // Case 1: |x| <= 0.5 - Direct polynomial evaluation + if (LIBC_LIKELY(x_abs <= 0.5)) { + double result = atanpi_eval(x_abs); + return signed_result(result); + } + + // Case 2: 0.5 < |x| <= 1 - Use double-angle reduction + // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2))) + // So atanpi(x) = 2 * atanpi(x') where x' = x / (1 + sqrt(1 + x^2)) + if (x_abs <= 1.0) { + double x2 = x_abs * x_abs; + double sqrt_term = fputil::sqrt(1.0 + x2); + double x_prime = x_abs / (1.0 + sqrt_term); + double result = 2.0 * atanpi_eval(x_prime); + return signed_result(result); + } + + // Case 3: |x| > 1 - Use reciprocal transformation + // atan(x) = pi/2 - atan(1/x) for x > 0 + // So atanpi(x) = 1/2 - atanpi(1/x) + double x_recip = 1.0 / x_abs; + double result; + + // if 1/|x| > 0.5, we need to apply Case 2 transformation to 1/|x| + if (x_recip > 0.5) { + double x_recip2 = x_recip * x_recip; + double sqrt_term = fputil::sqrt(1.0 + x_recip2); + double x_prime = x_recip / (1.0 + sqrt_term); + result = fputil::multiply_add(-2.0, atanpi_eval(x_prime), 0.5); + } else { + // direct evaluation since 1/|x| <= 0.5 + result = 0.5 - atanpi_eval(x_recip); + } + + return signed_result(result); +} + +} // namespace LIBC_NAMESPACE_DECL From 1a5d472cde4fb58887ddcf3d1e9bd73fc0b763b0 Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 24 Jul 2025 11:49:16 +0300 Subject: [PATCH 02/20] add entries --- libc/config/linux/x86_64/entrypoints.txt | 1 + libc/include/math.yaml | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 73dfeae1a2c94..1585f803229b6 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -664,6 +664,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.acoshf16 libc.src.math.asinf16 libc.src.math.asinhf16 + libc.src.math.atanpif16 libc.src.math.canonicalizef16 libc.src.math.ceilf16 libc.src.math.copysignf16 diff --git a/libc/include/math.yaml b/libc/include/math.yaml index fef829422244d..06a67fdb44a9c 100644 --- a/libc/include/math.yaml +++ b/libc/include/math.yaml @@ -113,6 +113,12 @@ functions: return_type: float arguments: - type: float + - name: atanpif16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 - name: canonicalize standards: - stdc From 926937077156306fe3ddbb3137e8416ab01160e8 Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 24 Jul 2025 12:45:34 +0300 Subject: [PATCH 03/20] add unit tests for `atanpif16` --- libc/src/math/generic/atanpif16.cpp | 16 ++--- libc/test/src/math/smoke/CMakeLists.txt | 12 ++++ libc/test/src/math/smoke/atanpif16_test.cpp | 66 +++++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 libc/test/src/math/smoke/atanpif16_test.cpp diff --git a/libc/src/math/generic/atanpif16.cpp b/libc/src/math/generic/atanpif16.cpp index e7ab0a48ca2ab..0ca0c534d1658 100644 --- a/libc/src/math/generic/atanpif16.cpp +++ b/libc/src/math/generic/atanpif16.cpp @@ -91,8 +91,8 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { double x_abs = fputil::cast(xbits.abs().get_val()); - // Polynomial coefficients for atan(x)/pi Taylor series - // Generated using SymPy: series(atan(x)/pi, x, 0, 21) + // polynomial coefficients for atan(x)/pi taylor series + // generated using sympy: series(atan(x)/pi, x, 0, 21) constexpr double POLY_COEFFS[] = { 0x1.45f306dc9c889p-2, // x^1: 1/pi -0x1.b2995e7b7b60bp-4, // x^3: -1/(3*pi) @@ -121,9 +121,9 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { return signed_result(result); } - // Case 2: 0.5 < |x| <= 1 - Use double-angle reduction + // case 2: 0.5 < |x| <= 1 - use double-angle reduction // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2))) - // So atanpi(x) = 2 * atanpi(x') where x' = x / (1 + sqrt(1 + x^2)) + // so atanpi(x) = 2 * atanpi(x') where x' = x / (1 + sqrt(1 + x^2)) if (x_abs <= 1.0) { double x2 = x_abs * x_abs; double sqrt_term = fputil::sqrt(1.0 + x2); @@ -132,16 +132,16 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { return signed_result(result); } - // Case 3: |x| > 1 - Use reciprocal transformation + // case 3: |x| > 1 - use reciprocal transformation // atan(x) = pi/2 - atan(1/x) for x > 0 - // So atanpi(x) = 1/2 - atanpi(1/x) + // so atanpi(x) = 1/2 - atanpi(1/x) double x_recip = 1.0 / x_abs; double result; // if 1/|x| > 0.5, we need to apply Case 2 transformation to 1/|x| if (x_recip > 0.5) { - double x_recip2 = x_recip * x_recip; - double sqrt_term = fputil::sqrt(1.0 + x_recip2); + double xx_recip = x_recip * x_recip; + double sqrt_term = fputil::sqrt(1.0 + xx_recip); double x_prime = x_recip / (1.0 + sqrt_term); result = fputil::multiply_add(-2.0, atanpi_eval(x_prime), 0.5); } else { diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 223d1933bca38..2461478e2ffb5 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3947,6 +3947,18 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + atanpif16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + atanpif16_test.cpp + DEPENDS + libc.src.math.atanpif16 + libc.src.errno.errno +) + add_fp_unittest( asinhf_test SUITE diff --git a/libc/test/src/math/smoke/atanpif16_test.cpp b/libc/test/src/math/smoke/atanpif16_test.cpp new file mode 100644 index 0000000000000..e0f3ce5f52392 --- /dev/null +++ b/libc/test/src/math/smoke/atanpif16_test.cpp @@ -0,0 +1,66 @@ +//===-- Unittests for atanpif16 -------------------------------------------===// +// +// 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/errno/libc_errno.h" +#include "src/math/atanpif16.h" +#include "test/UnitTest/FPMatcher.h" + +using LlvmLibcAtanpif16Test = LIBC_NAMESPACE::testing::FPTest; + +TEST_F(LlvmLibcAtanpif16Test, SpecialNumbers) { + // zero + EXPECT_FP_EQ(zero, LIBC_NAMESPACE::atanpif16(zero)); + EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::atanpif16(neg_zero)); + + // NaN inputs + EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), + LIBC_NAMESPACE::atanpif16(FPBits::quiet_nan().get_val())); + + EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), + LIBC_NAMESPACE::atanpif16(FPBits::signaling_nan().get_val())); + + // infinity inputs -> should return +/-0.5 + EXPECT_FP_EQ(0.5f16, LIBC_NAMESPACE::atanpif16(inf)); + EXPECT_FP_EQ(-0.5f16, LIBC_NAMESPACE::atanpif16(neg_inf)); +} + + +TEST_F(LlvmLibcAtanpif16Test, SymmetryProperty) { + // Test that atanpi(-x) = -atanpi(x) + constexpr float16 TEST_VALS[] = {0.1f16, 0.25f16, 0.5f16, 0.75f16, + 1.0f16, 1.5f16, 2.0f16, 5.0f16, + 10.0f16, 50.0f16, 100.0f16, 1000.0f16}; + + for (float16 x : TEST_VALS) { + FPBits neg_x_bits(x); + neg_x_bits.set_sign(Sign::NEG); + float16 neg_x = neg_x_bits.get_val(); + + float16 pos_result = LIBC_NAMESPACE::atanpif16(x); + float16 neg_result = LIBC_NAMESPACE::atanpif16(neg_x); + + EXPECT_FP_EQ(pos_result, FPBits(neg_result).abs().get_val()); + } +} + +TEST_F(LlvmLibcAtanpif16Test, MonotonicityProperty) { + // Test that atanpi is monotonically increasing + constexpr float16 TEST_VALS[] = {-1000.0f16, -100.0f16, -10.0f16, -2.0f16, + -1.0f16, -0.5f16, -0.1f16, 0.0f16, + 0.1f16, 0.5f16, 1.0f16, 2.0f16, + 10.0f16, 100.0f16, 1000.0f16}; + + for (size_t i = 0; i < sizeof(TEST_VALS) / sizeof(TEST_VALS[0]) - 1; ++i) { + float16 x1 = TEST_VALS[i]; + float16 x2 = TEST_VALS[i + 1]; + float16 result1 = LIBC_NAMESPACE::atanpif16(x1); + float16 result2 = LIBC_NAMESPACE::atanpif16(x2); + + EXPECT_TRUE(result1 < result2); + } +} From bdae5140992b134249ef8331ab91c4f0dda6f2ca Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 24 Jul 2025 12:53:13 +0300 Subject: [PATCH 04/20] add exhaustive test for `atanpif16` --- libc/test/src/math/CMakeLists.txt | 11 ++++++++ libc/test/src/math/atanpif16_test.cpp | 40 +++++++++++++++++++++++++++ libc/utils/MPFRWrapper/MPCommon.cpp | 6 ++++ libc/utils/MPFRWrapper/MPCommon.h | 1 + libc/utils/MPFRWrapper/MPFRUtils.cpp | 2 ++ libc/utils/MPFRWrapper/MPFRUtils.h | 1 + 6 files changed, 61 insertions(+) create mode 100644 libc/test/src/math/atanpif16_test.cpp diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 7ee8b86135557..b17c7bc50fa42 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -2143,6 +2143,17 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + atanpif16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + atanpif16_test.cpp + DEPENDS + libc.src.math.atanpif16 +) + add_fp_unittest( fmul_test NEED_MPFR diff --git a/libc/test/src/math/atanpif16_test.cpp b/libc/test/src/math/atanpif16_test.cpp new file mode 100644 index 0000000000000..2c24b5048a2fb --- /dev/null +++ b/libc/test/src/math/atanpif16_test.cpp @@ -0,0 +1,40 @@ +//===-- Exhaustive test for atanpif16 -------------------------------------===// +// +// 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/atanpif16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using LlvmLibcAtanpif16Test = LIBC_NAMESPACE::testing::FPTest; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +// Range: [0, Inf] +static constexpr uint16_t POS_START = 0x0000U; +static constexpr uint16_t POS_STOP = 0x7c00U; + +// Range: [-Inf, 0] +static constexpr uint16_t NEG_START = 0x8000U; +static constexpr uint16_t NEG_STOP = 0xfc00U; + +TEST_F(LlvmLibcAtanpif16Test, PositiveRange) { + for (uint16_t v = POS_START; v <= POS_STOP; ++v) { + float16 x = FPBits(v).get_val(); + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atanpi, x, + LIBC_NAMESPACE::atanpif16(x), 0.5); + } +} + +TEST_F(LlvmLibcAtanpif16Test, NegativeRange) { + for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { + float16 x = FPBits(v).get_val(); + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atanpi, x, + LIBC_NAMESPACE::atanpif16(x), 0.5); + } +} \ No newline at end of file diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp index ac8cde2f97221..5bb95df02fcf0 100644 --- a/libc/utils/MPFRWrapper/MPCommon.cpp +++ b/libc/utils/MPFRWrapper/MPCommon.cpp @@ -106,6 +106,12 @@ MPFRNumber MPFRNumber::atanh() const { return result; } +MPFRNumber MPFRNumber::atanpi() const { + MPFRNumber result(*this); + mpfr_atanpi(result.value, value, mpfr_rounding); + return result; +} + MPFRNumber MPFRNumber::cbrt() const { MPFRNumber result(*this); mpfr_cbrt(result.value, value, mpfr_rounding); diff --git a/libc/utils/MPFRWrapper/MPCommon.h b/libc/utils/MPFRWrapper/MPCommon.h index eaa512e30bc86..6888fcfad1329 100644 --- a/libc/utils/MPFRWrapper/MPCommon.h +++ b/libc/utils/MPFRWrapper/MPCommon.h @@ -187,6 +187,7 @@ class MPFRNumber { MPFRNumber atan() const; MPFRNumber atan2(const MPFRNumber &b); MPFRNumber atanh() const; + MPFRNumber atanpi() const; MPFRNumber cbrt() const; MPFRNumber ceil() const; MPFRNumber cos() const; diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index 4a033dbc2049b..cb65f080192b8 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -40,6 +40,8 @@ unary_operation(Operation op, InputType input, unsigned int precision, return mpfrInput.atan(); case Operation::Atanh: return mpfrInput.atanh(); + case Operation::Atanpi: + return mpfrInput.atanpi(); case Operation::Cbrt: return mpfrInput.cbrt(); case Operation::Ceil: diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h index bc65f87c6b5ab..a650a09428f18 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -32,6 +32,7 @@ enum class Operation : int { Asinh, Atan, Atanh, + Atanpi, Cbrt, Ceil, Cos, From 3d0becae259c11c1f6b9f5b1eb82cfa96c09bc7d Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 24 Jul 2025 12:55:58 +0300 Subject: [PATCH 05/20] improve `atanpif16` implementation --- libc/src/math/generic/atanpif16.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libc/src/math/generic/atanpif16.cpp b/libc/src/math/generic/atanpif16.cpp index 0ca0c534d1658..985cf3738614e 100644 --- a/libc/src/math/generic/atanpif16.cpp +++ b/libc/src/math/generic/atanpif16.cpp @@ -23,13 +23,12 @@ namespace LIBC_NAMESPACE_DECL { // >>> from sympy import * // >>> import math // >>> x = symbols('x') -// >>> print(series(atan(x)/math.pi, x, 0, 21)) +// >>> print(series(atan(x)/math.pi, x, 0, 17)) // // Output: // 0.318309886183791*x - 0.106103295394597*x**3 + 0.0636619772367581*x**5 - // 0.0454728408833987*x**7 + 0.0353677651315323*x**9 - 0.0289372623803446*x**11 -// + 0.0244853758602916*x**13 - 0.0212206590789194*x**15 + -// 0.0187241109519877*x**17 - 0.01675315190441*x**19 + O(x**21) +// + 0.0244853758602916*x**13 - 0.0212206590789194*x**15 + O(x**17) // // We will assign this 19-degree Taylor polynomial as g(x). This polynomial // approximation is accurate for arctan(x)/pi when |x| is in the range [0, 0.5]. @@ -86,13 +85,17 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { } if (LIBC_UNLIKELY(xbits.is_zero())) { - return x; // + return x; } double x_abs = fputil::cast(xbits.abs().get_val()); + if (LIBC_UNLIKELY(x_abs == 1.0)) { + return signed_result(0.25); + } + // polynomial coefficients for atan(x)/pi taylor series - // generated using sympy: series(atan(x)/pi, x, 0, 21) + // generated using sympy: series(atan(x)/pi, x, 0, 17) constexpr double POLY_COEFFS[] = { 0x1.45f306dc9c889p-2, // x^1: 1/pi -0x1.b2995e7b7b60bp-4, // x^3: -1/(3*pi) @@ -102,8 +105,6 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { -0x1.da1bace3cc68ep-6, // x^11: -1/(11*pi) 0x1.912b1c2336cf2p-6, // x^13: 1/(13*pi) -0x1.5bade52f95e7p-6, // x^15: -1/(15*pi) - 0x1.32c69d0bde9e8p-6, // x^17: 1/(17*pi) - -0x1.127bcfe232f8cp-6, // x^19: -1/(19*pi) }; // evaluate atan(x)/pi using polynomial approximation, valid for |x| <= 0.5 @@ -111,8 +112,7 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { double xx = x * x; return x * fputil::polyeval(xx, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2], POLY_COEFFS[3], POLY_COEFFS[4], - POLY_COEFFS[5], POLY_COEFFS[6], POLY_COEFFS[7], - POLY_COEFFS[8], POLY_COEFFS[9]); + POLY_COEFFS[5], POLY_COEFFS[6], POLY_COEFFS[7]); }; // Case 1: |x| <= 0.5 - Direct polynomial evaluation From 2499fc92c872e0fa5555db041cd83b209156d8ba Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 25 Jul 2025 12:59:05 +0300 Subject: [PATCH 06/20] formatting --- libc/src/math/atanpif16.h | 1 - libc/test/src/math/smoke/atanpif16_test.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/libc/src/math/atanpif16.h b/libc/src/math/atanpif16.h index 14dc150014578..8f2391a6e47e5 100644 --- a/libc/src/math/atanpif16.h +++ b/libc/src/math/atanpif16.h @@ -19,4 +19,3 @@ float16 atanpif16(float16 x); } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC_MATH_ASINF16_H - diff --git a/libc/test/src/math/smoke/atanpif16_test.cpp b/libc/test/src/math/smoke/atanpif16_test.cpp index e0f3ce5f52392..f1cb1ec4ef3b3 100644 --- a/libc/test/src/math/smoke/atanpif16_test.cpp +++ b/libc/test/src/math/smoke/atanpif16_test.cpp @@ -29,7 +29,6 @@ TEST_F(LlvmLibcAtanpif16Test, SpecialNumbers) { EXPECT_FP_EQ(-0.5f16, LIBC_NAMESPACE::atanpif16(neg_inf)); } - TEST_F(LlvmLibcAtanpif16Test, SymmetryProperty) { // Test that atanpi(-x) = -atanpi(x) constexpr float16 TEST_VALS[] = {0.1f16, 0.25f16, 0.5f16, 0.75f16, From 5d0880036612a0180e2c1fd9cce66ac73108cffe Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 25 Jul 2025 12:59:11 +0300 Subject: [PATCH 07/20] fix conflicts --- libc/include/math.yaml | 2 ++ libc/src/math/generic/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libc/include/math.yaml b/libc/include/math.yaml index 4e08fd74dccc3..539e42c0bbecb 100644 --- a/libc/include/math.yaml +++ b/libc/include/math.yaml @@ -134,12 +134,14 @@ functions: arguments: - type: float - name: atanhf16 + standatds: - stdc return_type: _Float16 arguments: - type: _Float16 guard: LIBC_TYPES_HAS_FLOAT16 - name: atanpif16 + standards: - stdc return_type: _Float16 arguments: diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 280493bed92e7..d1f375256d236 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3931,7 +3931,7 @@ add_entrypoint_object( libc.src.__support.macros.optimization ) -add_object_library( +add_entrypoint_object( atanhf16 SRCS atanhf16.cpp From c8ffe9b33af5d7473912de22a0792e39910507a0 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 25 Jul 2025 13:00:45 +0300 Subject: [PATCH 08/20] fix conflcts --- libc/src/math/generic/CMakeLists.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index d1f375256d236..603c91cd99598 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3968,18 +3968,6 @@ add_entrypoint_object( libc.src.__support.FPUtil.sqrt ) -add_object_library( - inv_trigf_utils - HDRS - inv_trigf_utils.h - SRCS - inv_trigf_utils.cpp - DEPENDS - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.common -) - add_entrypoint_object( asinf SRCS From 1e3a59fb5cc47db941e0a3b2e2399c87e9dd4cd9 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 25 Jul 2025 13:03:18 +0300 Subject: [PATCH 09/20] missed blank line --- libc/test/src/math/atanpif16_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libc/test/src/math/atanpif16_test.cpp b/libc/test/src/math/atanpif16_test.cpp index 2c24b5048a2fb..9e5606afe1fbc 100644 --- a/libc/test/src/math/atanpif16_test.cpp +++ b/libc/test/src/math/atanpif16_test.cpp @@ -37,4 +37,5 @@ TEST_F(LlvmLibcAtanpif16Test, NegativeRange) { EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atanpi, x, LIBC_NAMESPACE::atanpif16(x), 0.5); } -} \ No newline at end of file +} + From e06c286f16f154a47dae6d310f6f088279ec4eea Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 25 Jul 2025 13:04:16 +0300 Subject: [PATCH 10/20] missed blank line --- libc/test/src/math/smoke/atanpif16_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/test/src/math/smoke/atanpif16_test.cpp b/libc/test/src/math/smoke/atanpif16_test.cpp index f1cb1ec4ef3b3..ca12b3ad8d040 100644 --- a/libc/test/src/math/smoke/atanpif16_test.cpp +++ b/libc/test/src/math/smoke/atanpif16_test.cpp @@ -63,3 +63,4 @@ TEST_F(LlvmLibcAtanpif16Test, MonotonicityProperty) { EXPECT_TRUE(result1 < result2); } } + From fad9a76bbf3b796b151470c87b2011b3ce22d0b1 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 25 Jul 2025 14:19:40 +0300 Subject: [PATCH 11/20] check `atanpi` in float16 --- libc/docs/headers/math/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst index 9679c4a6c807f..d5fb397342d4f 100644 --- a/libc/docs/headers/math/index.rst +++ b/libc/docs/headers/math/index.rst @@ -269,7 +269,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | atanh | |check| | | | |check| | | 7.12.5.3 | F.10.2.3 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| atanpi | | | | | | 7.12.4.10 | F.10.1.10 | +| atanpi | | | | |check| | | 7.12.4.10 | F.10.1.10 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | cbrt | |check| | |check| | | | | 7.12.7.1 | F.10.4.1 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ From 5d9362a75d1a0c277bc3629800957315a5e1538c Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 7 Aug 2025 21:07:03 +0300 Subject: [PATCH 12/20] fix format --- libc/test/src/math/atanpif16_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libc/test/src/math/atanpif16_test.cpp b/libc/test/src/math/atanpif16_test.cpp index 9e5606afe1fbc..38771f0147d60 100644 --- a/libc/test/src/math/atanpif16_test.cpp +++ b/libc/test/src/math/atanpif16_test.cpp @@ -38,4 +38,3 @@ TEST_F(LlvmLibcAtanpif16Test, NegativeRange) { LIBC_NAMESPACE::atanpif16(x), 0.5); } } - From a5f5f1c11d79160fc9acdeafa85df3df86c33028 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 8 Aug 2025 14:14:29 +0300 Subject: [PATCH 13/20] fix atanpi mpfr number --- libc/utils/MPFRWrapper/MPCommon.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp index dab53eaa28abe..3b1827298ccb5 100644 --- a/libc/utils/MPFRWrapper/MPCommon.cpp +++ b/libc/utils/MPFRWrapper/MPCommon.cpp @@ -125,8 +125,17 @@ MPFRNumber MPFRNumber::atanh() const { MPFRNumber MPFRNumber::atanpi() const { MPFRNumber result(*this); - mpfr_atanpi(result.value, value, mpfr_rounding); +#if 0 && (MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)) + mpfr_asinpi(result.value, value, mpfr_rounding); + return result; +#else + MPFRNumber value_atan(0.0, 1280); + mpfr_atan(value_atan.value, value, MPFR_RNDN); + MPFRNumber value_pi(0.0, 1280); + mpfr_const_pi(value_pi.value, MPFR_RNDN); + mpfr_div(result.value, value_atan.value, value_pi.value, mpfr_rounding); return result; +#endif } MPFRNumber MPFRNumber::cbrt() const { From cefc0752c6fed7f88b1fb80d6892f134880d98c5 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 8 Aug 2025 14:14:49 +0300 Subject: [PATCH 14/20] improvements --- libc/src/math/generic/atanpif16.cpp | 19 +++++++++++-------- libc/test/src/math/smoke/atanpif16_test.cpp | 18 ++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/libc/src/math/generic/atanpif16.cpp b/libc/src/math/generic/atanpif16.cpp index 985cf3738614e..4db8be09bfd27 100644 --- a/libc/src/math/generic/atanpif16.cpp +++ b/libc/src/math/generic/atanpif16.cpp @@ -15,6 +15,7 @@ #include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/sqrt.h" +#include "src/__support/macros/optimization.h" namespace LIBC_NAMESPACE_DECL { @@ -78,21 +79,23 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { if (LIBC_UNLIKELY(xbits.is_inf_or_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; } // atanpi(±∞) = ±0.5 return signed_result(0.5); } - if (LIBC_UNLIKELY(xbits.is_zero())) { + if (LIBC_UNLIKELY(xbits.is_zero())) return x; - } double x_abs = fputil::cast(xbits.abs().get_val()); - if (LIBC_UNLIKELY(x_abs == 1.0)) { + if (LIBC_UNLIKELY(x_abs == 1.0)) return signed_result(0.25); - } // polynomial coefficients for atan(x)/pi taylor series // generated using sympy: series(atan(x)/pi, x, 0, 17) @@ -109,8 +112,8 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { // evaluate atan(x)/pi using polynomial approximation, valid for |x| <= 0.5 constexpr auto atanpi_eval = [](double x) -> double { - double xx = x * x; - return x * fputil::polyeval(xx, POLY_COEFFS[0], POLY_COEFFS[1], + double x_sq = x * x; + return x * fputil::polyeval(x_sq, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2], POLY_COEFFS[3], POLY_COEFFS[4], POLY_COEFFS[5], POLY_COEFFS[6], POLY_COEFFS[7]); }; @@ -140,8 +143,8 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { // if 1/|x| > 0.5, we need to apply Case 2 transformation to 1/|x| if (x_recip > 0.5) { - double xx_recip = x_recip * x_recip; - double sqrt_term = fputil::sqrt(1.0 + xx_recip); + double x_sq_recip = x_recip * x_recip; + double sqrt_term = fputil::sqrt(1.0 + x_sq_recip); double x_prime = x_recip / (1.0 + sqrt_term); result = fputil::multiply_add(-2.0, atanpi_eval(x_prime), 0.5); } else { diff --git a/libc/test/src/math/smoke/atanpif16_test.cpp b/libc/test/src/math/smoke/atanpif16_test.cpp index ca12b3ad8d040..5accb5d34193a 100644 --- a/libc/test/src/math/smoke/atanpif16_test.cpp +++ b/libc/test/src/math/smoke/atanpif16_test.cpp @@ -6,10 +6,11 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atanpif16.h" #include "test/UnitTest/FPMatcher.h" +using LIBC_NAMESPACE::cpp::array; using LlvmLibcAtanpif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAtanpif16Test, SpecialNumbers) { @@ -21,8 +22,7 @@ TEST_F(LlvmLibcAtanpif16Test, SpecialNumbers) { EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::atanpif16(FPBits::quiet_nan().get_val())); - EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), - LIBC_NAMESPACE::atanpif16(FPBits::signaling_nan().get_val())); + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::atanpif16(aNaN)); // infinity inputs -> should return +/-0.5 EXPECT_FP_EQ(0.5f16, LIBC_NAMESPACE::atanpif16(inf)); @@ -49,12 +49,11 @@ TEST_F(LlvmLibcAtanpif16Test, SymmetryProperty) { TEST_F(LlvmLibcAtanpif16Test, MonotonicityProperty) { // Test that atanpi is monotonically increasing - constexpr float16 TEST_VALS[] = {-1000.0f16, -100.0f16, -10.0f16, -2.0f16, - -1.0f16, -0.5f16, -0.1f16, 0.0f16, - 0.1f16, 0.5f16, 1.0f16, 2.0f16, - 10.0f16, 100.0f16, 1000.0f16}; - - for (size_t i = 0; i < sizeof(TEST_VALS) / sizeof(TEST_VALS[0]) - 1; ++i) { + constexpr array TEST_VALS = { + -1000.0f16, -100.0f16, -10.0f16, -2.0f16, -1.0f16, + -0.5f16, -0.1f16, 0.0f16, 0.1f16, 0.5f16, + 1.0f16, 2.0f16, 10.0f16, 100.0f16, 1000.0f16}; + for (size_t i = 0; i < TEST_VALS.size() - 1; ++i) { float16 x1 = TEST_VALS[i]; float16 x2 = TEST_VALS[i + 1]; float16 result1 = LIBC_NAMESPACE::atanpif16(x1); @@ -63,4 +62,3 @@ TEST_F(LlvmLibcAtanpif16Test, MonotonicityProperty) { EXPECT_TRUE(result1 < result2); } } - From 0da444c2e7857e5fc727595cc46ec72aee1f1774 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 8 Aug 2025 14:15:01 +0300 Subject: [PATCH 15/20] add missed depends --- libc/src/math/generic/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 603c91cd99598..b1fb6aa562288 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3960,12 +3960,14 @@ add_entrypoint_object( DEPENDS libc.hdr.errno_macros libc.hdr.fenv_macros + libc.src.__support.FPUtil.cast libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.polyeval - libc.src.__support.FPUtil.cast libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval libc.src.__support.FPUtil.sqrt + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.types ) add_entrypoint_object( From 669c7e06dfbfdc5cf1866af4f6557f9a0f755927 Mon Sep 17 00:00:00 2001 From: Mohamed Emad Date: Fri, 15 Aug 2025 10:42:01 +0300 Subject: [PATCH 16/20] fix: wrong condition in mpfr --- libc/utils/MPFRWrapper/MPCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp index 3b1827298ccb5..9f20f18217fa0 100644 --- a/libc/utils/MPFRWrapper/MPCommon.cpp +++ b/libc/utils/MPFRWrapper/MPCommon.cpp @@ -125,7 +125,7 @@ MPFRNumber MPFRNumber::atanh() const { MPFRNumber MPFRNumber::atanpi() const { MPFRNumber result(*this); -#if 0 && (MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)) +#if (MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)) mpfr_asinpi(result.value, value, mpfr_rounding); return result; #else From 5b69a72ea218afeef0c86831b5dae7b89977aef5 Mon Sep 17 00:00:00 2001 From: Mohamed Emad Date: Fri, 15 Aug 2025 10:48:01 +0300 Subject: [PATCH 17/20] formatting --- libc/utils/MPFRWrapper/MPCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp index 9f20f18217fa0..6463c0f7672cb 100644 --- a/libc/utils/MPFRWrapper/MPCommon.cpp +++ b/libc/utils/MPFRWrapper/MPCommon.cpp @@ -126,8 +126,8 @@ MPFRNumber MPFRNumber::atanh() const { MPFRNumber MPFRNumber::atanpi() const { MPFRNumber result(*this); #if (MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)) - mpfr_asinpi(result.value, value, mpfr_rounding); - return result; + mpfr_asinpi(result.value, value, mpfr_rounding); + return result; #else MPFRNumber value_atan(0.0, 1280); mpfr_atan(value_atan.value, value, MPFR_RNDN); From 0a234b66237ff77d1a9d222c6b6412c685c09620 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 15 Aug 2025 14:36:05 +0300 Subject: [PATCH 18/20] fix `MPFRNumber::atanpi()` --- libc/utils/MPFRWrapper/MPCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp index 6463c0f7672cb..8a164b8dc25ad 100644 --- a/libc/utils/MPFRWrapper/MPCommon.cpp +++ b/libc/utils/MPFRWrapper/MPCommon.cpp @@ -125,8 +125,8 @@ MPFRNumber MPFRNumber::atanh() const { MPFRNumber MPFRNumber::atanpi() const { MPFRNumber result(*this); -#if (MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)) - mpfr_asinpi(result.value, value, mpfr_rounding); +#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0) + mpfr_atanpi(result.value, value, mpfr_rounding); return result; #else MPFRNumber value_atan(0.0, 1280); From ed38cadf40d8c51e821df6624c78c0c902c51c61 Mon Sep 17 00:00:00 2001 From: hulxv Date: Tue, 2 Sep 2025 20:09:41 +0300 Subject: [PATCH 19/20] use `cpp::array` instead of regular array --- libc/test/src/math/smoke/atanpif16_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libc/test/src/math/smoke/atanpif16_test.cpp b/libc/test/src/math/smoke/atanpif16_test.cpp index 5accb5d34193a..9eb1005a5c171 100644 --- a/libc/test/src/math/smoke/atanpif16_test.cpp +++ b/libc/test/src/math/smoke/atanpif16_test.cpp @@ -31,9 +31,9 @@ TEST_F(LlvmLibcAtanpif16Test, SpecialNumbers) { TEST_F(LlvmLibcAtanpif16Test, SymmetryProperty) { // Test that atanpi(-x) = -atanpi(x) - constexpr float16 TEST_VALS[] = {0.1f16, 0.25f16, 0.5f16, 0.75f16, - 1.0f16, 1.5f16, 2.0f16, 5.0f16, - 10.0f16, 50.0f16, 100.0f16, 1000.0f16}; + constexpr array TEST_VALS = { + 0.1f16, 0.25f16, 0.5f16, 0.75f16, 1.0f16, 1.5f16, + 2.0f16, 5.0f16, 10.0f16, 50.0f16, 100.0f16, 1000.0f16}; for (float16 x : TEST_VALS) { FPBits neg_x_bits(x); From c5493aae7f8e07c14b067da41fa012c732f71cde Mon Sep 17 00:00:00 2001 From: hulxv Date: Tue, 2 Sep 2025 20:13:32 +0300 Subject: [PATCH 20/20] enhancements --- libc/src/math/generic/atanpif16.cpp | 35 ++++++++++++++--------------- libc/utils/MPFRWrapper/MPCommon.cpp | 4 ++-- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/libc/src/math/generic/atanpif16.cpp b/libc/src/math/generic/atanpif16.cpp index 4db8be09bfd27..c54087c7165fe 100644 --- a/libc/src/math/generic/atanpif16.cpp +++ b/libc/src/math/generic/atanpif16.cpp @@ -31,7 +31,7 @@ namespace LIBC_NAMESPACE_DECL { // 0.0454728408833987*x**7 + 0.0353677651315323*x**9 - 0.0289372623803446*x**11 // + 0.0244853758602916*x**13 - 0.0212206590789194*x**15 + O(x**17) // -// We will assign this 19-degree Taylor polynomial as g(x). This polynomial +// We will assign this degree-15 Taylor polynomial as g(x). This polynomial // approximation is accurate for arctan(x)/pi when |x| is in the range [0, 0.5]. // // @@ -97,21 +97,20 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { if (LIBC_UNLIKELY(x_abs == 1.0)) return signed_result(0.25); - // polynomial coefficients for atan(x)/pi taylor series - // generated using sympy: series(atan(x)/pi, x, 0, 17) - constexpr double POLY_COEFFS[] = { - 0x1.45f306dc9c889p-2, // x^1: 1/pi - -0x1.b2995e7b7b60bp-4, // x^3: -1/(3*pi) - 0x1.04c26be3b06ccp-4, // x^5: 1/(5*pi) - -0x1.7483758e69c08p-5, // x^7: -1/(7*pi) - 0x1.21bb945252403p-5, // x^9: 1/(9*pi) - -0x1.da1bace3cc68ep-6, // x^11: -1/(11*pi) - 0x1.912b1c2336cf2p-6, // x^13: 1/(13*pi) - -0x1.5bade52f95e7p-6, // x^15: -1/(15*pi) - }; - // evaluate atan(x)/pi using polynomial approximation, valid for |x| <= 0.5 constexpr auto atanpi_eval = [](double x) -> double { + // polynomial coefficients for atan(x)/pi taylor series + // generated using sympy: series(atan(x)/pi, x, 0, 17) + constexpr static double POLY_COEFFS[] = { + 0x1.45f306dc9c889p-2, // x^1: 1/pi + -0x1.b2995e7b7b60bp-4, // x^3: -1/(3*pi) + 0x1.04c26be3b06ccp-4, // x^5: 1/(5*pi) + -0x1.7483758e69c08p-5, // x^7: -1/(7*pi) + 0x1.21bb945252403p-5, // x^9: 1/(9*pi) + -0x1.da1bace3cc68ep-6, // x^11: -1/(11*pi) + 0x1.912b1c2336cf2p-6, // x^13: 1/(13*pi) + -0x1.5bade52f95e7p-6, // x^15: -1/(15*pi) + }; double x_sq = x * x; return x * fputil::polyeval(x_sq, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2], POLY_COEFFS[3], POLY_COEFFS[4], @@ -128,8 +127,8 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2))) // so atanpi(x) = 2 * atanpi(x') where x' = x / (1 + sqrt(1 + x^2)) if (x_abs <= 1.0) { - double x2 = x_abs * x_abs; - double sqrt_term = fputil::sqrt(1.0 + x2); + double x_abs_sq = x_abs * x_abs; + double sqrt_term = fputil::sqrt(1.0 + x_abs_sq); double x_prime = x_abs / (1.0 + sqrt_term); double result = 2.0 * atanpi_eval(x_prime); return signed_result(result); @@ -143,8 +142,8 @@ LLVM_LIBC_FUNCTION(float16, atanpif16, (float16 x)) { // if 1/|x| > 0.5, we need to apply Case 2 transformation to 1/|x| if (x_recip > 0.5) { - double x_sq_recip = x_recip * x_recip; - double sqrt_term = fputil::sqrt(1.0 + x_sq_recip); + double x_recip_sq = x_recip * x_recip; + double sqrt_term = fputil::sqrt(1.0 + x_recip_sq); double x_prime = x_recip / (1.0 + sqrt_term); result = fputil::multiply_add(-2.0, atanpi_eval(x_prime), 0.5); } else { diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp index 8a164b8dc25ad..1255559ebe115 100644 --- a/libc/utils/MPFRWrapper/MPCommon.cpp +++ b/libc/utils/MPFRWrapper/MPCommon.cpp @@ -129,9 +129,9 @@ MPFRNumber MPFRNumber::atanpi() const { mpfr_atanpi(result.value, value, mpfr_rounding); return result; #else - MPFRNumber value_atan(0.0, 1280); + MPFRNumber value_atan(0.0, mpfr_precision * 3); mpfr_atan(value_atan.value, value, MPFR_RNDN); - MPFRNumber value_pi(0.0, 1280); + MPFRNumber value_pi(0.0, mpfr_precision * 3); mpfr_const_pi(value_pi.value, MPFR_RNDN); mpfr_div(result.value, value_atan.value, value_pi.value, mpfr_rounding); return result;