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

improvements to accuracy/performance for float^integer #24500

Merged
merged 3 commits into from
Dec 5, 2017

Conversation

stevengj
Copy link
Member

@stevengj stevengj commented Nov 6, 2017

This PR makes a few improvements to accuracy and/or performance for float^integer exponentiation.

@stevengj stevengj added maths Mathematical functions performance Must go faster labels Nov 6, 2017
@stevengj stevengj requested a review from vtjnash November 6, 2017 22:13
@stevengj
Copy link
Member Author

stevengj commented Nov 7, 2017

CI failures seem unrelated.

@stevengj
Copy link
Member Author

Ping @StefanKarpinski.

@StefanKarpinski
Copy link
Member

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
Copy link
Contributor

@simonbyrne simonbyrne Nov 13, 2017

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?

Copy link
Member

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

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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
Copy link
Member

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.

Copy link
Member Author

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
Copy link
Member

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

@stevengj
Copy link
Member Author

Bump.

@stevengj
Copy link
Member Author

stevengj commented Dec 5, 2017

Any chance of merging this? It seems like a strict improvement over the current situation, and CI passes except for the usual AppVeyor hiccups.

@StefanKarpinski StefanKarpinski merged commit 8fa23ed into JuliaLang:master Dec 5, 2017
@stevengj stevengj deleted the betterfloatpows branch December 5, 2017 15:57
@iblislin
Copy link
Member

iblislin commented Dec 5, 2017

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:

@fredrikekre
Copy link
Member

Should have rerun CI here since it was over 2 weeks since the last time.

@StefanKarpinski
Copy link
Member

Sorry, my bad.

@KristofferC
Copy link
Member

So what do we do? Quick revert or live with it until someone fixes it?

@StefanKarpinski
Copy link
Member

@stevengj – do you think you could fix this soon or should I revert this?

StefanKarpinski added a commit that referenced this pull request Dec 5, 2017
@StefanKarpinski
Copy link
Member

Here's the revert PR: #24930

@simonbyrne
Copy link
Contributor

simonbyrne commented Dec 5, 2017

It appears to be due to the use of LLVM intrinsics. I think we've had trouble with those before (e.g. #2741 & #8939).

StefanKarpinski added a commit that referenced this pull request Dec 5, 2017
Revert "improvements to accuracy/performance for float^integer (#24500)"
@stevengj stevengj restored the betterfloatpows branch December 6, 2017 04:18
@stevengj
Copy link
Member Author

stevengj commented Dec 6, 2017

I don't really understand why there would be a problem with the LLVM intrinsics here. The ccall is virtually identical to the one in ^(x::Float64, y::Float64), just with the subsequent isnan check removed.

@stevengj
Copy link
Member Author

stevengj commented Dec 6, 2017

I'm guessing that the code is perfectly fine, but that 0.09496527f0 ^ -2 === 110.88438f0 test is too stringent? It looks like on amd64 it is actually getting a more accurate result, which should be fine…

(Is it something about extended-precision mode on Linux?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maths Mathematical functions performance Must go faster
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants