Skip to content

Instantly share code, notes, and snippets.

@pikesley
Created December 21, 2023 19:19
Show Gist options
  • Save pikesley/9c0e00cc706195c0db200d5a39b1d282 to your computer and use it in GitHub Desktop.
Save pikesley/9c0e00cc706195c0db200d5a39b1d282 to your computer and use it in GitHub Desktop.
Approximating Pi by throwing darts

From my ancient blogpost. To run it:

  • Download these files somewhere on your computer (probably in a fresh directory)
  • Run make
  • Watch the pretty numbers
FROM python:3.12
ARG PROJECT
COPY ./ /opt/${PROJECT}
WORKDIR /opt/${PROJECT}
PROJECT = $(shell basename $(shell pwd))
ID = pikesley/${PROJECT}
default: pi
build:
docker build \
--build-arg PROJECT=${PROJECT} \
--tag ${ID} .
run:
docker run \
--name ${PROJECT} \
--volume $(shell pwd):/opt/${PROJECT} \
--rm \
--interactive \
--tty \
${ID} bash
pi: build
docker run \
--name ${PROJECT} \
--volume $(shell pwd):/opt/${PROJECT} \
--rm \
--interactive \
--tty \
${ID} python montecarlo.py
#!/usr/bin/env python
import random
import math
class Throw:
def __init__(self):
# generate two random coordinates and work out how far away we are from
# the origin
self.x = random.random()
self.y = random.random()
self.distance = self.distance()
def distance(self):
# the distance from the origin is the hypotenuse of a right-angled
# triangle with sides of length and x and y. Pythagoras told us that:
# distance = sqrt((x^2) + (y^2))
# which looks like this in python
return math.sqrt(self.x**2 + self.y**2)
# did we land inside the quadrant?
def is_a_hit(self):
return self.distance <= 1.0
class MonteCarlo:
def __init__(self):
self.hits = 0
self.throws = 0
self.pi = 0
def increment(self, throw):
self.throws += 1
if throw.is_a_hit():
self.hits += 1
self.calculate_pi()
def calculate_pi(self):
self.pi = 4 * (float(self.hits) / float(self.throws))
def divides_by(self, number):
return float(self.throws) % number == 0
def __repr__(self):
return "Throws: %10d, Hits: %10d, Pi: %10f, Actual Pi: %10f" % (
self.throws,
self.hits,
self.pi,
math.pi,
)
if __name__ == "__main__":
import sys
try:
step = int(sys.argv[1])
except IndexError:
step = 1000
m = MonteCarlo()
# loop forever
while 1:
m.increment(Throw())
# only print on every nth iteration
if m.divides_by(step):
print(m)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment