Skip to content

AK: Make atan() more precise and faster on non-x86#26691

Merged
nico merged 2 commits intoSerenityOS:masterfrom
nico:ak-math-asin-atan
Apr 2, 2026
Merged

AK: Make atan() more precise and faster on non-x86#26691
nico merged 2 commits intoSerenityOS:masterfrom
nico:ak-math-asin-atan

Conversation

@nico
Copy link
Copy Markdown
Contributor

@nico nico commented Apr 2, 2026

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:

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().)

nico added 2 commits April 1, 2026 23:03
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().)
@github-actions github-actions bot added the 👀 pr-needs-review PR needs review from a maintainer or community member label Apr 2, 2026
@nico
Copy link
Copy Markdown
Contributor Author

nico commented Apr 2, 2026

Here's the atan precision test program, similar to the programs over in #26674:
test-ak-atan.cpp

@nico nico mentioned this pull request Apr 2, 2026
18 tasks
Copy link
Copy Markdown
Member

@LucasChollet LucasChollet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines +902 to +906
if (value < 0)
return -atan(-value);

if (value > 1)
return Pi<T> / 2 - atan(1 / value);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably faster to not refuse here either, yes. But I leave that for the future 🙂

@nico nico merged commit 3938f7f into SerenityOS:master Apr 2, 2026
16 checks passed
@nico nico deleted the ak-math-asin-atan branch April 2, 2026 14:07
@github-actions github-actions bot removed the 👀 pr-needs-review PR needs review from a maintainer or community member label Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants