From dbc5b05b7a6520056ebbc27c7e9167e3b131260c Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Thu, 15 Apr 2021 18:42:41 +0430 Subject: [PATCH] LibM: Use fptan/fpatan instead of approximating atan2/tan The previous versions were very inaccurate, and sometimes wrong. --- Userland/Libraries/LibM/math.cpp | 22 +++++++++++++++------- Userland/Tests/LibM/test-math.cpp | 9 +++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibM/math.cpp b/Userland/Libraries/LibM/math.cpp index c3892479f2..dc162a5873 100644 --- a/Userland/Libraries/LibM/math.cpp +++ b/Userland/Libraries/LibM/math.cpp @@ -495,7 +495,7 @@ float tanhf(float x) NOEXCEPT return (float)tanhl(x); } -static long double ampsin(long double angle) NOEXCEPT +[[maybe_unused]] static long double ampsin(long double angle) NOEXCEPT { long double looped_angle = fmodl(M_PI + angle, M_TAU) - M_PI; long double looped_angle_squared = looped_angle * looped_angle; @@ -514,7 +514,13 @@ static long double ampsin(long double angle) NOEXCEPT long double tanl(long double angle) NOEXCEPT { - return ampsin(angle) / ampsin(M_PI_2 + angle); + long double ret = 0.0, one; + __asm__( + "fptan" + : "=t"(one), "=u"(ret) + : "0"(angle)); + + return ret; } double tan(double angle) NOEXCEPT @@ -721,8 +727,6 @@ float coshf(float x) NOEXCEPT long double atan2l(long double y, long double x) NOEXCEPT { - if (x > 0) - return atanl(y / x); if (x == 0) { if (y > 0) return M_PI_2; @@ -730,9 +734,13 @@ long double atan2l(long double y, long double x) NOEXCEPT return -M_PI_2; return 0; } - if (y >= 0) - return atanl(y / x) + M_PI; - return atanl(y / x) - M_PI; + + long double result = 0; //atanl(y / x); + __asm__("fpatan" + : "=t"(result) + : "0"(x), "u"(y) + : "st(1)"); + return result; } double atan2(double y, double x) NOEXCEPT diff --git a/Userland/Tests/LibM/test-math.cpp b/Userland/Tests/LibM/test-math.cpp index 10744e24f3..e5b790e3ca 100644 --- a/Userland/Tests/LibM/test-math.cpp +++ b/Userland/Tests/LibM/test-math.cpp @@ -29,6 +29,15 @@ #include #include +TEST_CASE(atan2) +{ + EXPECT_APPROXIMATE(atan2(-1, -0.0e0), -M_PI_2); + EXPECT_APPROXIMATE(atan2(-0.0e0, -1), -M_PI); + EXPECT_APPROXIMATE(atan2(0.0e0, -1), M_PI); + EXPECT_APPROXIMATE(atan2(-0.0e0, 1), -0.0e0); + EXPECT_APPROXIMATE(atan2(0.0e0, 1), 0.0e0); +} + TEST_CASE(trig) { EXPECT_APPROXIMATE(sin(1234), 0.601927);