投针实验计算Π值的可视化

2019-06-16  本文已影响0人  zhuangX

1.介绍

    18世纪,法国数学家Buffon提出了“投针实验”,即“在平面上画有一组间距为a的平行线,将一根长度为的针l(l≤a)任意掷在这个平面上,求此针与平行线中任一条相交的概率。”,并证明其概率为2l/πa。
    因为它与π有关,所以常用投针实验来估计π值。
    由蒙特卡罗方法(即频率估计概率)可知,掷的次数越多,针与平行线相交的频率越接近概率,此时求出的π值也越来越精确。

2.思路

   下面我们将通过程序可视化该实验并计算π值,为方便起见,我们取针长l=a/2,此时概率为1/π。
   (1) 平面:Canvas
   (2) 线:Canvas中绘制直线
   (3) 针:Canvas中绘制直线(随机生成针头位置(x,y)和针与平行线夹角α)
   (4) 相交概率:针头和针尾与某一平行线的差值乘积小于零说明针与该平行线相交

3.结果

    程序很简单,故不多做赘述。
    可视化如下图所示:


图一 投针实验的可视化

    经验证,实验误差比较大,但还是可以看出在慢慢接近π值。

试验次数 π值
10 10
100 2.9411764705882355
1000 3.125
10000 3.189792663476874
100000 3.1738978639667375

4.代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>needleProblem</title>
</head>
<body>

  <canvas id="myCanvas"></canvas>
  <br>
  <input id="times" type="text">
  <button id="submit">提交</button>
  
  <script type="text/javascript">
  
    // 初始化
    const myCanvas = document.getElementById("myCanvas");
    myCanvas.width = 500;   // 只能在这里设置,CSS中的设置没有作用
    myCanvas.height = 500;
    const context = myCanvas.getContext("2d");
    const a = 10;
    
    let arr = [];
    // 绘制线
    for (let i = 0; i < myCanvas.height; i += a) {
      context.beginPath();
      context.moveTo(0,i);
      context.lineTo(myCanvas.width,i);
      context.closePath();
      context.stroke();
      arr.push(i);
    }
    
    // 绘制针
    const submit = document.getElementById("submit");
    submit.addEventListener("click", function() {
      const times = document.getElementById("times").value;
      const len = a / 2.0;
      let timesPoint = 0;
      for (let i = 0; i < times; i++) {
        let x1 = Math.random() * myCanvas.width;
        let y1 = Math.random() * myCanvas.height;
        let angle = Math.random() * 2 * Math.PI - Math.PI;
        let x2 = x1 + len * Math.cos(angle);
        let y2 = y1 + len * Math.sin(angle);
        context.beginPath();
        context.moveTo(x1, y1);
        context.lineTo(x2, y2);
        context.closePath();
        context.strokeStyle="red";
        context.stroke();
    
        // 检测针与线的交点
        let length = arr.length;
        for (let j = 0; j < length; j++) {
          if ((y1 - arr[j]) * (y2 - arr[j]) <= 0) {
            timesPoint++;
          }
        }
      }
      alert(times/timesPoint);
    });
  </script>
</body>
</html>
上一篇下一篇

猜你喜欢

热点阅读