# Pi raised to negative integer powers produces a strange error message, and the literal\_pow obfuscation

**URL:** <https://discourse.julialang.org/t/pi-raised-to-negative-integer-powers-produces-a-strange-error-message-and-the-literal-pow-obfuscation/37434>\
**Category:** General Usage\
**Tags:** question\
**Created:** [April 12, 2020, 5:24am UTC](https://discourse.julialang.org/t/pi-raised-to-negative-integer-powers-produces-a-strange-error-message-and-the-literal-pow-obfuscation/37434 "2020-04-12T05:24:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [April 12, 2020, 5:24am UTC](https://discourse.julialang.org/t/pi-raised-to-negative-integer-powers-produces-a-strange-error-message-and-the-literal-pow-obfuscation/37434/1 "2020-04-12T05:24:08Z")

</div>

I am trying to raise `pi` to negative integer powers, and end up with unexpected errors:

```julia
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
julia> Base.to_power_type(pi)
3.141592653589793

```

The error message seems to originate from

```julia
@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
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

```julia
# don't use the inv(x) transformation here since float^p is slightly more accurate

```

and I would like the accuracy to be preserved.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [April 12, 2020, 7:57am UTC](https://discourse.julialang.org/t/pi-raised-to-negative-integer-powers-produces-a-strange-error-message-and-the-literal-pow-obfuscation/37434/2 "2020-04-12T07:57:03Z")

</div>

> [@jishnub](#):
>
> would like the accuracy to be preserved

Since `pi` is an abstract representation of the constant \pi, you need to _choose_ a level of accuracy you want to work with in other representations (eg floating point). Some operations, eg `1/pi`, pick that for you implicitly, but for your expression you might just use something like

```julia
julia> Float64(pi)^-2
0.10132118364233778

```

You may be interested in the discussion for this feature, in particular this comment

> <https://github.com/JuliaLang/julia/pull/20530#issuecomment-279505475>
>
> Having \`x^(-2)\` work dramatically better than \`p=-2; x^p\` and give potentially d…ifferent behavior in some package would be rather surprising. There's a semantic red flag this is raising to me (would you call this referential transparency?)

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [April 12, 2020, 9:04am UTC](https://discourse.julialang.org/t/pi-raised-to-negative-integer-powers-produces-a-strange-error-message-and-the-literal-pow-obfuscation/37434/3 "2020-04-12T09:04:12Z")

</div>

Thanks, but it seems to work differently with `\euler`

```julia
julia> ℯ
ℯ = 2.7182818284590...

julia> n=2; ℯ^-n
0.1353352832366127

```

The reason behind this appears to be that `\euler` has a special method dealing with exponentiation, and this simply calls the exponential function `exp(n)`

```julia
julia> @which ℯ^-n
^(::Irrational{:ℯ}, x::Integer) in Base.MathConstants at mathconstants.jl:91

julia> @which π^-n
^(x::Number, p::Integer) in Base at intfuncs.jl:222

```

This, however, introduces an arbitrariness in how irrational numbers behave. Is it worth defining a special exponentiation method for `pi`? Although looking at possible options

```julia
julia> exp(-2*log(pi))
0.10132118364233778

julia> inv(pi)^2
0.10132118364233779

```

It’s not clear which one is more accurate in general. One way to avoid this is to do what `exp(::Real)` does, by converting its argument to float. In this case we obtain

```julia
julia> pi^-2.0
0.10132118364233778

```

In the course of the evaluation `pi` is also promoted to `Float64`, so the exponentiation is effectively calling `^(::Float64,::Float64)`. This will likely be a breaking change, as

```julia
julia> float(pi)^float(5.0)
306.0196847852814

julia> pi*pi*pi*pi*pi
306.01968478528136

```

I can see the ambiguity here, but the present situation is pretty confusing. At the very least we need a better error message.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [April 12, 2020, 9:27am UTC](https://discourse.julialang.org/t/pi-raised-to-negative-integer-powers-produces-a-strange-error-message-and-the-literal-pow-obfuscation/37434/4 "2020-04-12T09:27:21Z")

</div>

> [@jishnub](#):
>
> This, however, introduces an arbitrariness in how irrational numbers behave. Is it worth defining a special exponentiation method for `pi` ?

I think this can be considered a missing method issue, which could be solved by defining a fallback method

```julia
Base.:^(x::Irrational, y) = Float64(x)^y

```

which would fix this for all other constants (note that I did not check method ambiguities etc). Cf

```julia
julia> n = 2; MathConstants.catalan^(-n)
ERROR: DomainError with -2:
Cannot raise an integer x to a negative power -2.
Convert input to float.

```

I would not worry about accuracy in the first iteration; general methods (eg power by squaring) should be fine. Having a missing method is an issue that should be resolved, please consider making a PR.
