//===-- Double-precision atan2 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/atan2.h" #include "inv_trigf_utils.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PolyEval.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/FPUtil/rounding_mode.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY namespace LIBC_NAMESPACE_DECL { namespace { DoubleDouble; // atan(i/64) with i = 0..64, generated by Sollya with: // > for i from 0 to 64 do { // a = round(atan(i/64), D, RN); // b = round(atan(i/64) - a, D, RN); // print("{", b, ",", a, "},"); // }; constexpr fputil::DoubleDouble ATAN_I[65] = …; // Approximate atan(x) for |x| <= 2^-7. // Using degree-9 Taylor polynomial: // P = x - x^3/3 + x^5/5 -x^7/7 + x^9/9; // Then the absolute error is bounded by: // |atan(x) - P(x)| < |x|^11/11 < 2^(-7*11) / 11 < 2^-80. // And the relative error is bounded by: // |(atan(x) - P(x))/atan(x)| < |x|^10 / 10 < 2^-73. // For x = x_hi + x_lo, fully expand the polynomial and drop any terms less than // ulp(x_hi^3 / 3) gives us: // P(x) ~ x_hi - x_hi^3/3 + x_hi^5/5 - x_hi^7/7 + x_hi^9/9 + // + x_lo * (1 - x_hi^2 + x_hi^4) DoubleDouble atan_eval(const DoubleDouble &x) { … } } // anonymous namespace // 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)) { … } } // namespace LIBC_NAMESPACE_DECL