布冯的针(Java实现)

时间:2013-10-26 00:38:12

标签: java algorithm pi

** 首先我要说的是,这个问题是"作业启发":它是统计力学的作业,并没有涉及编程,所以我把作业标签留了出来。 **

我试图用java的方法实现Buffon估计pi的方法, 但是我的结果太过分了,不是很多 - 但是有一个着名的结果,使用针/空间比为5/6,这应该给出比我得到的更好的估计。 我希望你的帮助能够理解为什么我的结果不准确。

(对于这种方法,有一个很好的解释,有动画,在wikipedia

我的想法是:

如果针的中心垂直位置+垂直投影(半长* sin(角度))大于线的位置,则减去垂直投影的位置小于线的位置:那意味着针的一端在线的上方而另一端在它的下方,这意味着它的交叉点。

(这几乎是中间值定理)

我尝试的事情:

  • 将随机数更改为任何大于0.99的随机数得1,并没有什么区别。
  • 检查位置/(行间距离)和sin(角度)值是否有效,在[0,1]范围内 并且分布大致均匀;例如:在149100次迭代中,两个数字的75000都大于0.5。
  • 检查(并证明)数学(中间值定理),只有当引脚与线相交时才计算迭代次数。

这是实现(我是编程的新手,所以我很乐意接收有关代码本身的评论):

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

2 个答案:

答案 0 :(得分:2)

  

我是编程的新手,所以我很乐意接收有关代码本身的评论

这里是:

  1. 不要抓住Exception。捕获您预期的特定异常,然后传播其他异常。

  2. 如果您抓住了Exception,请确保您处理所有的可能性。您当前的实现假定该问题将是无效的数字。它可能是其他的东西;例如标准输入位于EOF位置,一些(假设的)错误导致NPE,等等。

  3. 本地变量应始终以小写字母开头; Num - &gt; num

  4. checkNumber处理错误(通过递归)的方式存在问题。如果根本原因不正确的用户输入,但重试无法治愈的东西,你将最终得到无限递归!在Java中,这将导致StackOverflowError ...和大量堆栈跟踪(如果它被打印)。

答案 1 :(得分:1)

嗯,原来没有任何问题,估计错误是

Math.sqrt((Math.PI*Math.PI)/(2*iterations) * (Math.PI * (iterations/intersections  - 2) ))

并且可以使用概率的渐近方差导出。

Pi估计在误差范围内。