AK: Make atan() more precise and faster on non-x86#26691
Merged
nico merged 2 commits intoSerenityOS:masterfrom Apr 2, 2026
Merged
AK: Make atan() more precise and faster on non-x86#26691nico merged 2 commits intoSerenityOS:masterfrom
nico merged 2 commits intoSerenityOS:masterfrom
Conversation
On my system, with macOS system libm (including the existing
sin(), cos() perf tests):
% Build/lagom/bin/TestAKMath
...
Running benchmark 'bench_trig_cos'.
Completed benchmark 'bench_trig_cos' in 66ms
Running benchmark 'bench_trig_cosf'.
Completed benchmark 'bench_trig_cosf' in 58ms
Running benchmark 'bench_trig_sin'.
Completed benchmark 'bench_trig_sin' in 54ms
Running benchmark 'bench_trig_sinf'.
Completed benchmark 'bench_trig_sinf' in 58ms
Running benchmark 'bench_trig_tan'.
Completed benchmark 'bench_trig_tan' in 75ms
Running benchmark 'bench_trig_tanf'.
Completed benchmark 'bench_trig_tanf' in 82ms
Running benchmark 'bench_trig_acos'.
Completed benchmark 'bench_trig_acos' in 11ms
Running benchmark 'bench_trig_acosf'.
Completed benchmark 'bench_trig_acosf' in 10ms
Running benchmark 'bench_trig_asin'.
Completed benchmark 'bench_trig_asin' in 11ms
Running benchmark 'bench_trig_asinf'.
Completed benchmark 'bench_trig_asinf' in 11ms
Running benchmark 'bench_trig_atan'.
Completed benchmark 'bench_trig_atan' in 60ms
Running benchmark 'bench_trig_atanf'.
Completed benchmark 'bench_trig_atanf' in 63ms
With serenity libm (SerenityOS#26662):
% Build/lagom/bin/TestAKMath
...
Completed benchmark 'bench_trig_cos' in 87ms
Running benchmark 'bench_trig_cosf'.
Completed benchmark 'bench_trig_cosf' in 65ms
Running benchmark 'bench_trig_sin'.
Completed benchmark 'bench_trig_sin' in 75ms
Running benchmark 'bench_trig_sinf'.
Completed benchmark 'bench_trig_sinf' in 67ms
Running benchmark 'bench_trig_tan'.
Completed benchmark 'bench_trig_tan' in 184ms
Running benchmark 'bench_trig_tanf'.
Completed benchmark 'bench_trig_tanf' in 163ms
Running benchmark 'bench_trig_acos'.
Completed benchmark 'bench_trig_acos' in 10ms
Running benchmark 'bench_trig_acosf'.
Completed benchmark 'bench_trig_acosf' in 10ms
Running benchmark 'bench_trig_asin'.
Completed benchmark 'bench_trig_asin' in 10ms
Running benchmark 'bench_trig_asinf'.
Completed benchmark 'bench_trig_asinf' in 10ms
Running benchmark 'bench_trig_atan'.
Completed benchmark 'bench_trig_atan' in 176ms
Running benchmark 'bench_trig_atanf'.
Completed benchmark 'bench_trig_atanf' in 184ms
Instead of calling asin(), approximate atan() directly. Takes the biggest error of atan() over 0..2*pi (which is an arbitrary interval, given that atan()'s domain is all reals) from 7.15256e-07 to 1.19209e-07. That's enough to make TestPDF pass when run inside serenity (part of SerenityOS#25934). It also takes bench_trig_atan* from: Running benchmark 'bench_trig_atan'. Completed benchmark 'bench_trig_atan' in 181ms Running benchmark 'bench_trig_atanf'. Completed benchmark 'bench_trig_atanf' in 188ms to Running benchmark 'bench_trig_atan'. Completed benchmark 'bench_trig_atan' in 123ms Running benchmark 'bench_trig_atanf'. Completed benchmark 'bench_trig_atanf' in 72ms See the PR adding this commit for details on the program that computed the precision. (I first tried making asin() more precise, but even with a more precise asin(), atan()'s error never went below 7.15256e-07 when it was implemented in terms of asin(). Possibly because larger values all map to arguments close to 1.0 for asin().)
Contributor
Author
|
Here's the atan precision test program, similar to the programs over in #26674: |
spholz
reviewed
Apr 2, 2026
Comment on lines
+902
to
+906
| if (value < 0) | ||
| return -atan(-value); | ||
|
|
||
| if (value > 1) | ||
| return Pi<T> / 2 - atan(1 / value); |
Member
There was a problem hiding this comment.
You recently removed recursion from sin()/cos() to make it faster. Does recursion not cause any issues here?
(Or do you want to do this in a follow-up?)
Contributor
Author
There was a problem hiding this comment.
It's probably faster to not refuse here either, yes. But I leave that for the future 🙂
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Instead of calling asin(), approximate atan() directly.
Takes the biggest error of atan() over 0..2*pi (which is
an arbitrary interval, given that atan()'s domain is all
reals) from 7.15256e-07 to 1.19209e-07. That's enough to
make TestPDF pass when run inside serenity (part of #25934).
It also takes bench_trig_atan* from:
to
See the PR adding this commit for details on the program that
computed the precision.
(I first tried making asin() more precise, but even with a more
precise asin(), atan()'s error never went below 7.15256e-07 when
it was implemented in terms of asin(). Possibly because larger
values all map to arguments close to 1.0 for asin().)