Skip to content

Commit b05afe0

Browse files
authored
map in +/- for Arrays (#59961)
`map` is a simpler operation and uses linear indexing for `Array`s. This often improves performance (occasionally enabling vectorization) and improves TTFX in common cases. It also automatically returns the correct result for 0-D arrays, unlike broadcasting that returns a scalar. Performance: ```julia julia> A = ones(3,3); julia> @Btime $A + $A; 44.622 ns (2 allocations: 144 bytes) # v"1.13.0-DEV.1387" 29.047 ns (2 allocations: 144 bytes) # this PR julia> A = ones(3,3000); julia> @Btime $A + $A; 10.095 μs (3 allocations: 70.40 KiB) # v"1.13.0-DEV.1387" 4.787 μs (3 allocations: 70.40 KiB) # this PR julia> @Btime A + B + C + D + E + F setup=(A = rand(200,200); B = rand(200,200); C = rand(200,200); D = rand(200,200); E = rand(200,200); F = rand(200,200)); 93.910 μs (3 allocations: 312.59 KiB) # v"1.13.0-DEV.1387" 64.813 μs (9 allocations: 312.77 KiB) # this PR ``` Similarly for `-`. TTFX: ```julia julia> A = ones(3,3); julia> @time A + A; 0.174090 seconds (303.47 k allocations: 14.575 MiB, 99.98% compilation time) # v"1.13.0-DEV.1387" 0.072748 seconds (220.27 k allocations: 11.139 MiB, 99.95% compilation time) # this PR ``` These are measured on ```julia julia> versioninfo() Julia Version 1.13.0-DEV.1388 Commit c5f4927 (2025-10-27 11:44 UTC) Platform Info: OS: Linux (x86_64-linux-gnu) CPU: 8 × Intel(R) Core(TM) i5-10310U CPU @ 1.70GHz WORD_SIZE: 64 LLVM: libLLVM-20.1.8 (ORCJIT, skylake) GC: Built with stock GC Threads: 1 default, 1 interactive, 1 GC (on 8 virtual cores) Environment: LD_LIBRARY_PATH = /usr/local/lib: JULIA_EDITOR = subl ```
1 parent c0d34aa commit b05afe0

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

base/arraymath.jl

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,45 @@
22

33
## Binary arithmetic operators ##
44

5+
function _broadcast_preserving_zero_d(f, A, B)
6+
broadcast_preserving_zero_d(f, A, B)
7+
end
8+
9+
# Using map over broadcast enables vectorization for wide matrices with few rows.
10+
# This is because we use linear indexing in `map` as opposed to Cartesian indexing in broadcasting.
11+
# https://github.com/JuliaLang/julia/issues/47873#issuecomment-1352472461
12+
function _broadcast_preserving_zero_d(f, A::Array, B::Array)
13+
map(f, A, B)
14+
end
15+
16+
function _broadcast_preserving_zero_d(f, A::Array, B::Number)
17+
map(Fix2(f, B), A)
18+
end
19+
20+
function _broadcast_preserving_zero_d(f, A::Number, B::Array)
21+
map(Fix1(f, A), B)
22+
end
23+
524
for f in (:+, :-)
625
@eval function ($f)(A::AbstractArray, B::AbstractArray)
726
promote_shape(A, B) # check size compatibility
8-
broadcast_preserving_zero_d($f, A, B)
27+
_broadcast_preserving_zero_d($f, A, B)
928
end
1029
end
1130

1231
function +(A::Array, Bs::Array...)
1332
for B in Bs
1433
promote_shape(A, B) # check size compatibility
1534
end
16-
broadcast_preserving_zero_d(+, A, Bs...)
35+
map(+, A, Bs...)
1736
end
1837

1938
for f in (:/, :\, :*)
2039
if f !== :/
21-
@eval ($f)(A::Number, B::AbstractArray) = broadcast_preserving_zero_d($f, A, B)
40+
@eval ($f)(A::Number, B::AbstractArray) = _broadcast_preserving_zero_d($f, A, B)
2241
end
2342
if f !== :\
24-
@eval ($f)(A::AbstractArray, B::Number) = broadcast_preserving_zero_d($f, A, B)
43+
@eval ($f)(A::AbstractArray, B::Number) = _broadcast_preserving_zero_d($f, A, B)
2544
end
2645
end
2746

0 commit comments

Comments
 (0)