# Any suggestions for speeding this simple scalar function up?

**URL:** https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748
**Category:** Performance
**Tags:** performance
**Created:** [August 20, 2021, 8:19pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748 "2021-08-20T20:19:06Z")
**Posts on this page:** 17
**Page:** 2

<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: [August 21, 2021, 10:41am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/22 "2021-08-21T10:41:32Z")

</div>

> [@Ahmed\_Salih](#):
>
> I found using “7” instead of “7.0” sped up the power calculation.

You sure?

```julia
julia> @btime ρ0 ^ γ setup = (ρ0 = 1000.0; γ = 7)
  85.486 ns (0 allocations: 0 bytes)
1.0e21

julia> @btime ρ0 ^ γ setup = (ρ0 = 1000.0; γ = 7.0)
  85.442 ns (0 allocations: 0 bytes)
1.0e21

```

Maybe that’s true when the exponent is a literal, or a small (\< 4) integer, but if you’re using a variable that is larger than 3, the exponent is converted to a float anyway

> [@DNF](#):
>
> Probably integer overflow for 1000^7

Ehr…

> [@giordano](#):
>
> What if gamma and rho0 are floats instead of integers that can overflow?

---

<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: [August 21, 2021, 10:52am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/23 "2021-08-21T10:52:52Z")

</div>

> [@giordano](#):
>
> that is larger than 3, the exponent is converted to a float anyway

Is it with `@turbo`?

---

<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: [August 21, 2021, 10:53am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/24 "2021-08-21T10:53:20Z")

</div>

I’m talking about `Base` Julia, in the example above there is no `@turbo`

---

<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: [August 21, 2021, 10:56am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/25 "2021-08-21T10:56:04Z")

</div>

Just because the begining of this discussion was 50x speedup by using it. [Here](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/4)

---

<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: [August 21, 2021, 10:58am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/26 "2021-08-21T10:58:50Z")

</div>

> [@Ahmed\_Salih](#):
>
> But it means I cannot get the speed up from calculating 1/rho0^7 first I suppose.

Yes, you can do

```julia
(1/rho0)^7

```

but I don’t recommend this anymore, I think it’s bad numerically, even if it doesn’t fail catastrophically.

---

<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: [August 21, 2021, 11:09am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/27 "2021-08-21T11:09:08Z")

</div>

In [_ **my** _ example above](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/22) there was no `@turbo`. With `@turbo`:

```julia
julia> @btime @turbo(ρ0 ^ γ) setup = (ρ0 = 1000.0; γ = 7.0)
  85.443 ns (0 allocations: 0 bytes)
1.0e21

julia> @btime @turbo(ρ0 ^ γ) setup = (ρ0 = 1000.0; γ = 7)
  85.474 ns (0 allocations: 0 bytes)
1.0e21

```

No difference at all between the two versions, and _exactly_ same timing as without `@turbo` (not sure `@turbo` does anything at all here, though)

---

<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: [August 21, 2021, 12:10pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/28 "2021-08-21T12:10:31Z")

</div>

It makes a _huge_ difference for _vectors_, just look up thread.

Here’s another example:

> [@stillyslalom](#):
>
> ```julia
> julia> pow(x, n) = x^n
> pow (generic function with 1 method)
> 
> julia> @btime Base.map(x -> pow(x, 7), x) setup=(x=rand(1000));
> 30.900 μs (1 allocation: 7.94 KiB)
> 
> julia> @btime LoopVectorization.vmap(x -> pow(x, 7), x) setup=(x=rand(1000));
> 897.872 ns (1 allocation: 7.94 KiB)
> 
> ```

---

<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: [August 21, 2021, 12:13pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/29 "2021-08-21T12:13:02Z")

</div>

> [@giordano](#):
>
> Ehr…

I’m on my phone, and can’t check. It’s weird that accuracy crashed and burned exactly for `^7`, and was suddenly off by 8 orders of magnitude, but was ok for `^6`, so I assumed overflow.

---

<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: [August 21, 2021, 12:47pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/30 "2021-08-21T12:47:57Z")

</div>

> [@DNF](#):
>
> It makes a _huge_ difference for _vectors_ , just look up thread.

I believe we’re getting lost in translation. I was talking about difference between `a ^ b` when `b` is an integer or a float (and `b` is not an integer literal). @lmiq asked about LoopVectorization when I was talking about the `Base` function `^`. Now you’re comparing `pow(x, 7)` (which is _different_ from `x ^ 7`) for vectors, between `Base.map` and `LoopVectorization.vmap`, which doesn’t have anything to do with what I was talking about above?

---

<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: [August 21, 2021, 12:49pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/31 "2021-08-21T12:49:45Z")

</div>

But then I think it’s you who are a bit off-topic.

---

<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: [August 21, 2021, 12:51pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/32 "2021-08-21T12:51:19Z")

</div>

How so? 😕 I pointed out that `ρ0 ^ γ` overflows when `ρ0 = 1000` and `γ = 7`, and there is no performance benefit in using integer values in this case (at least in `Base`)

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [August 21, 2021, 1:27pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/33 "2021-08-21T13:27:53Z")

</div>

> [@giordano](#):
>
> if you’re using a variable that is larger than 3, the exponent is converted to a float anyway

While off topic, why is this threshold so low? Looks like it was added in [#20889](https://github.com/JuliaLang/julia/pull/20889) but I don’t quite see where 3 was argued for.

```julia
julia> @btime y .= x .^ 3 setup=(x=rand(1000); y=similar(x));
  176.471 ns (0 allocations: 0 bytes)

julia> @btime y .= x .^ 4 setup=(x=rand(1000); y=similar(x));
  16.958 μs (0 allocations: 0 bytes)

julia> pow4(x) = begin z = x * x; z * z end

julia> @btime y .= pow4.(x) setup=(x=rand(1000); y=similar(x));
  157.401 ns (0 allocations: 0 bytes)

```

Edit with some LV comparison:

```julia
julia> @btime @turbo(y .= x .^ 4) setup=(x=rand(1000); y=similar(x));
  327.248 ns (0 allocations: 0 bytes)

julia> @btime @turbo(y .= x .^ 4.0) setup=(x=rand(1000); y=similar(x));
  8.875 μs (0 allocations: 0 bytes)

# and x^7, similar

julia> @btime @turbo(y .= x .^ 7) setup=(x=rand(1000); y=similar(x));
  240.423 ns (0 allocations: 0 bytes)

julia> pow7(x) = begin x3 = x^3; x * x3^2 end;

julia> @btime y .= pow7.(x) setup=(x=rand(1000); y=similar(x));
  213.394 ns (0 allocations: 0 bytes)

```

---

<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: [August 21, 2021, 1:36pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/34 "2021-08-21T13:36:06Z")

</div>

> [@giordano](#):
>
> How so?

I said so because everyone else was talking about LoopVectorization, and you came in saying that this was was not relevant, and insisted on talking about the Base versions.

---

<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: [August 21, 2021, 5:50pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/35 "2021-08-21T17:50:51Z")

</div>

The threshold is low because of numerical accuracy. `x^3` is the last point when the accuracy of repeated multiplication is less than 1.5 ULP.

---

<div class="post-metadata">

### Author: ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)
#### Post date: [August 22, 2021, 12:02am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/36 "2021-08-22T00:02:04Z")

</div>

> [@mcabbott](#):
>
> ```julia
> julia> pow7(x) = begin x3 = x^3; x * x3^2 end;
> 
> julia> @btime y .= pow7.(x) setup=(x=rand(1000); y=similar(x));
> 213.394 ns (0 allocations: 0 bytes)
> 
> ```

If you do this in a loop, LoopVectorization will automatically do this for you:

```julia
using LoopVectorization, BenchmarkTools
function pow7turbo!(y, x)
    @turbo for i in eachindex(y,x)
        y[i] = x[i]^7
    end
end
pow7(x) = begin x3 = x^3; x * x3^2 end;
@btime pow7turbo!(y, x) setup=(x=rand(1000); y=similar(x));
@btime y .= pow7.(x) setup=(x=rand(1000); y=similar(x));

```

I get:

```julia
julia> @btime pow7turbo!(y, x) setup=(x=rand(1000); y=similar(x));
  111.771 ns (0 allocations: 0 bytes)

julia> @btime y .= pow7.(x) setup=(x=rand(1000); y=similar(x));
  117.757 ns (0 allocations: 0 bytes)

```

I guess I could apply the same transform earlier, at a time that it’d also apply to broadcast statements.  
This happens at macro-expand time given literals, otherwise LoopVectorization currently can’t read the constant values.

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [August 22, 2021, 12:30am UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/37 "2021-08-22T00:30:12Z")

</div>

> [@Oscar\_Smith](#):
>
> because of numerical accuracy

Ah thanks, that makes sense.

> [@Elrod](#):
>
> could apply the same transform earlier, at a time that it’d also apply to broadcast statements

After Oscar’s comment I realised that fastmath also seems to make this transformation? But also doesn’t seem to digest the broadcast:

```julia
julia> @btime y .= Base.FastMath.pow_fast.(x, Val(7)) setup=(x=rand(1000); y=similar(x));
  163.589 ns (0 allocations: 0 bytes)

julia> @macroexpand @fastmath(y .= x .^ 7)
:(y .= x .^ 7)

julia> @macroexpand @fastmath(y = x ^ 7)
:(y = Base.FastMath.pow_fast(x, Val{7}()))

```

---

<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: [August 22, 2021, 2:35pm UTC](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748/38 "2021-08-22T14:35:24Z")

</div>

For expressions like this, the first thing I would strive for (before speed) is numerical stability, eg by transforming to logs, such as

```julia
logP = logb + LogExpFunctions.logsubexp(gamma * (logrho - logrho0), 0)

```

and if possible staying in log space for the whole calculation. This occasionally improves speed to, but I did not benchmark for this particular problem.

[Previous page](https://discourse.julialang.org/t/any-suggestions-for-speeding-this-simple-scalar-function-up/66748.md?page=1)
