
Lecture 12: Advanced Simulation
August 22, 2026
👈 Last lecture we had yet another very math heavy lecture covering:
👇 This lecture we will conclude our study of probability by looking at:
📌 This will be our last R-focused lecture until Lecture 19, but R will still appear in homework and section exercises.
One of the oldest approximation problems humans have been working on is estimating \(\pi\).
There is evidence of estimating \(\pi\) as far back as:
More recently we have estimated \(\pi\) using:

We attempt to construct our own estimate of \(\pi\) using simulation on the unit circle.
Recall from basic trigonometry that the area of a circle is given by:
\[ A = \pi \times r^2. \]
When considering a unit circle \(r=1\), and so
\[ A = \pi. \]
Hence if we can approximate the area of a unit circle we approximate \(\pi\).
To approximate the area of the unit circle our approach is as follows:
\[ \pi \approx 4 \times \text{Prop} \]
We draw a circle!

Then perfectly draw a square around our circle:

Then simulate a lot of points uniformly within the square:

Here we have 77 points within the circle, and so we compute
\[ \pi \approx 4 \times 0.77 = 3.08. \]
⬆️ To increase our accuracy we increase the number of simulations.
Let’s up our simulation count from 100 points to 100,000 points and see what approximation we get.

Here our approximation is 3.13816.
Let’s see how our estimate converges as we increase the number of simulated points \(n\).

📌 As \(n\) grows, the estimate settles down around the true value \(\pi \approx 3.14159\) — the same long-run averaging behaviour we saw earlier with expectation.
Monte Carlo (MC) methods are a study of these types of problems:
runif()).
Consideration 1: Time and computation effort.
Let’s compare how long it takes to simulate 100 versus 1,000,000 random values:
Time difference of 0.001812935 secs
Time difference of 0.01979899 secs
Consideration 2: Error bounds.
Let’s compare the absolute error of our \(\pi\) estimate using \(m=100\) versus \(m=100{,}000\) samples:
[1] 0.1384073
[1] 0.001872654
These considerations are essential in evaluating MC methods.
A method that is easy to do (fast sampling), with predictable error rates that rapidly converges to the true value.
Buffon’s needle is a famous thought problem from the 1700s:
d apart.Interestingly, the probability \(p\) has a closed form expression which we can rearrange to estimate \(\pi\):
\[ p = \frac{2}{\pi}\times \frac{1}{d} \implies \pi = \frac{2}{p} \times \frac{1}{d}. \]
We will simulate the simplest case:
We conduct the following simulation:
D <- runif(m, 0, 0.5) simulates the distance from the needle’s center to the nearest plank, uniform between \(0\) and \(0.5\).theta <- runif(m, 0, pi) simulates the angle of the needle, uniform between \(0\) and \(\pi\).p <- sum(D < 0.5*sin(theta))/m computes the proportion of needles that cross a plank — our estimate of \(p\).We can increase our accuracy by increasing our simulation count.
We have worked with \(e\) every time we have used the exp() function, which is defined as:
\[ \exp(x) = e^x \]
i.e. raising \(e\) to the power of the input of the function.
05:00
Consider how we might estimate \(e\) with Monte Carlo simulation.
Lex Fridman Problem
Write and replicate a function that:
runif() until the sum is \(>1\);m=10000 times to approximate \(e\).above_one() keeps drawing uniform random numbers and adding them to a running total i, counting how many draws it takes until that total exceeds \(1\).count is therefore the number of draws needed for a single trial’s running sum to pass \(1\).mean(replicate(m, above_one())) repeats this trial m=10000 times and averages the counts, giving our Monte Carlo estimate of \(e\).The golden ratio \(\phi\) is another important mathematical constant, which is defined as
\[ \phi = \frac{a}{b}\quad s.t.\quad \frac{a+b}{a} = \frac{a}{b}. \]
We have encountered \(\phi\) previously when working with the Fibonacci sequence.

We estimate the golden ratio as follows:
📌 This approach requires many trials.
📌 Recall that the actual value is: 1.61803…
Let’s see how our estimate converges as we increase the number of trials \(m\).

📌 As \(m\) grows, the estimate settles down around the true value \(\phi \approx 1.61803\).
We compute the following integral via simulation
\[ \int_0^5 x^3 dx. \]
Granted this is not a very interesting integral, but at least it is quite simple.
Idea: Express the integral as the expectation of a random variable, say \(X\sim\mathcal{U}(0,5)\) with PDF
\[ f_X(x) = \frac 15\quad \text{for}\quad 0<x<5. \]
We can rewrite the integral as follows:
\[ \begin{aligned} \int_0^5 x^3 dx & = \int_0^5 5x^3 \times 1/5 ~dx \\ & = \int_0^5 5x^3 f_X(x)~dx \\ & = \mathbb{E}[5X^3]. \end{aligned} \]
Where \(X\sim\mathcal{U}(0,5)\). The problem reduces to:
Computing the actual value analytically we have:
\[ \int_0^5 x^3dx = \left[\frac{x^4}{4}\right]_0^5=\frac{5^4}{4} = 156.25. \]
The Monty Hall problem is another famous probability puzzle with the following setup:
📌 Question: Should you change your guess?

Solution: It is always better to switch doors!
Computing the odds of winning using conditional probability we find that:
This seems counter intuitive! Surely it is just 50/50, i.e. \(1/2\) for both — there are two doors and 1 is the winner?
monty_hall_game <- function(strategy) {
prize_door <- sample(1:3, 1) # set door with car
player_choice <- sample(1:3, 1) # set player choice
remaining_doors <- setdiff(1:3, c(prize_door, player_choice))
if (length(remaining_doors) == 1) { revealed_door <- remaining_doors}
else { revealed_door <- sample(remaining_doors, 1)} # open door
if (strategy == "stay") { # stay put
final_choice <- player_choice
} else { # switch doors
options <- setdiff(1:3, c(revealed_door, player_choice))
if (length(options) == 1) {
final_choice <- options
} else {
final_choice <- sample(options, 1)
}
}
win <- final_choice == prize_door; return(win)
}monty_hall_game() plays one round of the game for a given strategy ("stay" or "switch") and returns whether the player won.strategy, the player’s final choice is either their original pick or the one remaining unopened door.We initially set the door with the prize, selected door and remaining door.
We then simulate the host picking a door.
We then decide whether to switch or stick with the current door.
Let’s use our simulation to test the claim that switching is better, by playing many games under each strategy.
m, the closer these simulated win rates get to the true \(1/3\) and \(2/3\) probabilities.🤔 We have now looked through several examples of more complex simulation, including simulating:
📌 That’s all we need for probability in PSTAT 10!
🤩 Next class we will be moving away from RStudio and will instead be focusing on: