https://github.com/bassiounix updated https://github.com/llvm/llvm-project/pull/150968
>From d411e7849f1cf9d0b1f31def4bdd2b126363bd6a Mon Sep 17 00:00:00 2001 From: bassiounix <muhammad.m.bassio...@gmail.com> Date: Mon, 28 Jul 2025 18:07:19 +0300 Subject: [PATCH] [libc][math] Refactor atan2 implementation to header-only in src/__support/math folder. --- libc/shared/math.h | 1 + libc/shared/math/atan2.h | 23 ++ libc/src/__support/math/CMakeLists.txt | 20 +- libc/src/__support/math/atan2.h | 209 ++++++++++++++++++ libc/src/math/generic/CMakeLists.txt | 8 +- libc/src/math/generic/atan2.cpp | 187 +--------------- libc/test/shared/CMakeLists.txt | 1 + libc/test/shared/shared_math_test.cpp | 1 + .../llvm-project-overlay/libc/BUILD.bazel | 14 +- 9 files changed, 266 insertions(+), 198 deletions(-) create mode 100644 libc/shared/math/atan2.h create mode 100644 libc/src/__support/math/atan2.h diff --git a/libc/shared/math.h b/libc/shared/math.h index bcbe0de56170a..0605d918eb2af 100644 --- a/libc/shared/math.h +++ b/libc/shared/math.h @@ -23,6 +23,7 @@ #include "math/asinhf.h" #include "math/asinhf16.h" #include "math/atan.h" +#include "math/atan2.h" #include "math/atanf.h" #include "math/atanf16.h" #include "math/erff.h" diff --git a/libc/shared/math/atan2.h b/libc/shared/math/atan2.h new file mode 100644 index 0000000000000..894110838817c --- /dev/null +++ b/libc/shared/math/atan2.h @@ -0,0 +1,23 @@ +//===-- Shared atan2 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_ATAN2_H +#define LLVM_LIBC_SHARED_MATH_ATAN2_H + +#include "shared/libc_common.h" +#include "src/__support/math/atan2.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using math::atan2; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_ATAN2_H diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt index 04cbd3fd1cc01..bbb07b62552f6 100644 --- a/libc/src/__support/math/CMakeLists.txt +++ b/libc/src/__support/math/CMakeLists.txt @@ -158,7 +158,7 @@ add_header_library( asinhf16 HDRS asinhf16.h -DEPENDS + DEPENDS .acoshf_utils libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits @@ -176,7 +176,7 @@ add_header_library( atan_utils HDRS atan_utils.h -DEPENDS + DEPENDS libc.src.__support.integer_literals libc.src.__support.FPUtil.double_double libc.src.__support.FPUtil.dyadic_float @@ -189,7 +189,21 @@ add_header_library( atan HDRS atan.h -DEPENDS + 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( + atan2 + HDRS + atan2.h + DEPENDS .atan_utils libc.src.__support.FPUtil.double_double libc.src.__support.FPUtil.fenv_impl diff --git a/libc/src/__support/math/atan2.h b/libc/src/__support/math/atan2.h new file mode 100644 index 0000000000000..90ed926c8d75f --- /dev/null +++ b/libc/src/__support/math/atan2.h @@ -0,0 +1,209 @@ +//===-- Implementation header for atan2 -------------------------*- 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_ATAN2_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2_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 { + +// There are several range reduction steps we can take for atan2(y, x) as +// follow: + +// * Range reduction 1: signness +// atan2(y, x) will return a number between -PI and PI representing the angle +// forming by the 0x axis and the vector (x, y) on the 0xy-plane. +// In particular, we have that: +// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant) +// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant) +// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant) +// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant) +// Since atan function is odd, we can use the formula: +// atan(-u) = -atan(u) +// to adjust the above conditions a bit further: +// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant) +// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant) +// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant) +// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant) +// Which can be simplified to: +// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0 +// = sign(y) * (pi - atan( |y|/|x| )) if x < 0 + +// * Range reduction 2: reciprocal +// Now that the argument inside atan is positive, we can use the formula: +// atan(1/x) = pi/2 - atan(x) +// to make the argument inside atan <= 1 as follow: +// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x +// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y| +// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x +// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y| + +// * Range reduction 3: look up table. +// After the previous two range reduction steps, we reduce the problem to +// compute atan(u) with 0 <= u <= 1, or to be precise: +// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|). +// An accurate polynomial approximation for the whole [0, 1] input range will +// require a very large degree. To make it more efficient, we reduce the input +// range further by finding an integer idx such that: +// | n/d - idx/64 | <= 1/128. +// In particular, +// idx := round(2^6 * n/d) +// Then for the fast pass, we find a polynomial approximation for: +// atan( n/d ) ~ atan( idx/64 ) + (n/d - idx/64) * Q(n/d - idx/64) +// For the accurate pass, we use the addition formula: +// atan( n/d ) - atan( idx/64 ) = atan( (n/d - idx/64)/(1 + (n*idx)/(64*d)) ) +// = atan( (n - d*(idx/64))/(d + n*(idx/64)) ) +// And for the fast pass, we use degree-9 Taylor polynomial to compute the RHS: +// atan(u) ~ P(u) = u - u^3/3 + u^5/5 - u^7/7 + u^9/9 +// with absolute errors bounded by: +// |atan(u) - P(u)| < |u|^11 / 11 < 2^-80 +// and relative errors bounded by: +// |(atan(u) - P(u)) / P(u)| < u^10 / 11 < 2^-73. + +LIBC_INLINE static constexpr double atan2(double y, double x) { + using namespace atan_internal; + using FPBits = fputil::FPBits<double>; + + constexpr double IS_NEG[2] = {1.0, -1.0}; + constexpr DoubleDouble ZERO = {0.0, 0.0}; + constexpr DoubleDouble MZERO = {-0.0, -0.0}; + constexpr DoubleDouble PI = {0x1.1a62633145c07p-53, 0x1.921fb54442d18p+1}; + constexpr DoubleDouble MPI = {-0x1.1a62633145c07p-53, -0x1.921fb54442d18p+1}; + constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54, + 0x1.921fb54442d18p0}; + constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54, + -0x1.921fb54442d18p0}; + constexpr DoubleDouble PI_OVER_4 = {0x1.1a62633145c07p-55, + 0x1.921fb54442d18p-1}; + constexpr DoubleDouble THREE_PI_OVER_4 = {0x1.a79394c9e8a0ap-54, + 0x1.2d97c7f3321d2p+1}; + // Adjustment for constant term: + // CONST_ADJ[x_sign][y_sign][recip] + constexpr DoubleDouble CONST_ADJ[2][2][2] = { + {{ZERO, MPI_OVER_2}, {MZERO, MPI_OVER_2}}, + {{MPI, PI_OVER_2}, {MPI, PI_OVER_2}}}; + + FPBits x_bits(x), y_bits(y); + bool x_sign = x_bits.sign().is_neg(); + bool y_sign = y_bits.sign().is_neg(); + x_bits = x_bits.abs(); + y_bits = y_bits.abs(); + uint64_t x_abs = x_bits.uintval(); + uint64_t y_abs = y_bits.uintval(); + bool recip = x_abs < y_abs; + uint64_t min_abs = recip ? x_abs : y_abs; + uint64_t max_abs = !recip ? x_abs : y_abs; + unsigned min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN); + unsigned max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN); + + double num = FPBits(min_abs).get_val(); + double den = FPBits(max_abs).get_val(); + + // Check for exceptional cases, whether inputs are 0, inf, nan, or close to + // overflow, or close to underflow. + if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) { + if (x_bits.is_nan() || y_bits.is_nan()) { + if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan()) + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1); + unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1); + + // Exceptional cases: + // EXCEPT[y_except][x_except][x_is_neg] + // with x_except & y_except: + // 0: zero + // 1: finite, non-zero + // 2: infinity + constexpr DoubleDouble EXCEPTS[3][3][2] = { + {{ZERO, PI}, {ZERO, PI}, {ZERO, PI}}, + {{PI_OVER_2, PI_OVER_2}, {ZERO, ZERO}, {ZERO, PI}}, + {{PI_OVER_2, PI_OVER_2}, + {PI_OVER_2, PI_OVER_2}, + {PI_OVER_4, THREE_PI_OVER_4}}, + }; + + if ((x_except != 1) || (y_except != 1)) { + DoubleDouble r = EXCEPTS[y_except][x_except][x_sign]; + return fputil::multiply_add(IS_NEG[y_sign], r.hi, IS_NEG[y_sign] * r.lo); + } + bool scale_up = min_exp < 128U; + bool scale_down = max_exp > 0x7ffU - 128U; + // At least one input is denormal, multiply both numerator and denominator + // by some large enough power of 2 to normalize denormal inputs. + if (scale_up) { + num *= 0x1.0p64; + if (!scale_down) + den *= 0x1.0p64; + } else if (scale_down) { + den *= 0x1.0p-64; + if (!scale_up) + num *= 0x1.0p-64; + } + + min_abs = FPBits(num).uintval(); + max_abs = FPBits(den).uintval(); + min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN); + max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN); + } + + double final_sign = IS_NEG[(x_sign != y_sign) != recip]; + DoubleDouble const_term = CONST_ADJ[x_sign][y_sign][recip]; + unsigned exp_diff = max_exp - min_exp; + // We have the following bound for normalized n and d: + // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1). + if (LIBC_UNLIKELY(exp_diff > 54)) { + return fputil::multiply_add(final_sign, const_term.hi, + final_sign * (const_term.lo + num / den)); + } + + double k = fputil::nearest_integer(64.0 * num / den); + unsigned idx = static_cast<unsigned>(k); + // k = idx / 64 + k *= 0x1.0p-6; + + // Range reduction: + // atan(n/d) - atan(k/64) = atan((n/d - k/64) / (1 + (n/d) * (k/64))) + // = atan((n - d * k/64)) / (d + n * k/64)) + DoubleDouble num_k = fputil::exact_mult(num, k); + DoubleDouble den_k = fputil::exact_mult(den, k); + + // num_dd = n - d * k + DoubleDouble num_dd = fputil::exact_add(num - den_k.hi, -den_k.lo); + // den_dd = d + n * k + DoubleDouble den_dd = fputil::exact_add(den, num_k.hi); + den_dd.lo += num_k.lo; + + // q = (n - d * k) / (d + n * k) + DoubleDouble q = fputil::div(num_dd, den_dd); + // p ~ atan(q) + DoubleDouble p = atan_eval(q); + + DoubleDouble r = fputil::add(const_term, fputil::add(ATAN_I[idx], p)); + r.hi *= final_sign; + r.lo *= final_sign; + + return r.hi + r.lo; +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index eae42a323fc6c..003e0655a5816 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -4079,13 +4079,7 @@ add_entrypoint_object( HDRS ../atan2.h DEPENDS - libc.src.__support.math.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_entrypoint_object( diff --git a/libc/src/math/generic/atan2.cpp b/libc/src/math/generic/atan2.cpp index 58042d3bcf721..4aaa63d077d4c 100644 --- a/libc/src/math/generic/atan2.cpp +++ b/libc/src/math/generic/atan2.cpp @@ -7,195 +7,12 @@ //===----------------------------------------------------------------------===// #include "src/math/atan2.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_utils.h" +#include "src/__support/math/atan2.h" namespace LIBC_NAMESPACE_DECL { -// There are several range reduction steps we can take for atan2(y, x) as -// follow: - -// * Range reduction 1: signness -// atan2(y, x) will return a number between -PI and PI representing the angle -// forming by the 0x axis and the vector (x, y) on the 0xy-plane. -// In particular, we have that: -// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant) -// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant) -// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant) -// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant) -// Since atan function is odd, we can use the formula: -// atan(-u) = -atan(u) -// to adjust the above conditions a bit further: -// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant) -// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant) -// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant) -// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant) -// Which can be simplified to: -// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0 -// = sign(y) * (pi - atan( |y|/|x| )) if x < 0 - -// * Range reduction 2: reciprocal -// Now that the argument inside atan is positive, we can use the formula: -// atan(1/x) = pi/2 - atan(x) -// to make the argument inside atan <= 1 as follow: -// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x -// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y| -// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x -// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y| - -// * Range reduction 3: look up table. -// After the previous two range reduction steps, we reduce the problem to -// compute atan(u) with 0 <= u <= 1, or to be precise: -// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|). -// An accurate polynomial approximation for the whole [0, 1] input range will -// require a very large degree. To make it more efficient, we reduce the input -// range further by finding an integer idx such that: -// | n/d - idx/64 | <= 1/128. -// In particular, -// idx := round(2^6 * n/d) -// Then for the fast pass, we find a polynomial approximation for: -// atan( n/d ) ~ atan( idx/64 ) + (n/d - idx/64) * Q(n/d - idx/64) -// For the accurate pass, we use the addition formula: -// atan( n/d ) - atan( idx/64 ) = atan( (n/d - idx/64)/(1 + (n*idx)/(64*d)) ) -// = atan( (n - d*(idx/64))/(d + n*(idx/64)) ) -// And for the fast pass, we use degree-9 Taylor polynomial to compute the RHS: -// atan(u) ~ P(u) = u - u^3/3 + u^5/5 - u^7/7 + u^9/9 -// with absolute errors bounded by: -// |atan(u) - P(u)| < |u|^11 / 11 < 2^-80 -// and relative errors bounded by: -// |(atan(u) - P(u)) / P(u)| < u^10 / 11 < 2^-73. - LLVM_LIBC_FUNCTION(double, atan2, (double y, double x)) { - using namespace atan_internal; - using FPBits = fputil::FPBits<double>; - - constexpr double IS_NEG[2] = {1.0, -1.0}; - constexpr DoubleDouble ZERO = {0.0, 0.0}; - constexpr DoubleDouble MZERO = {-0.0, -0.0}; - constexpr DoubleDouble PI = {0x1.1a62633145c07p-53, 0x1.921fb54442d18p+1}; - constexpr DoubleDouble MPI = {-0x1.1a62633145c07p-53, -0x1.921fb54442d18p+1}; - constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54, - 0x1.921fb54442d18p0}; - constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54, - -0x1.921fb54442d18p0}; - constexpr DoubleDouble PI_OVER_4 = {0x1.1a62633145c07p-55, - 0x1.921fb54442d18p-1}; - constexpr DoubleDouble THREE_PI_OVER_4 = {0x1.a79394c9e8a0ap-54, - 0x1.2d97c7f3321d2p+1}; - // Adjustment for constant term: - // CONST_ADJ[x_sign][y_sign][recip] - constexpr DoubleDouble CONST_ADJ[2][2][2] = { - {{ZERO, MPI_OVER_2}, {MZERO, MPI_OVER_2}}, - {{MPI, PI_OVER_2}, {MPI, PI_OVER_2}}}; - - FPBits x_bits(x), y_bits(y); - bool x_sign = x_bits.sign().is_neg(); - bool y_sign = y_bits.sign().is_neg(); - x_bits = x_bits.abs(); - y_bits = y_bits.abs(); - uint64_t x_abs = x_bits.uintval(); - uint64_t y_abs = y_bits.uintval(); - bool recip = x_abs < y_abs; - uint64_t min_abs = recip ? x_abs : y_abs; - uint64_t max_abs = !recip ? x_abs : y_abs; - unsigned min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN); - unsigned max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN); - - double num = FPBits(min_abs).get_val(); - double den = FPBits(max_abs).get_val(); - - // Check for exceptional cases, whether inputs are 0, inf, nan, or close to - // overflow, or close to underflow. - if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) { - if (x_bits.is_nan() || y_bits.is_nan()) { - if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan()) - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1); - unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1); - - // Exceptional cases: - // EXCEPT[y_except][x_except][x_is_neg] - // with x_except & y_except: - // 0: zero - // 1: finite, non-zero - // 2: infinity - constexpr DoubleDouble EXCEPTS[3][3][2] = { - {{ZERO, PI}, {ZERO, PI}, {ZERO, PI}}, - {{PI_OVER_2, PI_OVER_2}, {ZERO, ZERO}, {ZERO, PI}}, - {{PI_OVER_2, PI_OVER_2}, - {PI_OVER_2, PI_OVER_2}, - {PI_OVER_4, THREE_PI_OVER_4}}, - }; - - if ((x_except != 1) || (y_except != 1)) { - DoubleDouble r = EXCEPTS[y_except][x_except][x_sign]; - return fputil::multiply_add(IS_NEG[y_sign], r.hi, IS_NEG[y_sign] * r.lo); - } - bool scale_up = min_exp < 128U; - bool scale_down = max_exp > 0x7ffU - 128U; - // At least one input is denormal, multiply both numerator and denominator - // by some large enough power of 2 to normalize denormal inputs. - if (scale_up) { - num *= 0x1.0p64; - if (!scale_down) - den *= 0x1.0p64; - } else if (scale_down) { - den *= 0x1.0p-64; - if (!scale_up) - num *= 0x1.0p-64; - } - - min_abs = FPBits(num).uintval(); - max_abs = FPBits(den).uintval(); - min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN); - max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN); - } - - double final_sign = IS_NEG[(x_sign != y_sign) != recip]; - DoubleDouble const_term = CONST_ADJ[x_sign][y_sign][recip]; - unsigned exp_diff = max_exp - min_exp; - // We have the following bound for normalized n and d: - // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1). - if (LIBC_UNLIKELY(exp_diff > 54)) { - return fputil::multiply_add(final_sign, const_term.hi, - final_sign * (const_term.lo + num / den)); - } - - double k = fputil::nearest_integer(64.0 * num / den); - unsigned idx = static_cast<unsigned>(k); - // k = idx / 64 - k *= 0x1.0p-6; - - // Range reduction: - // atan(n/d) - atan(k/64) = atan((n/d - k/64) / (1 + (n/d) * (k/64))) - // = atan((n - d * k/64)) / (d + n * k/64)) - DoubleDouble num_k = fputil::exact_mult(num, k); - DoubleDouble den_k = fputil::exact_mult(den, k); - - // num_dd = n - d * k - DoubleDouble num_dd = fputil::exact_add(num - den_k.hi, -den_k.lo); - // den_dd = d + n * k - DoubleDouble den_dd = fputil::exact_add(den, num_k.hi); - den_dd.lo += num_k.lo; - - // q = (n - d * k) / (d + n * k) - DoubleDouble q = fputil::div(num_dd, den_dd); - // p ~ atan(q) - DoubleDouble p = atan_eval(q); - - DoubleDouble r = fputil::add(const_term, fputil::add(ATAN_I[idx], p)); - r.hi *= final_sign; - r.lo *= final_sign; - - return r.hi + r.lo; + return math::atan2(y, x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt index 2dd5bdafe24f6..4ed32d43f1c24 100644 --- a/libc/test/shared/CMakeLists.txt +++ b/libc/test/shared/CMakeLists.txt @@ -19,6 +19,7 @@ add_fp_unittest( libc.src.__support.math.asinhf libc.src.__support.math.asinhf16 libc.src.__support.math.atan + libc.src.__support.math.atan2 libc.src.__support.math.atanf libc.src.__support.math.atanf16 libc.src.__support.math.erff diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp index 2b80068f991be..cd72df46bf676 100644 --- a/libc/test/shared/shared_math_test.cpp +++ b/libc/test/shared/shared_math_test.cpp @@ -62,6 +62,7 @@ TEST(LlvmLibcSharedMathTest, AllDouble) { EXPECT_FP_EQ(0x1.921fb54442d18p+0, LIBC_NAMESPACE::shared::acos(0.0)); EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::asin(0.0)); EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::atan(0.0)); + EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::atan2(0.0, 0.0)); EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp(0.0)); EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp10(0.0)); } diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index bc0c4a55b59c6..a1d5afd4469ab 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -2274,6 +2274,16 @@ libc_support_library( ], ) +libc_support_library( + name = "__support_math_atan2", + hdrs = ["src/__support/math/atan2.h"], + deps = [ + ":__support_fputil_double_double", + ":__support_fputil_nearest_integer", + ":__support_math_atan_utils", + ], +) + libc_support_library( name = "__support_math_atanf", hdrs = ["src/__support/math/atanf.h"], @@ -2945,9 +2955,7 @@ libc_math_function( libc_math_function( name = "atan2", additional_deps = [ - ":__support_fputil_double_double", - ":__support_fputil_nearest_integer", - ":__support_math_atan_utils", + ":__support_math_atan2", ], ) _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits