Introduction
There is a simple experiment you can perform to estimate the value of π, i.e. 3.14159…, using a random number generator. Explicitly, π is defined as the ratio of a circle’s circumference to its diameter, \(\pi = C/d\) where \(C\) and \(d\) are the circumference and diameter, respectively. Also recall the area of a circle is \(\pi r^2 = A\)
For this experiment, you’ll need a programming language with a random number generator that will generate uniform random numbers, or that is randomly pick a number over a uniform distribution.
What does a uniform random number mean? Let us consider a discrete (numbers that are individually separate and distinct) example:
Consider the game where you have a dozen unique marbles in a bag. You pick one at random, record the color, and then return it. Over time (i.e. thousands of draws), you will notice that approximately each marble will be drawn approximately the same number of times. That is because, theoretically, there is no bias toward any specific marble in the bag. It’s the same concept, in an ideal world a random number will be be picked without bias to any other number.
Unfortunately, computers are not truly random. Most, if not all, random numbers are pseudo-random number generators. They rely on mathematical formulations to generate random numbers (which, can’t be random!). However, they have a depth and complexity to sufficiently provide a program with a random number.
Python’s Random Function
To attempt to compute the value of π using this random sampling, consider python’s random number generator. Using the function
random.random()
you can draw a random floating point number in the range [0.0, 1.0).
So In your preferred Python IDE of choice, import the random module.
import random
after typing
random.random()
a few dozen times, you should begin to see that you’ll get a random number between 0 and 1.
Consider the circle
Now, consider a geometric representation of a circle. In a Cartesian plane a circle centered at the origin can be represented as the following equation:
\((x^2 + y^2)^{1/2} = a\)
and the area of a circle as:
\(\pi r^2 = A_C\)
In addition, consider a square that is circumscribed around the same circle:
\((2 \times r)^2 =A_S\)
Visually:
Looking at the figure above, assume we pick a uniformly random point that is bounded by the blue square \(S\), what is the chance that the point chosen would be inside the circle \(C\) as well? It would be the ratio of the area of the circle \(A_c\) to the area of the square \(A_s\), that is the probability of selecting a point in \(S\) and \(C\) is \(P\{S \& C\}\)
\(P\{S \& C\} = A_C/A_S\)
\(P\{S \& C\} = {\pi r^2}/{(2r)^2}\)
Of course, assuming a \(r>0\)
\(P\{S \& C\} = {\pi}/{4}\)
So the chance of selecting a point in the square \(S\) that is also inside the circle \(C\) is \({\pi}/{4}\)
Coding the experiment in Python
To test this experiment Pythonically, let us consider a square and circle centered at the origin and, for simplicity, we draw only positive numbers from the random number generator:
def GetPoint(): # Returns True if the point is inside the circle. x, y = random.random(), random.random() # uniform [0.0, 1.0) return math.sqrt(x**2+y**2) <= 1
GetPoint() tests if randomly generated point from inside the square is also inside the circle.
Since we are only considering one-quarter the area of the circle and one-quarter the area of the square, the reduction cancels out and we are still left with the relationship of \(\pi/4\). To call the experiment and estimate π, we must interpret what happens when a random point is inside the circle. In Python, we can write:
def circle_estimator(n): i = 0 for k in range(n): if GetPoint(): i += 1 return 4 * i / n # returns the estimated value of pi
For this experiment to work, we must execute it many times. If we only call GetPoint() once, there is a chance it will say π is 4 or 0! Clearly not a close value to π.
Running the experiment for multiple iterations, the following is the results of the estimated value of π:
Iterations | Estimation | Pct |
10 | 3.4 | 8.23% |
100 | 3.12 | -0.69% |
10000 | 3.1552 | 0.43% |
1000000 | 3.143532 | 0.06% |
Close! However, this is clearly not as efficient as just calling
math.pi