Not the most efficient way of computing
As we very well know, there are a lot of ways to compute . There is even a blog entry in the Julia blog for that. Nevertheless, we decided for a different method (that is part of the introductory courses on JuliaAcademy).
A circle with radius has an area of
The ratio between the area of the circle and the area of the square is
The above formula suggests that we can compute by a Monte Carlo Method. Actually this example is also included in the Wiki article and it comes with this nice gif.

The algorithm therefore becomes:
For a given number of uniformly scattered points in the quadrant determine if these points are in the circle (distance less than 1) or not. We call the number of points in the circle .
Estimate by computing
For the following Exercises, we will use and complete the following code stub:
# You will need some Packages. Add them here by using <PACKAGE>.
function sample_M_non_distributed_rng(N::Int64, rng::AbstractRNG)
# Exercise 1 (pt 1/2)
return nothing
# Exercise 1 end
end
function estimate_pi(N::Int64, method::Symbol)
function sample_M_non_distributed(N::Int64)
return sample_M_non_distributed_rng(N, Random.default_rng())
end
function sample_M_threaded(N::Int64)
# Exercise 2
return nothing
# Exercise 2 end
end
function sample_M_threaded_atomic(N::Int64)
# Exercise 3
return nothing
# Exercise 3 end
end
function sample_M_threaded_tasksafe(N::Int64)
# Exercise 4
return nothing
# Exercise 4 end
end
function sample_M_threaded_over_buckets(N::Int64)
# Exercise 5
return nothing
# Exercise 5 end
end
function sample_M_threaded_over_buckets_rng(N::Int64)
# Exercise 6
return nothing
# Exercise 6 end
end
function_mapping = Dict(
:ex1 => sample_M_non_distributed,
:ex2 => sample_M_threaded,
:ex3 => sample_M_threaded_atomic,
:ex4 => sample_M_threaded_tasksafe,
:ex5 => sample_M_threaded_over_buckets,
:ex6 => sample_M_threaded_over_buckets_rng,
)
M = function_mapping[method](N)
# Exercise 1 (pt 2/2)
return nothing
# Exercise 1 end
end
Complete the function
sample_M_non_distributed
which samples for givenN
and random number generatorrng
.At the bottom of
estimate_pi
use to compute an estimate for . Also compute the absolute error and return both values.Test your code with different values for . You can run your implementation like this:
estimate_pi(N, :ex1)
(defineN
beforehand).Benchmark your naive implementation (we will keep improving it later).
Hint: The function rand()
(without additional arguments) generates a random sample from a uniform distribution spanning the interval . You can also pass rng
to rand()
for using a specific random number generator.
using BenchmarkTools
using Random
function sample_M_non_distributed_rng(N::Int64, rng::AbstractRNG)
M = zero(Int64)
for _ in 1:N
if (rand(rng)^2 + rand(rng)^2) < 1
M += 1
end
end
return M
end
function estimate_pi(N::Int64, method::Symbol)
function sample_M_non_distributed(N::Int64)
return sample_M_non_distributed_rng(N, Random.default_rng())
end
function_mapping = Dict(
:ex1 => sample_M_non_distributed,
)
M = function_mapping[method](N)
est_pi = 4 * M / N
return est_pi, abs(pi - est_pi)
end
N = 2^30
@btime estimate_pi(N, :ex1)
3.718 s (4 allocations: 384 bytes)
(3.1414526104927063, 0.00014004309708681717)