# Broadcasting of minus as prefix operator

Hello, I have the following technical question: when using - as prefix operator, does it get broadcasted as it would be an operator with a dot, i.e. is this

``````x = 2
y = [1,2,3]
z = -x .+ y
``````

equivalent to

``````x = 2
y = [1,2,3]
z = -1 .* x .+ y
``````

because it would matter in terms of performance.

At least the `@code_lowered` after defining a function is not the same:

``````f(x,y) = -x .+ y
CodeInfo(
91 1 ─ %1 = Base.Broadcast.materialize                               │
│   %3 = -x                                                       │
│   %4 = (%2)(Main.:+, %3, y)                                     │
│   %5 = (%1)(%4)                                                 │
└──      return %5                                                │
)
``````
``````f(x,y) = -1 .* x .+ y
CodeInfo(
91 1 ─ %1 = Base.Broadcast.materialize                               │
│   %4 = (%3)(Main.:*, -1, x)                                     │
│   %5 = (%2)(Main.:+, %4, y)                                     │
│   %6 = (%1)(%5)                                                 │
└──      return %6
``````

Thanks.

The Unary `-` operator has higher precedence than the addition operator, so yes.

Performance wise, they’re virtually equivalent:

``````julia> using BenchmarkTools

julia> f(x,y) = -x .+ y
f (generic function with 1 method)

julia> g(x,y) = -1 .* x .+ y
g (generic function with 1 method)

julia> @btime f(\$x, \$y)
32.161 ns (1 allocation: 112 bytes)
3-element Array{Int64,1}:
-1
0
1

julia> @btime g(\$x, \$y)
32.193 ns (1 allocation: 112 bytes)
3-element Array{Int64,1}:
-1
0
1
``````
1 Like

It is equivalent to `z = (-x) .+ y`. At least that’s what I take from `@code_lowered`:

``````julia> f() = z = -x .+ y
f (generic function with 1 method)

julia> @code_lowered f()
CodeInfo(
1 1 ─ %1 = Base.Broadcast.materialize                                                                                                                                                                                              │
│   %3 = -Main.x                                                                                                                                                                                                                 │
│   %4 = (%2)(Main.:+, %3, Main.y)                                                                                                                                                                                               │
│   %5 = (%1)(%4)                                                                                                                                                                                                                │
│        z = %5                                                                                                                                                                                                                  │
└──      return %5                                                                                                                                                                                                               │
)
``````

Sorry, I was a little bit misleading in my example, I wanted `x` to be an array as well. Now I have the test and it is not the same speed !!!

``````julia> using BenchmarkTools

julia> x = [4,5,6];

julia> y = [1,2,3];

julia> f(x,y) = -1 .* x .+ y ;

julia> g(x,y) = -x .+ y ;

julia> @code_lowered f(x,y)
CodeInfo(
1 1 ─ %1 = Base.Broadcast.materialize                                                               │
│   %4 = (%3)(Main.:*, -1, x)                                                                     │
│   %5 = (%2)(Main.:+, %4, y)                                                                     │
│   %6 = (%1)(%5)                                                                                 │
└──      return %6                                                                                │
)

julia> @code_lowered g(x,y)
CodeInfo(
1 1 ─ %1 = Base.Broadcast.materialize                                                               │
│   %3 = -x                                                                                       │
│   %4 = (%2)(Main.:+, %3, y)                                                                     │
│   %5 = (%1)(%4)                                                                                 │
└──      return %5                                                                                │
)

julia> @btime f(\$x,\$y)
107.821 ns (1 allocation: 112 bytes)
3-element Array{Int64,1}:
-3
-3
-3

julia> @btime g(\$x,\$y)
201.928 ns (2 allocations: 224 bytes)
3-element Array{Int64,1}:
-3
-3
-3
``````

This is bad, I would say. Because `-x` is much more convenient than `-1 .* x` when dealing with longer expressions.

If `x` is an array, just dot the `-` as well:

``````julia> f(x,y) = .-x .+ y
f (generic function with 1 method)

julia> g(x,y) = -1 .* x .+ y
g (generic function with 1 method)

julia> @btime f(\$x,\$y)
39.354 ns (1 allocation: 112 bytes)
3-element Array{Int64,1}:
-3
-3
-3

julia> @btime g(\$x,\$y)
39.315 ns (1 allocation: 112 bytes)
3-element Array{Int64,1}:
-3
-3
-3
``````

The reason it’s gotten slower if you don’t dot it as well is because if an expression has all dots, the compiler can fuse all the broadcasts into a single call, greatly reducing overhead. The same can be achieved with `@.` which dots every operator/function call:

``````julia> h(x,y) = @. -x + y
h (generic function with 1 method)

julia> @btime h(\$x,\$y)
39.315 ns (1 allocation: 112 bytes)
3-element Array{Int64,1}:
-3
-3
-3
``````
2 Likes

Thanks, I accidentally tried `-.x .+ y` before writing this post and this did not worked, of cause.

Yes, I know, just did not realiesed that using `.-` is the right way for writing it, because usually for a function you use `f.()` so I thougt it should be `-.x`.

`-` is an operator though, and those usually go with the dot beforehand:

``````julia> a = [1,2,3]
3-element Array{Int64,1}:
1
2
3

julia> b = [3,4,5]
3-element Array{Int64,1}:
3
4
5

julia> a .+ b
3-element Array{Int64,1}:
4
6
8
``````

The other way around is even in “function syntax” wrong:

``````julia> .-(a)
3-element Array{Int64,1}:
-1
-2
-3

julia> -.(a)
ERROR: syntax: numeric constant "-." cannot be implicitly multiplied because it ends with "."
``````

Yeah, will remember that in future