# How to speed up array comparisons?

**URL:** <https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019>\
**Category:** Performance\
**Tags:** question\
**Created:** [May 19, 2018, 8:55pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019 "2018-05-19T20:55:43Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Noel\_Araujo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/noel_araujo/32/4862_2.png) [@Noel\_Araujo](https://discourse.julialang.org/u/Noel_Araujo)\
**Post date:** [May 19, 2018, 8:55pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/1 "2018-05-19T20:55:43Z")

</div>

I need to fix a bottleneck in my code during comparison of an array and a variable.  
I’ve tested the map() function and it speed up my code only when I declare the number directly. If I store my number inside a variable I lost the performance.  
Below we have a simple example in Julia 0.6.2. `A` is just an array and I need to compare it with a value stored in `cte`.

```julia
A = collect(1:1000) + rand(1000);
cte = 560.5
@btime A .> 560.5
@btime A .> cte
@btime map( (l)-> l > 560.5,A)
@btime map( (l)-> l > cte,A)

```

In my computer, results were:

- 4.679 μs (21 allocations: 5.06 KiB)
- 3.916 μs (21 allocations: 4.95 KiB)
- 846.938 ns (2 allocations: 1.08 KiB)
- 16.998 μs (1003 allocations: 16.72 KiB)

We can see the third line has the better result. How can I define my variable `cte` so that the fourth line will had the same performance ?

Thank you

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [May 19, 2018, 9:00pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/2 "2018-05-19T21:00:57Z")

</div>

You can do `const cte = 560.5`, or wrap the call in a function which takes `cte` as an argument.

---

<div class="post-metadata">

**Author:** ![Noel\_Araujo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/noel_araujo/32/4862_2.png) [@Noel\_Araujo](https://discourse.julialang.org/u/Noel_Araujo)\
**Post date:** [May 19, 2018, 9:07pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/3 "2018-05-19T21:07:01Z")

</div>

It works, thank you

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [May 19, 2018, 10:00pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/4 "2018-05-19T22:00:34Z")

</div>

Or, if you need something super fast:

```julia
julia> function f(x,A)
       C = Array{Bool}(undef,length(A))
       @inbounds for i in 1:length(A)
         C[i] = ifelse(A[i]>x, true, false)
       end
       C
       end
f (generic function with 1 method)

julia> A = (1:1000) + rand(1000);
julia> cte = 560.5;
julia> @btime f($cte,$A);
  256.591 ns (1 allocation: 1.06 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:** [May 19, 2018, 10:26pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/5 "2018-05-19T22:26:32Z")

</div>

> [@Noel\_Araujo](#):
>
> @btime map( (l)-\> l \> cte,A)

When benchmarking with BenchmarkTools, remember to _ **always** _ interpolate the variables!

```julia
julia> @btime map( (l)-> l > cte,A);
  25.785 μs (1003 allocations: 16.72 KiB)

julia> @btime map( (l)-> l > $cte,$A);
  737.640 ns (2 allocations: 1.09 KiB)

```

If you have weird benchmarking results, 98% of the time, it’s because you didn’t interpolate.

---

<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 19, 2018, 10:36pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/6 "2018-05-19T22:36:35Z")

</div>

If `array .> x` is the bottleneck in your code, it’s likely you are doing something wrong. Don’t write Matlab/Numpy-style code that performs a sequence of vector operations one by one. Write a single loop that does all your processing in one pass over the array. (And put performance-critical code like this in a function.)

---

<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 19, 2018, 10:38pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/7 "2018-05-19T22:38:18Z")

</div>

> [@nalimilan](#):
>
> You can do `const cte = 560.5` , or wrap the call in a function which takes `cte` as an argument.

I have seen pretty much this exact answer to basically the same question countless times. Why the reluctance to recommending variable interpolation? To me, that seems so much more convenient than creating a function. What am I missing?

---

<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 19, 2018, 10:42pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/8 "2018-05-19T22:42:49Z")

</div>

Interpolation is only something that works with the BenchmarkTools macros. And writing a lot of performance critical code as one big global script is bad programming style anyway—it leads to code reuse by copy-paste and editing your code every time you need to change a parameter.

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [May 19, 2018, 11:42pm UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/9 "2018-05-19T23:42:44Z")

</div>

> [@DNF](#):
>
> > [@nalimilan](#):
> >
> > You can do `const cte = 560.5` , or wrap the call in a function which takes `cte` as an argument.
> 
> I have seen pretty much this exact answer to basically the same question countless times. Why the reluctance to recommending variable interpolation? To me, that seems so much more convenient than creating a function. What am I missing?

Could you explain what’s variable interpolation and when does it make a difference in performance?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [May 20, 2018, 12:26am UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/10 "2018-05-20T00:26:15Z")

</div>

> [@RoyiAvital](#):
>
> Could you explain what’s variable interpolation and when does it make a difference in performance?

Interpolating it adds the literal to the expression instead of using a global which breaks type-inference.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [May 20, 2018, 12:29am UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/11 "2018-05-20T00:29:20Z")

</div>

> [@RoyiAvital](#):
>
> Could you explain what’s variable interpolation and when does it make a difference in performance?

It makes no difference in practice, it is a quirk of the `BenchmarkTools` macros

`@btime` only really works in the global scope. But when you measure a function call via `@btime`, then you will measure both dispatch and time spent in the function, because `@btime` has to take your variables from the global scope (where they are untyped). This is distinct from using literals for benchmarking. Generally, whenever your timings are in usecs (or even nanoseconds), I would be wary of artifacts; such functions can really only be properly benchmarked in context (inlining and whatever your CPU ends up doing).

```julia
#on 0.62
julia> using BenchmarkTools

julia> @btime +(1,2);
  2.198 ns (0 allocations: 0 bytes)

julia> x=1;y=2;
julia> @btime +(x,y);
  23.521 ns (0 allocations: 0 bytes)
julia> @btime +($x,$y)
  2.633 ns (0 allocations: 0 bytes)

```

and

```julia
#on 0.7
julia> using BenchmarkTools

julia> @btime +(1,2)
  0.024 ns (0 allocations: 0 bytes)

julia> x=1;y=2;
julia> @btime +(x,y)
  29.138 ns (0 allocations: 0 bytes)
julia> @btime +($x,$y)
  2.207 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [May 20, 2018, 5:44am UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/12 "2018-05-20T05:44:31Z")

</div>

@foobar_lv2, I can see the difference in results, but what’s Variable Interpolation?  
What’s being done exactly?

---

<div class="post-metadata">

**Author:** ![TsurHerman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tsurherman/32/1234_2.png) [@TsurHerman](https://discourse.julialang.org/u/TsurHerman)\
**Post date:** [May 20, 2018, 7:11am UTC](https://discourse.julialang.org/t/how-to-speed-up-array-comparisons/11019/13 "2018-05-20T07:11:06Z")

</div>

If I understand correctly  
when you are doing  
`@benchmark func(X)`  
if func and or X are not constants in the scope you are benchmarking… that is, if it is possible to change  
the type of func or X (without getting a warning).

then what you are actually benchmarking in each iteration is:  
tic  
get the current values for func and X  
apply func(X)  
toc

Whereas when you add the $ sign in the benchmark macro, you are not using the variable you are using the value of that variable in the time of the macro invocation, which is probably what you wanted.
