-
-
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
make x^-n equivalent to inv(x)^n for literal n #24240
Conversation
Note that this changes (and apparently greatly improves?) the code that is generated for e.g. julia> @code_llvm f(2.3)
define double @julia_f_60740(double) #0 !dbg !5 {
top:
%1 = call double @llvm.pow.f64(double %0, double -2.000000e+00)
%2 = fadd double %0, -2.000000e+00
%notlhs = fcmp ord double %1, 0.000000e+00
%notrhs = fcmp uno double %2, 0.000000e+00
%3 = or i1 %notrhs, %notlhs
br i1 %3, label %L12, label %if
if: ; preds = %top
call void @jl_throw(i8** inttoptr (i64 4624304072 to i8**))
unreachable
L12: ; preds = %top
ret double %1
} whereas now I get: julia> @code_llvm f(2.3)
%1 = fdiv double 1.000000e+00, %0
%2 = fmul double %1, %1
ret double %2
} which looks a lot nicer. BenchmarkTools seems to be broken on 0.7 at the moment, but I can simulate the new behavior in 0.6 by julia> @btime f(2.3);
37.351 ns (0 allocations: 0 bytes)
julia> @btime g(2.3);
2.048 ns (0 allocations: 0 bytes) which seems almost too good to be true. (They give exactly the same result I really don't understand what the branch and |
The branch is because the exponent @inline function ^(x::Float64, y::Float64)
z = ccall("llvm.pow.f64", llvmcall, Float64, (Float64, Float64), x, y)
if isnan(z) & !isnan(x+y)
throw_exp_domainerror(x)
end
z
end is called. |
Ah, thanks @KristofferC. Separate from this PR, maybe we should add a @inline ^(x::Float64, y::Int) = ccall("llvm.pow.f64", llvmcall, Float64, (Float64, Float64), x, y) method that skips the domain-error check for integer exponents (where I think it can never throw)? ( |
julia> -2.0^-2.3
-0.2030630990890589
julia> f(x, y) = x^y
f (generic function with 1 method)
julia> f(-2.0, -2.3)
ERROR: DomainError:
Exponentiation yielding a complex result requires a complex argument.
Replace x^y with (x+0im)^y, Complex(x)^y, or similar.
Stacktrace:
[1] nan_dom_err at ./math.jl:300 [inlined]
[2] ^ at ./math.jl:699 [inlined]
[3] f(::Float64, ::Float64) at ./REPL[2]:1 At http://en.cppreference.com/w/c/numeric/math/pow they say:
|
@KristofferC, we don't throw a domain error in the other two cases you mention. |
Well, it says "may occur"... :P |
@nanosoldier |
Nanosoldier doesn't work at the moment due to an issue with JLD on 0.7. I'm working on removing the dependency on JLD entirely, but until that's done, it's unlikely that any Nanosoldier run will succeed. |
@@ -85,6 +85,7 @@ catalan | |||
for T in (Irrational, Rational, Integer, Number) | |||
Base.:^(::Irrational{:ℯ}, x::T) = exp(x) | |||
end | |||
@generated Base.literal_pow(::typeof(^), ::Irrational{:ℯ}, ::Val{p}) where {p} = exp(p) |
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.
this doesn't need to be @generated
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.
whoops, that was copy-and-paste typo, sorry.
@vtjnash, we could only do this in LLVM for e.g. As far as I can tell, #19872 is not an issue for the new Regarding #8939, you're right that there seems to be a slight degradation in accuracy for small powers, typically of 1ulp, but occasionally 2ulp for |
It's also providing worse results with worse performance for non-hardware types like BigFloat, since we no longer fuse the operations, due to the catch-all behavior of this PR. |
With most types, e.g. complex numbers, the behavior is identical (since most types implement negative integer powers by With Another way of saying it is that people implementing their own |
I generally agree with @stevengj here, but I think @vtjnash's point is that we can just define |
xref #21014 (comment) |
This fixes #3024 by taking advantage of #20530 to transform
x^-n
toinv(x)^n
for literal integer exponentsn
.It means that things like
2^-2
now work (giving0.25
) in a type-stable way, you can useA^-1
for the inverse of aMatrix{Int}
, etcetera.(This pulls out the negative-exponent portions of PR #20637.)