Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a fourthroot function with unicode symbol ∜ #48899

Merged
merged 5 commits into from
Mar 9, 2023

Conversation

tomchor
Copy link
Contributor

@tomchor tomchor commented Mar 5, 2023

I noticed that there's a unicode symbol for the fourth root (∜) but there's no fourth root defined in Base. This PR adds a fourthroot() function that simply applies sqrt() twice in a row and defines ∜ = fourthroot.

In my opinion two advantages of this are that

  1. We don't let a perfectly good unicode symbol go to waste :)
  2. This would probably avoid some naive users obtaining the fourth root as x^(1/4), which is less efficient than this new function:
julia> @btime (rand(Float64, 10000).^(1/4));
  285.677 μs (4 allocations: 156.34 KiB)

julia> @btime sqrt.(sqrt.(rand(Float64, 10000)));
  81.906 μs (4 allocations: 156.34 KiB)

base/math.jl Outdated Show resolved Hide resolved
@oscardssmith
Copy link
Member

Looks good to me! For reference, worst case accuracy on Float32 inputs is 0.853 ULP.

base/math.jl Outdated Show resolved Hide resolved
@N5N3 N5N3 added maths Mathematical functions needs tests Unit tests are required for this change needs news A NEWS entry is required for this change labels Mar 6, 2023
@N5N3 N5N3 removed needs tests Unit tests are required for this change needs news A NEWS entry is required for this change labels Mar 7, 2023
@tomchor tomchor requested a review from oscardssmith March 7, 2023 14:53
@tomchor
Copy link
Contributor Author

tomchor commented Mar 9, 2023

Is there anything else I need to do to merge this PR? (Sorry, this is my first time contributing to Julia)

@oscardssmith oscardssmith merged commit 78ec99b into JuliaLang:master Mar 9, 2023
@oscardssmith
Copy link
Member

Thanks for the contribution!

@tomchor
Copy link
Contributor Author

tomchor commented Mar 9, 2023

Thanks for the contribution!

No problem! Hopefully I can contribute more in the future :)

@PallHaraldsson
Copy link
Contributor

PallHaraldsson commented Apr 5, 2023

It is faster, but can it be done even faster? And more importantly, would it be more accurate to do some other way, than twice sqrt? Is the version in the PR at least as accurate as to power of 1/4?

I discovered at least 4th power is 6.7x slower over 3 almost 4 times slower than it needs to be (a separate issue to file?), but I'm not sure it helps me speed up 1/4th power:

pow4c(x) = (x*x)^2
pow4(x) = x*x*x*x
pow4b(x) = x^4

julia> A = rand(Float64, 10000);

julia> @btime (pow4c.(A));
  11.172 μs (4 allocations: 78.20 KiB)

julia> @btime (pow4.(A));
  25.074 μs (4 allocations: 156.34 KiB)

julia> @btime (pow4b.(A));
  75.634 μs (4 allocations: 78.20 KiB)

julia> @btime (A.^4);  # why not as fast? A benchmark artefact? $4 didn't help. Nor @btime @fastmath (A.^$4);
  77.206 μs (8 allocations: 78.33 KiB)
  <s>94.618 μs (4 allocations: 156.34 KiB)</s> timing before I used A, rather with rand.

@oscardssmith
Copy link
Member

I believe it can not be done faster (although that is rather difficult to bemchmark). It is less accurate than x^(1/4) but that's not surprising (0.5 ULP for x^.25f0 vs 0.853 on Float32, 0.55 vs 0.85ish on Float64).

x*x*x*x is dramatically less accurate than x^4 (2 ULP vs 0.5 ULP for Float32, 2 vs 0.55 for Float64). (x*x)^2 will be both faster and more accurate (1.9 ULP). The slowness here is that we are compensating the math to make it fast.

@PallHaraldsson
Copy link
Contributor

PallHaraldsson commented Apr 5, 2023

julia> fourth_root(x) = ℯ^(log(x)*0.25)  # strangely 2^(log2(x)*0.25) is even slower despite "Another instruction, fldl2e, stores log2(e) in the floating point stack." Reason likely I don't see that instruction used.

is 4.7 times slower, so I give up. Unless some faster log is possible? And FYI, I added the faster pow4c above in my edited comment, seems it should be the default for such (literal) power in Julia?!

@oscardssmith
Copy link
Member

The one thing that might be faster is some bithacks to get an approximate fourth route and use newton iterations to hit the tolerance, but I doubt that will be quicker due to the required divisions.

2 ULP is above our normal error tolerance. We could probably make @fastmath powers use uncompensated power by squaring though.

Xnartharax pushed a commit to Xnartharax/julia that referenced this pull request Apr 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maths Mathematical functions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants