logo

Julia's Broadcasting Syntax 📂Julia

Julia's Broadcasting Syntax

Overview

Broadcasting is one of the most important concepts in Julia, offering a convenient syntax for writing vectorized code1. It is used by placing a dot . before a binary operation or after a function. This represents the application of a function in a pointwise manner, which is a perfect expression of its purpose.

From a programming perspective, broadcasting can be viewed as a simplification of using Map in Map and Reduce.

Code

Binary Operations

For binary operations, we place a . before them. For example, to add a scalar $a \in \mathbb{R}$ to every element of a matrix $A \in \mathbb{Z}_{9}^{3 \times 4}$, we use the following code.

julia> A = rand(0:9, 3,4)
3×4 Matrix{Int64}:
 5  6  3  3
 7  4  8  8
 0  2  2  7

julia> a = rand()
0.23234165065465284

julia> A .+ a
3×4 Matrix{Float64}:
 5.23234   6.23234  3.23234  3.23234
 7.23234   4.23234  8.23234  8.23234
 0.232342  2.23234  2.23234  7.23234

General Functions

julia> f(x) = x^2 - 1
f (generic function with 3 methods)

julia> f(a)
-0.9460173573710713

Consider the function $f : \mathbb{R} \to \mathbb{R}$, for example. Since this is a scalar function, it calculates well for $a \in \mathbb{R}$ as shown above.

julia> f(A)
ERROR: LoadError: DimensionMismatch

However, if we attempt to input a matrix $A$, we encounter a LoadError. Upon reflection, the very concept of squaring a matrix, especially a rectangular matrix like $A \in \mathbb{Z}_{9}^{3 \times 4}$, is ambiguous, thus we cannot simply input it into a function like $f(x) = x^{2} - 1$. Yet, if what we desire is a matrix derived from taking the square of each value in matrix $A$ and then subtracting $1$, by placing a dot . as in f., we can apply the function $f : \mathbb{R} \to \mathbb{R}$ to every element of the matrix.

julia> f.(A)
3×4 Matrix{Int64}:
 24  35   8   8
 48  15  63  63
 -1   3   3  48

Speed Comparison

In many cases, broadcasting is also superior in terms of performance. However, when evaluating performance based on speed, there are some nuances to be aware of, which are crucial to understand as indicated below.

For instance, the following code squares the numbers from 1 to 100,000.

julia> @time for x in 1:100000
           sqrt(x)
       end
  0.000001 seconds

julia> @time sqrt.(1:100000);
  0.000583 seconds (2 allocations: 781.297 KiB)

Comparing simple speed, broadcasting is about 500 times slower than a for loop. However, this benchmark, derived from simple calculations, changes if we include processes such as storage ― then the story differs.

julia> z = []
Any[]

julia> @time for x in 1:100000
           push!(z, sqrt(x))
       end
  0.005155 seconds (100.01 k allocations: 3.353 MiB)

julia> @time y = sqrt.(1:100000);
  0.000448 seconds (2 allocations: 781.297 KiB)

Whether or not the process includes storage, the code with broadcasting remains unchanged. However, for a loop that needs to add values to an empty array, it’s about 10 times slower than vectorized code. This could be attributed to the cost of handling a dynamic array with push!() rather than sqrt() itself, but in any case, broadcasting turns out to be faster. Naturally, there are ways to make loops faster (for example, changing Any[] to Float64[] would help), but in most coding scenarios encountered in reality, using broadcasting is not only more convenient but also superior in speed.

This goes beyond merely conceptual issues, also relating to Julia being closer to a compiled language rather than an interpreted one1. If you were a compiler, wouldn’t you prefer compiling for a vector, whose type and size are specifically defined, over a for loop, where what happens next is uncertain?

It’s safe to say that in about 99% of functions, using the Julia developers’ designed method is faster than crafting loops ourselves. There’s no need to force vectorization of code, but when it can be vectorized, it’s overwhelmingly… indeed overwhelmingly faster. This is not unique to Julia, but is a characteristic of languages specialized in vector operations like Matlab, R. However, Julia sets itself apart by embracing the paradigm of functional programming while confidently asserting its speed advantage.

Environment

  • OS: Windows
  • julia: v1.7.0