# Speed of power "^"

**URL:** <https://discourse.julialang.org/t/speed-of-power/80605>\
**Category:** Performance\
**Created:** [May 6, 2022, 12:08pm UTC](https://discourse.julialang.org/t/speed-of-power/80605 "2022-05-06T12:08:42Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![zhubonan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhubonan/32/31877_2.png) [@zhubonan](https://discourse.julialang.org/u/zhubonan)\
**Post date:** [May 6, 2022, 12:08pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/1 "2022-05-06T12:08:43Z")

</div>

I am writing a code that involves lots of use of “^” and profiling seems to suggest “^” is contributing a lot of the time.  
I have done the following test of the timing. Replacing “^” “\*” seems to give a massive speed up, which is not surprising. Interestingly, x^3 is much faster than x^4 and it seems that the compiler is capable of dynamically convert “^” to “\*”!

```julia
f1(x) = x ^ 2
f2(x) = x ^ 1.1
f3(x) = x ^ 3
f4(x) = x ^ 4
f5(x) = x ^ 9.9
f6(x) = x ^ 5
f7(x, y) = x ^ y
f8(x) = x * x * x * x * x
@btime f1(1.5)
@btime f2(1.5)
@btime f3(1.5)
@btime f4(1.5)
@btime f5(1.5)
@btime f6(1.5)

@btime f7(1.5, 3)
@btime f7(1.5, 9.9)
@btime f8(1.5)

```

```julia
  0.011 ns (0 allocations: 0 bytes)
  0.864 ns (0 allocations: 0 bytes)
  0.011 ns (0 allocations: 0 bytes)
  0.825 ns (0 allocations: 0 bytes)
  0.825 ns (0 allocations: 0 bytes)
  0.826 ns (0 allocations: 0 bytes)
  0.011 ns (0 allocations: 0 bytes)
  0.861 ns (0 allocations: 0 bytes)
  0.011 ns (0 allocations: 0 bytes)

```

Unfortunately, I have to go beyond “x^3”… I am wondering if there is any tip to improve the performance further. Perhaps the solution would be to convert “^” to “\*” in the equation at compile time through macros?

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [May 6, 2022, 12:13pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/2 "2022-05-06T12:13:52Z")

</div>

Note that you aren’t benchmarking anything. Subnanosecond times indicate you’re running into constant propagation: [Manual · BenchmarkTools.jl](https://juliaci.github.io/BenchmarkTools.jl/stable/manual/#Understanding-compiler-optimizations). In Julia v1.8 `BenchmarkTools` will be able to automatically stop constant propagation.

---

<div class="post-metadata">

**Author:** ![zhubonan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhubonan/32/31877_2.png) [@zhubonan](https://discourse.julialang.org/u/zhubonan)\
**Post date:** [May 6, 2022, 12:16pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/3 "2022-05-06T12:16:39Z")

</div>

Ahh I see @giordano thanks! I will check with v1.8.

Also I found that it is actually in the stdlib where the change to \* is defined:

[https://github.com/JuliaLang/julia/blob/bf534986350a991e4a1b29126de0342ffd76205e/base/math.jl#L922-L929](https://github.com/JuliaLang/julia/blob/bf534986350a991e4a1b29126de0342ffd76205e/base/math.jl#L922-L929)

Perhaps there is a way to extended it beyond `x*x*x*x` in this case.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 6, 2022, 12:42pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/4 "2022-05-06T12:42:04Z")

</div>

What timings do you see in your real application? How did you come to the conclusion that `^` is the bottleneck (did you profile using e.g. the [Profile stdlib](https://docs.julialang.org/en/v1/stdlib/Profile/))?

If you’re doing lots of `^`, I’d also expect `^` to take up most of the time, to be honest.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 6, 2022, 12:47pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/5 "2022-05-06T12:47:08Z")

</div>

> [@zhubonan](#):
>
> [https://github.com/JuliaLang/julia/blob/bf534986350a991e4a1b29126de0342ffd76205e/base/math.jl#L922-L929](https://github.com/JuliaLang/julia/blob/bf534986350a991e4a1b29126de0342ffd76205e/base/math.jl#L922-L929)

You can check out `Base.power_by_squaring`. Be aware that numerical accuracy is not quite as good, but that may not be a problem for you.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [May 6, 2022, 12:48pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/6 "2022-05-06T12:48:56Z")

</div>

Julia 1.8 is much faster here. that said, powers are inherently a lot harder than multiplication.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [May 6, 2022, 1:00pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/7 "2022-05-06T13:00:50Z")

</div>

Also take a look at [https://github.com/JuliaMath/FastPow.jl](https://github.com/JuliaMath/FastPow.jl)

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [May 6, 2022, 1:19pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/8 "2022-05-06T13:19:17Z")

</div>

> [@lmiq](#):
>
> Also take a look at [GitHub - JuliaMath/FastPow.jl: optimal addition-chain exponentiation for Julia](https://github.com/JuliaMath/FastPow.jl)

To clarify: for literal integer powers like `x^7`, this will give you better performance at the cost of slightly degraded accuracy. (For the built-in hardware floating-point types you can also simply use `@fastmath`.)

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 6, 2022, 1:33pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/9 "2022-05-06T13:33:24Z")

</div>

I’m not sure what you are trying to do, but if you happen to evaluate polynomials, consider using `evalpoly` (aka Horner’s method) to mitigate the number of multiplications / powers

---

<div class="post-metadata">

**Author:** ![zhubonan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhubonan/32/31877_2.png) [@zhubonan](https://discourse.julialang.org/u/zhubonan)\
**Post date:** [May 6, 2022, 1:44pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/10 "2022-05-06T13:44:47Z")

</div>

Yeah I used Pofile stdlib to do the profiling. There are lots of “^” inside loops, taking sum of different powers…

---

<div class="post-metadata">

**Author:** ![zhubonan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhubonan/32/31877_2.png) [@zhubonan](https://discourse.julialang.org/u/zhubonan)\
**Post date:** [May 6, 2022, 2:15pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/11 "2022-05-06T14:15:13Z")

</div>

Thanks for all the suggestions!  
In the end I just made a more aggressive version of `(^)` in `Base`:

```julia
@inline function fast_pow(x, y)
    y == -1 && return inv(x)
    y == 0 && return one(x)
    y == 1 && return x
    y == 2 && return x * x
    y == 3 && return x * x * x
    y == 4 && return x * x * x * x
    y == 5 && return x * x * x * x * x
    y == 6 && return x * x * x * x * x * x
    y == 7 && return x * x * x * x * x * x * x
    y == 8 && return x * x * x * x * x * x * x * x 
    y == 9 && return x * x * x * x * x * x * x * x * x 
    y == 10 && return x * x * x * x * x * x * x * x * x * x 
    y == 11 && return x * x * x * x * x * x * x * x * x * x * x 
    y == 12 && return x * x * x * x * x * x * x * x * x * x * x * x 
    ^(x, y)
end

```

and it already gives good speedups.  
Because `y` is only known at runtime so I cannot use FastPow.jl to statically expand it.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [May 6, 2022, 2:17pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/12 "2022-05-06T14:17:59Z")

</div>

Note that this will be much less accurate than `^`.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 6, 2022, 2:29pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/13 "2022-05-06T14:29:46Z")

</div>

Out of curiosity, where do you use these powers? In a polynomial?

---

<div class="post-metadata">

**Author:** ![zhubonan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhubonan/32/31877_2.png) [@zhubonan](https://discourse.julialang.org/u/zhubonan)\
**Post date:** [May 6, 2022, 2:44pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/14 "2022-05-06T14:44:35Z")

</div>

ahh good point.

---

<div class="post-metadata">

**Author:** ![zhubonan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhubonan/32/31877_2.png) [@zhubonan](https://discourse.julialang.org/u/zhubonan)\
**Post date:** [May 6, 2022, 2:50pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/15 "2022-05-06T14:50:17Z")

</div>

Not quite polynomial, something like:

```julia
function f(x, y, z, p, q)
    np = length(p)
    nq = length(q
    results = zeros(np * nq)
    k = 1
    for i in 1:np
        for j in 1:nq
            results[k] = x^p[i] * y^p[i] * z^q[j]
            k += 1
        end
    end
end

```

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [May 6, 2022, 2:52pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/16 "2022-05-06T14:52:18Z")

</div>

Oh, this can be made 3x faster trivially by computing `x^p[i]*y^p[i]` outside the inner loop.

If you are willing to lose a little bit of accuracy, you can get another 2x speedup by saving `log(z)` and writing

```julia
function f(x, y, z, p, q)
    np = length(p)
    nq = length(q
    results = zeros(np * nq)
    k = 1
    logz = log(z)
    for i in 1:np
        xyp = x^p[i] * y^p[i] 
        for j in 1:nq
            results[k] = xyp * exp(logz*q[j])
            k += 1
        end
    end
end
```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [May 6, 2022, 3:17pm UTC](https://discourse.julialang.org/t/speed-of-power/80605/17 "2022-05-06T15:17:26Z")

</div>

> [@zhubonan](#):
>
> `y == 8 && return x * x * x * x * x * x * x * x `

This (and your other cases) are using more multiplications than necessary. For example, `x^8 = ((x*x)^2)^2`, which is only 3 multiplications instead of 7. You can do `return @fastpow x^8` here (or `return @fastmath x^8` for hardware-float types), I guess.

But I agree with @Oscar_Smith that it’s better to optimize the larger context for these calculations.
