** First I want to say, that this question is "homework-inspired": it was homework in Statistical Mechanics, and did not involve programming so I left the homework tag out. **
I have tried to implement Buffon's needle method for estimation of pi in java, but my results are too off, not by much - but there is a famous results using needle/space ratio as 5/6 which should give a better estimation than I'm getting. I would like your help to understand why my results are not accurate.
(For the method, there is a good explanation, with animation, in wikipedia )
My idea was this :
if the the vertical position of the center of the needle + vertical projection (half length*sin(angle)) is greater than the position of a line AND the position minus the vertical projection is less than the position of a line: then that means that one end of the needle is above the line and the other is below it which means there's intersection.
(that's pretty much the intermediate value theorem)
Things I tried:
This is the implementation ( I'm a newbie to programming, so I would gladly receive comments about the code itself):
import java.util.Scanner;
import java.lang.Math;
public class BuffonNeedle {
public static Scanner scan = new Scanner(System.in);
public static double checkNumber(double min) {
String input = scan.next();
if (input.equalsIgnoreCase("END")) {
System.exit(0);
}
try {
double Num = Double.parseDouble(input);
if(Num<=min ) {
System.out.println("Try again: input must be a number greater than "+min);
return checkNumber(min);
}
return Num;
} catch (Exception e) {
System.out.println("Try again: input must be a number greater than "+min);
return checkNumber(min);
} // end try-catch
}// end checkNumber method
public static void main(String[] args) {
double d = 0; // distance between two lines
double l = 0; // size of needle
double angle = 0;
double position = 0; // the position of the center of the pin (in the range of 0 to the distance between two lines)
double estimateOfPi =0; // the result we will finally give (should be Pi)
double iterations = 0;
double intersections = 0; // number of times needle intersected with line, the number is a double due to calculation later
int count = 0;
System.out.println();
System.out.println("Typing END at any stage will cause the program to terminate, otherwise it will run a 100 times.");
System.out.println("if you would like to cheat try- needle: 5 , space: 6 , iterations: a multiply of 213 (like 149100) ");
// cheating is actually for any multiply of (d*355/(2*l)), provided the expression is an integer
System.out.println();
while (count<100) {
if (count >=1) System.out.println("Lets try again.");
System.out.println("Please insert the size of the needle:");
l = checkNumber(0);
System.out.println("Please insert the size between two lines:");
d = checkNumber(l);
System.out.println("How many iterations would you like? (the more iterations - the better chance for close estimate)");
iterations = checkNumber(0);
for(int i=0;i<iterations;i++) {
angle = Math.random()*Math.PI;
position = d * Math.random();
// checking to see if there is indeed an intersection - using the intermediate value theorem.
if( ( ( position + l*Math.sin(angle)/2 >= d ) && ( position - l*Math.sin(angle)/2 <= d ) ) ||
( ( position + l*Math.sin(angle)/2 >= 0 ) && ( position - l*Math.sin(angle)/2 <= 0 ) ) ) {
intersections++;
} // end if
} // end for
estimateOfPi = (2*l*iterations) / (d*intersections);
intersections=0;
System.out.println("π = "+estimateOfPi);
count++;
} // end while
} // end main
} // end class
Well, turns out there is no problem at all, the error of the estimation is
Math.sqrt((Math.PI*Math.PI)/(2*iterations) * (Math.PI * (iterations/intersections - 2) ))
and can be derived using asymptotic variance of the probability.
Pi is estimated within the margin of error.