Negative integer exponent

There is something strange that I do not understand:

julia> 2^-3
0.125

works ok. But the following minor generalization does not.

julia> g() = -3; 2^g()
ERROR: DomainError with -3:
Cannot raise an integer x to a negative power -3.
Make x or -3 a float by adding a zero decimal (e.g., 2.0^-3 or 2^-3.0 instead of 2^-3)or write 1/x^3, float(x)^-3, x^float(-3) or (x//1)^-3.
Stacktrace:
 [1] throw_domerr_powbysq(::Int64, p::Int64)
   @ Base ./intfuncs.jl:265
 [2] power_by_squaring(x_::Int64, p::Int64)
   @ Base ./intfuncs.jl:286
 [3] ^(x::Int64, p::Int64)
   @ Base ./intfuncs.jl:310
 [4] top-level scope
   @ REPL[2]:1

of course

julia> 2.0^g()
0.125

works. I tried to descend into the call but did not find where 2^g() misses the promotion to 2.0^g(). I do not think it is a bug, but I do not see the rationale behind this behavior.

Thanks

From documentation on ^:

If y is an Int literal (e.g. 2 in x^2 or -3 in x^-3), the Julia code x^y is transformed by the compiler to Base.literal_pow(^, x, Val(y)), to enable compile-time specialization on the value of the exponent. (As a default fallback we have Base.literal_pow(^, x, Val(y)) = ^(x,y), where usually ^ == Base.^ unless ^ has been defined in the calling namespace.) If y is a negative integer literal, then Base.literal_pow transforms the operation to inv(x)^-y by default, where -y
is positive.

julia> Base.literal_pow(^, 3, Val(-3))
0.037037037037037035

g() in 2^g() is not a literal, so this transformation does not happen.

1 Like

Thanks @barucden … I overlooked the docs. Marking your reply as a solution.

Yet, it is not completely clear why 2^g() where g() is inferred to be an Int should behave differently. g() is not a literal true, but there should be a code path where literal_pow and pow should behave the same for provably integer exponents.

This is not just about the exponent being an integer, but being a specific integer. Cf. Confusing difference: ^literal vs ^variable - #6 by StefanKarpinski for some rationale.

Thanks @GunnarFarneback.

Confusing difference: ^literal vs ^variable - #6 by StefanKarpinski indeed answers precisely my doubts.