Buffon's needle on an Arduino Uno
Drop thousands of random needles on a floor of lines, count the crossings and watch a 16x2 LCD close in on pi, with no sine, square root or pi in the sketch. The whole build, an Arduino Uno and 4 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate Runs in your browser. Free, and no account needed.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Buffon's needle: find pi by dropping needles at random onto a floor of
// parallel lines and counting how many land across one.
//
// LCD 16x2 with an I2C backpack: SDA -> A4, SCL -> A5
// button pin 2 -> button -> GND (INPUT_PULLUP): start again
// lamp pin 5 -> 220 ohms -> LED -> GND: blinks on a crossing
//
// Georges-Louis Leclerc, Comte de Buffon, asked the question in the 1700s.
// Drop a needle as long as the lines are apart. It crosses a line with a
// chance of 2 / pi, so after N drops with H crossings, pi is about 2N / H.
//
// Each drop picks two random things: how far the needle's middle is from the
// nearest line (0 to half the gap), and which way it points. The direction
// comes from a random point inside a circle, thrown away and picked again if
// it lands outside, so every direction is equally likely and the sketch never
// needs pi, sine or a square root to find pi. The needle crosses when
//
// distance * r <= half the needle * |y|
//
// where (x, y) is the point and r its distance from the middle. Both sides
// are squared to keep it in whole numbers.
//
// The estimate wanders and then settles slowly: ten times the drops buys
// about one more correct digit. That slowness is the lesson.
//
// Things to try. Press the button to start again. Watch how far off it is
// after 100 drops, then after 10,000.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const int BUTTON_PIN = 2;
const int LAMP_PIN = 5;
const long HALF = 1000; // half the needle, and half the gap between lines
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long drops = 0, hits = 0;
unsigned long nextShow = 0;
unsigned long nextReport = 100;
void reset() {
drops = 0;
hits = 0;
nextReport = 100;
lcd.clear();
lcd.print("Dropping needles");
Serial.println("Buffon's needle: dropping needles");
}
void drop() {
long distance = random(0, HALF + 1); // middle to the nearest line
long x, y, r2;
do {
x = random(-HALF, HALF + 1);
y = random(-HALF, HALF + 1);
r2 = x * x + y * y;
} while (r2 > HALF * HALF || r2 == 0);
drops++;
// distance * r <= HALF * |y|, squared on both sides; in 64 bits, since the
// squares of numbers near a million do not fit in 32.
if ((uint64_t)(distance * distance) * (uint64_t)r2 <= (uint64_t)(HALF * HALF) * (uint64_t)(y * y)) {
hits++;
digitalWrite(LAMP_PIN, HIGH);
} else {
digitalWrite(LAMP_PIN, LOW);
}
}
void show() {
lcd.setCursor(0, 0);
lcd.print("N ");
lcd.print(drops);
lcd.print(" H ");
lcd.print(hits);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("pi ~ ");
if (hits > 0) lcd.print(2.0 * drops / hits, 4);
lcd.print(" ");
}
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LAMP_PIN, OUTPUT);
lcd.init();
lcd.backlight();
randomSeed(analogRead(A0)); // a floating pin for a different run each time
reset();
}
void loop() {
if (digitalRead(BUTTON_PIN) == LOW) {
reset();
while (digitalRead(BUTTON_PIN) == LOW) delay(10);
}
drop();
if (millis() >= nextShow) {
nextShow = millis() + 250;
show();
}
if (drops == nextReport && hits > 0) {
Serial.print(drops);
Serial.print(" drops, ");
Serial.print(hits);
Serial.print(" crossings: pi is about ");
Serial.println(2.0 * drops / hits, 4);
nextReport *= 10;
}
}
Parts list
6 parts, plus the jumper wires. Every one is in the editor's parts bin.
- 1 × Arduino Uno R3
- 1 × Half breadboard
- 1 × Pushbutton
- 1 × Resistor, 220 Ω
- 1 × LED, green
- 1 × Character LCD with I2C backpack
How it is wired
7 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- Arduino Uno R3 pin 5; Resistor, 220 Ω pin 1
- Arduino Uno R3 pin 2; Pushbutton pin 1a
- Arduino Uno R3 pin 5V; Character LCD with I2C backpack pin VCC
- Ground: Arduino Uno R3 pin GND; Pushbutton pin 2a; LED, green pin C; Character LCD with I2C backpack pin GND
- Arduino Uno R3 pin A4; Character LCD with I2C backpack pin SDA
- Arduino Uno R3 pin A5; Character LCD with I2C backpack pin SCL
- Resistor, 220 Ω pin 2; LED, green pin A
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.