# Confusion on performance when using the broadcasting macro @. vs explicit . operators

**URL:** <https://discourse.julialang.org/t/confusion-on-performance-when-using-the-broadcasting-macro-vs-explicit-operators/127380>\
**Category:** Performance\
**Created:** [March 26, 2025, 12:42pm UTC](https://discourse.julialang.org/t/confusion-on-performance-when-using-the-broadcasting-macro-vs-explicit-operators/127380 "2025-03-26T12:42:54Z")\
**Posts on this page:** 1\
**Showing post:** 7

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [March 26, 2025, 4:59pm UTC](https://discourse.julialang.org/t/confusion-on-performance-when-using-the-broadcasting-macro-vs-explicit-operators/127380/7 "2025-03-26T16:59:07Z")

</div>

Indeed, ranges are often slower to access than `Array`(at least when arrays are small-ish and accessed in a predictable order). There are ways to make the ranges somewhat faster, however.

A big part of the cost of ranges is that they are usually `TwicePrecision`, giving extra accuracy (and critical to making things like `0:0.1:1` behave how you’d hope – try `collect(StepRangeLen(0.0, 0.1, 11))` for comparison). But one can give this up to make things a bit faster.

```julia-repl
julia> x = range(0, π, 100); y = StepRangeLen(first(x), step(x), length(x)); z = collect(x);

julia> typeof(x)
StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}

julia> typeof(y) # no TwicePrecision
StepRangeLen{Float64, Float64, Float64, Int64}

julia> @btime sum(a for a in $x) # use generator to block other optimizations
  134.046 ns (0 allocations: 0 bytes)
157.07963267948963

julia> @btime sum(a for a in $y) # use generator to block other optimizations
  45.063 ns (0 allocations: 0 bytes)
157.07963267948963

julia> @btime sum(a for a in $z) # use generator to block other optimizations
  19.002 ns (0 allocations: 0 bytes)
157.07963267948963

julia> @btime sum($z) # optimized Array method using SIMD
  5.862 ns (0 allocations: 0 bytes)
157.07963267948966

julia> @btime sum(collect($x)) # the worst of both worlds
  146.022 ns (2 allocations: 928 bytes)
157.07963267948966

julia> @btime sum(collect($y)) # the worst of both worlds
  78.811 ns (2 allocations: 928 bytes)
157.07963267948966

```

Without `TwicePrecision`, the range indexing is considerably faster (but not exactly the same, although the sums coincide here). Also note that `collect`ing a range and _then_ iterating the `Array` once will virtually always be slower than simply iterating it. To see a speed benefit, you’d need to collect it once and then iterate it many times.

The reason ranges are usually recommended is that they are memory-free and that iterating them is usually either 1) much less expensive than other things you’re doing or 2) only done a few times.

---

_[View the full topic](https://discourse.julialang.org/t/confusion-on-performance-when-using-the-broadcasting-macro-vs-explicit-operators/127380)._
