I used two sets of codes to estimate the value of pi as a simple example of Monte Carlo methods.
Code 1:
function compute_pi(N::Int)
n_landed_in_circle = 0
for i = 1:N
x = rand()
y = rand()
r2 = x*x + y*y
if r2 < 1.0
n_landed_in_circle += 1
end
end
return n_landed_in_circle / N * 4.0
end
Code2:
function compute_pi1(N::Int)
return 4 * sum([1 for _ in filter(_ -> rand()^2 + rand()^2 < 1, 1:N)]) / N
end
I tested the speed with N = 1_000_000_000, and found that code1 is 2 times faster than code 2. I am not sure what makes the difference.
I used Julia 6.2 on Fedora 25 OS with I7 core and 16gb ram.
julia> function sum1() s=0; for i in 1:3 s+=1 end;s;end;
julia> function sum2() sum(1 for i in 1:3); end;
julia> @code_llvm sum1()
julia> @code_llvm sum2()
Is optimization in sum1 Julia compiler’s work or llvm’s?
function compute_pi_ifelse(N::Int)
n_landed_in_circle = 0
for i = 1:N
x = rand()
y = rand()
r2 = x*x + y*y
n_landed_in_circle += ifelse(r2<1.0,1,0)
end
return n_landed_in_circle / N * 4.0
end
Also, if you can (and want to) use memory, you may be able to speed things up further by generating multiple random numbers at once.
The last function below is a little faster on my system (you will need to tune the second argument; here 10’000 seems to work reasonably well).
using Compat, StatsBase,StaticArrays
using Revise
using BenchmarkTools
function compute_pi(N::Int)
n_landed_in_circle = 0
for i = 1:N
x = rand()
y = rand()
r2 = x*x + y*y
if r2 < 1.0
n_landed_in_circle += 1
end
end
return n_landed_in_circle / N * 4.0
end
function compute_pi_ifelse(N::Int)
n_landed_in_circle = 0
for i = 1:N
x = rand()
y = rand()
r2 = x*x + y*y
n_landed_in_circle += ifelse(r2<1.0,1,0)
end
return n_landed_in_circle / N * 4.0
end
function compute_pi_vector(N::Int,vec_size::Int)
n_landed_in_circle = 0
randvec = zeros(vec_size)
counter = vec_size
for i = 1:N
if counter >= vec_size-1
rand!(randvec)
counter = 1
end
@inbounds x = randvec[counter]
@inbounds y = randvec[counter+1]
counter += 2
r2 = x*x + y*y
n_landed_in_circle += ifelse(r2<1.0,1,0)
end
return n_landed_in_circle / N * 4.0
end
@benchmark compute_pi_ifelse(1_000_000)
@benchmark compute_pi_vector(1_000_000,100)
@benchmark compute_pi_vector(1_000_000,1000)
@benchmark compute_pi_vector(1_000_000,10000)