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>
网友评论