Broadcasting *= and the like

I tried using broadcast for computing the radicals of integers 1 to limit. But it was significantly slower than the for loop version. Am I doing something wrong? I tried map! but I’m not sure if I got it right so please include that as well (and any other not so complicated alternative).

function getradicals(limit)
    radicals = ones(Int, limit)

    for i ∈ Iterators.filter(x -> isone(radicals[x]), 2:length(radicals))
        radicals[i:i:end] .*= i
        #for j ∈ i:i:length(radicals)
        #    radicals[j] *= i
        #end
    end

    radicals
end

Broadcasting *= doesn’t seem to be a problem, but you’re allocating a temporary array at each iteration i when saying radicals[i:i:end]. You can avoid this by either using @views or the loop you’ve commented out.

julia> using BenchmarkTools

julia> function getradicals1(limit)
           radicals = ones(Int64, limit)

           for i ∈ Iterators.filter(x -> isone(radicals[x]), 2:length(radicals))
               radicals[i:i:end] .*= i
               #for j ∈ i:i:length(radicals)
               #    radicals[j] *= i
               #end
           end

           radicals
       end
getradicals1 (generic function with 1 method)

julia> @btime getradicals1(100);
  1.560 μs (26 allocations: 4.33 KiB)

julia> function getradicals2(limit)
           radicals = ones(Int64, limit)

           for i ∈ Iterators.filter(x -> isone(radicals[x]), 2:length(radicals))
               @views radicals[i:i:end] .*= i
               #for j ∈ i:i:length(radicals)
               #    radicals[j] *= i
               #end
           end

           radicals
       end
getradicals2 (generic function with 1 method)

julia> @btime getradicals2(100);
  824.390 ns (1 allocation: 896 bytes)

julia> function getradicals3(limit)
           radicals = ones(Int64, limit)

           for i ∈ Iterators.filter(x -> isone(radicals[x]), 2:length(radicals))
               #radicals[i:i:end] .*= i
               for j ∈ i:i:length(radicals)
                   radicals[j] *= i
               end
           end

           radicals
       end
getradicals3 (generic function with 1 method)

julia> @btime getradicals3(100);
  414.065 ns (1 allocation: 896 bytes)
1 Like

I read somewhere that a += b is converted to a = a + b. I only realized it after using @views. Thanks!
Additional but related question. How would I use broadcasting for something like

radicals[j] -= radicals[j] \div i

instead of

radicals[j] *= i

in the inner loop?

This seems to work

@. @views radicals[i:i:end] -= radicals[i:i:end] \div i