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 my ancient blogpost. To run it:
make| 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) |