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 }