-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
improvements to accuracy/performance for float^integer #24500
Conversation
CI failures seem unrelated. |
Ping @StefanKarpinski. |
Looks good to me but I'm not sure I'm the best person to review this. Maybe @vtjnash for the LLVM bit and @simonbyrne for the math bit? |
base/intfuncs.jl
Outdated
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{0}) = one(x) | ||
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{1}) = x | ||
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{2}) = x*x | ||
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{3}) = x*x*x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth adding @inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{-1}) = 1/x
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these ambiguous? LLVM already knows about how to do this rewrite, when it can show that it won't cause accuracy issues. That at least seemed to be the conclusion in #19890 (otherwise, I would have also just altered the flag to let LLVM know that it was allowed to do this rewrite).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without these methods, literal_pow(::typeof(^), x::AbstractFloat, ::Val{p})
is ambiguous with literal_pow(::typeof(^), x::HWNumber, ::Val{2})
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@simonbyrne, that couldn't hurt, I guess — might as well add it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vtjnash, actually, it seems like there is no longer an ambiguity — there used to be an ambiguity when I was defining literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{p})
, but it looks like it may be fine now that it is AbstractFloat
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, ok. It still seems unnecessary to be defining a special function overlay to be doing something that LLVM is doing already (e.g., it already rewrites pow(x, 2)
as x*x
whenever possible). The same is true of -1
method proposed above: that optimization is already implemented transparently in the backend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LLVM only does that conversion for types that it knows about. e.g. it won't do it for Complex{Float64}
or DecimalFloat32
.
base/intfuncs.jl
Outdated
@@ -234,6 +234,15 @@ const HWNumber = Union{HWReal, Complex{<:HWReal}, Rational{<:HWReal}} | |||
@inline literal_pow(::typeof(^), x::HWNumber, ::Val{2}) = x*x | |||
@inline literal_pow(::typeof(^), x::HWNumber, ::Val{3}) = x*x*x | |||
|
|||
# don't use the inv(x) transformation here since x^p is slightly more accurate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like you should have to opt-in to getting a less accurate answer that violates referential transparency, rather than opt-out of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For most types, it's not less accurate. For most floating-point-based types (complex numbers, matrices, etc.), negative integer powers are already computed by inv(x)^-n
. And for many other types (e.g. Int
), negative literal powers wouldn't be defined at all without this transformation.
Can we not re-litigate the whole literal_pow
debate in this PR? The question is whether this PR is an improvement on the current literal_pow
rules.
base/intfuncs.jl
Outdated
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{0}) = one(x) | ||
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{1}) = x | ||
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{2}) = x*x | ||
@inline literal_pow(::typeof(^), x::Union{Float32,Float64}, ::Val{3}) = x*x*x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these ambiguous? LLVM already knows about how to do this rewrite, when it can show that it won't cause accuracy issues. That at least seemed to be the conclusion in #19890 (otherwise, I would have also just altered the flag to let LLVM know that it was allowed to do this rewrite).
Bump. |
Any chance of merging this? It seems like a strict improvement over the current situation, and CI passes except for the usual AppVeyor hiccups. |
master build failed after this PR merged: Error in testset numbers:
Test Failed at /home/julia/ci/worker/11rel-amd64/build/test/numbers.jl:2971
Expression: 0.09496527f0 ^ -2 === 110.88438f0
Evaluated: 110.884384f0 === 110.88438f0 seems only happened on amd64 build Ref: |
Should have rerun CI here since it was over 2 weeks since the last time. |
Sorry, my bad. |
So what do we do? Quick revert or live with it until someone fixes it? |
@stevengj – do you think you could fix this soon or should I revert this? |
This reverts commit 8fa23ed.
Here's the revert PR: #24930 |
Revert "improvements to accuracy/performance for float^integer (#24500)"
I don't really understand why there would be a problem with the LLVM intrinsics here. The |
I'm guessing that the code is perfectly fine, but that (Is it something about extended-precision mode on Linux?) |
…Lang#24500)" This reverts commit 8fa23ed.
This PR makes a few improvements to accuracy and/or performance for
float^integer
exponentiation.Float64^integer
andFloat32^integer
no longer check for DomainErrors, since these can only occur for fractional powers (make x^-n equivalent to inv(x)^n for literal n #24240 (comment)). This seems to greatly improve performance in some cases (by a factor of 20+) on my machine, and the performance advantage ofinv(x)^n
overx^-n
seems to be mostly gone.float^-n
no longer uses theinv(x)^n
fallback for literaln
, since that degrades accuracy slightly (make x^-n equivalent to inv(x)^n for literal n #24240 (comment))