I am trying to raise pi
to negative integer powers, and end up with unexpected errors:
julia> pi^-2 # works
0.10132118364233779
julia> n=2; pi^-n # doesn't work
ERROR: DomainError with -2:
Cannot raise an integer x to a negative power -2.
Convert input to float.
Stacktrace:
[1] throw_domerr_powbysq(::Float64, ::Int64) at ./intfuncs.jl:190
[2] power_by_squaring(::Irrational{:π}, ::Int64) at ./intfuncs.jl:214
[3] ^(::Irrational{:π}, ::Int64) at ./intfuncs.jl:239
[4] top-level scope at REPL[18]:1
The error message is confusing as pi
is firstly not an integer, and the first line in Base.power_by_squaring
is a call to Base.to_power_type
that converts pi
to a float
.
julia> Base.to_power_type(pi)
3.141592653589793
The error message seems to originate from
@noinline throw_domerr_powbysq(::Any, p) = throw(DomainError(p,
string("Cannot raise an integer x to a negative power ", p, '.',
"\nConvert input to float.")))
which is a catch-all method, but the error message assumes that the base is an integer.
As I understand, Julia lowers literal integer exponentiation to literal_pow
, while integer variables are treated using Base.power_by_squaring
. The matter isn’t helped by the fact that @code_lowered
doesn’t show you what’s happening.
julia> @code_lowered pi^-2
CodeInfo(
1 ─ %1 = Base.power_by_squaring(x, p)
└── return %1
)
julia> n=2; @code_lowered pi^-n
CodeInfo(
1 ─ %1 = Base.power_by_squaring(x, p)
└── return %1
)
julia> Base.power_by_squaring(pi,-n)
ERROR: DomainError with -2:
Cannot raise an integer x to a negative power -2.
Convert input to float.
Stacktrace:
[1] throw_domerr_powbysq(::Float64, ::Int64) at ./intfuncs.jl:173
[2] power_by_squaring(::Irrational{:π}, ::Int64) at ./intfuncs.jl:197
[3] top-level scope at REPL[6]:1
The lowered code is identical for a literal integer and a variable. How to raise pi
to a negative integer power without actually evaluating inv(pi^n)
? intfuncs.jl
says
# don't use the inv(x) transformation here since float^p is slightly more accurate
and I would like the accuracy to be preserved.