From f2af6d720f92605c1c764ab2305c02d70f6d9bb2 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 23 Dec 2024 19:11:34 -0500 Subject: [PATCH] AK: Implement atan2() in terms of atan() on non-x86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit atan() isn't implemented yet on non-x86, so this isn't super useful yet. But it does handle a couple corner cases correctly already, and those are even enough to make all the atan2 tests in Tests/LibC/TestMath.cpp pass 🙃 --- AK/Math.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/AK/Math.h b/AK/Math.h index 11c39b64e226df..d03137b436efd6 100644 --- a/AK/Math.h +++ b/AK/Math.h @@ -799,11 +799,65 @@ constexpr T atan2(T y, T x) : "st(1)"); return ret; #else -# if defined(AK_OS_SERENITY) - // TODO: Add implementation for this function. - TODO(); -# endif - return __builtin_atan2(y, x); + if (__builtin_isnan(y)) + return y; + if (__builtin_isnan(x)) + return x; + + // SPECIAL VALUES + // atan2(±0, -0) returns ±pi. + if (y == 0 && x == 0 && signbit(x)) + return copysign(Pi, y); + + // atan2(±0, +0) returns ±0. + if (y == 0 && x == 0 && !signbit(x)) + return y; + + // atan2(±0, x) returns ±pi for x < 0. + if (y == 0 && x < 0) + return copysign(Pi, y); + + // atan2(±0, x) returns ±0 for x > 0. + if (y == 0 && x > 0) + return y; + + // atan2(y, ±0) returns +pi/2 for y > 0. + if (y > 0 && x == 0) + return Pi / 2; + + // atan2(y, ±0) returns -pi/2 for y < 0. + if (y < 0 && x == 0) + return -Pi / 2; + + // atan2(±y, -infinity) returns ±pi for finite y > 0. + if (!__builtin_isinf(y) && y > 0 && __builtin_isinf(x) && signbit(x)) + return copysign(Pi, y); + + // atan2(±y, +infinity) returns ±0 for finite y > 0. + if (!__builtin_isinf(y) && y > 0 && __builtin_isinf(x) && !signbit(x)) + return copysign(static_cast(0), y); + + // atan2(±infinity, x) returns ±pi/2 for finite x. + if (__builtin_isinf(y) && !__builtin_isinf(x)) + return copysign(Pi / 2, y); + + // atan2(±infinity, -infinity) returns ±3*pi/4. + if (__builtin_isinf(y) && __builtin_isinf(x) && signbit(x)) + return copysign(3 * Pi / 4, y); + + // atan2(±infinity, +infinity) returns ±pi/4. + if (__builtin_isinf(y) && __builtin_isinf(x) && !signbit(x)) + return copysign(Pi / 4, y); + + // Check quadrant, going counterclockwise. + if (y > 0 && x > 0) + return atan(y / x); + if (y > 0 && x < 0) + return atan(y / x) + Pi; + if (y < 0 && x < 0) + return atan(y / x) - Pi; + // y < 0 && x > 0 + return atan(y / x); #endif }