【数学】通俗解释布丰投针实验过程及python仿真代码

很郁闷为什么网上的布丰投针都写的这么复杂,而且很多都是复读机直接copy别人,其实这是个很精巧、有趣的实验,所以打算自己写一个布丰投针的介绍

故事背景

你在教室里写数学题,突然有个人,抱着一大盒针走过来,然后把针撒到地上,然后很淡定地点点头说,“嗯,我知道π等于多少了”。

是不是觉得很神奇?!这跟π什么关系?!!!

没错,这个人就是布丰。

实验过程

这个实验也很简单,两段距离为D的平行线、一根长为L的针(L≤D)
【数学】通俗解释布丰投针实验过程及python仿真代码_第1张图片
投针实验就是把这根针扔到两段平行线之间,然后统计针碰到平行线的次数,例如图中的两根针,红色针就是碰到,黑色针就是没碰到
【数学】通俗解释布丰投针实验过程及python仿真代码_第2张图片
哪这和π是怎么扯上关系的呢?是从”针碰到平行线“的数学定义中推导得到的。我们先想办法定义针的位置,取针的中点向最近的平行线做垂线,定义该垂线为 X X X,该垂线与针的夹角为 θ θ θ
因为针是在两段平行线之间,故
X ∈ [ 0 , D / 2 ] X\in[0, D/2] X[0,D/2]
同时因为总能找到一个小于90°的角,故
θ ∈ [ 0 , π / 2 ] θ\in[0, π/2] θ[0,π/2]

【数学】通俗解释布丰投针实验过程及python仿真代码_第3张图片
X X X θ θ θ与平行线可以组成一个直角三角形,所以斜边的长度是 X / c o s θ X/cosθ X/cosθ
【数学】通俗解释布丰投针实验过程及python仿真代码_第4张图片
因此,只要
X / c o s θ < L / 2 X/cosθ < L/2 X/cosθ<L/2
即 X < ( L / 2 ) ∗ c o s θ 即X < (L/2)*cosθ X<(L/2)cosθ
的话(其实取≤也可以,影响不大),就说明针碰到了平行线,否则就说明没碰到,下图分别为”没碰到和“碰到”的情况
【数学】通俗解释布丰投针实验过程及python仿真代码_第5张图片
下面我们来表示出“针碰到平行线的概率”,即
P { X < L 2 c o s θ } P\{X<\frac{L}{2}cosθ\} P{X<2Lcosθ}

求概率,本质就是比值,而因为 X X X θ θ θ是连续的,所以上面的比值可以等价于面积的比值

即,当 X X X θ θ θ在其取值范围内变化时,会生成无数个点,这些点的总面积为 S = D 2 ∗ π 2 = D ∗ π 4 S = \frac{D}{2} * \frac{π}{2} = \frac{D*π}{4} S=2D2π=4Dπ (由 X X X θ θ θ的取值范围决定)

在这无数个点中,有一些点满足 X < L 2 c o s θ X<\frac{L}{2}cosθ X<2Lcosθ这一条件,这些点的面积记作 S 1 S_1 S1,所以

P { X < L 2 c o s θ } = S 1 S P\{X<\frac{L}{2}cosθ\} = \frac{S1}{S} P{X<2Lcosθ}=SS1

那怎么把 S 1 S_1 S1表示出来呢?因为针的中心点和角度是没关系的,所以我们可以假设中 X X X θ θ θ是相互独立的,且他们在各自的取值范围内服从均匀分布,所以可以写成
【数学】通俗解释布丰投针实验过程及python仿真代码_第6张图片
剩下的就算微积分的事情了
【数学】通俗解释布丰投针实验过程及python仿真代码_第7张图片
所以可得
P { X < L 2 c o s θ } = 2 ∗ L π ∗ D P\{X<\frac{L}{2}cosθ\} = \frac{2*L}{π*D} P{X<2Lcosθ}=πD2L

接下来,我们就可以反向思维,把 π π π表示出来
π = 2 ∗ L P { X < L 2 c o s θ } ∗ D π = \frac{2*L}{P\{X<\frac{L}{2}cosθ\}*D} π=P{X<2Lcosθ}D2L

所以,只要知道了 L L L D D D P { X < L 2 c o s θ } P\{X<\frac{L}{2}cosθ\} P{X<2Lcosθ}就可以算出 π π π

那问题来了, P { X < L 2 c o s θ } P\{X<\frac{L}{2}cosθ\} P{X<2Lcosθ}不是根据上面积分算出来的吗?你这样不就鸡生蛋蛋生鸡了?

其实 P { X < L 2 c o s θ } P\{X<\frac{L}{2}cosθ\} P{X<2Lcosθ}还可以通过做实验的途径得到,例如我投100次针,其中有50次针碰到了平行线,那么 P { X < L 2 c o s θ } = 50 100 = 0.5 P\{X<\frac{L}{2}cosθ\}=\frac{50}{100}=0.5 P{X<2Lcosθ}=10050=0.5

这样一来, π π π也就能求出来了

这种通过做实验来求积分的方法,就是大名鼎鼎的蒙特卡洛方法
(你也可以认为是暴力求解积分哈哈哈)

以上,就是布丰投针实验求 π π π的过程

代码实验

import random
import numpy as np
from tqdm import tqdm

# 平行线距离
D = 2
# 针的长度
L = 1
# 实验次数
exp_num = 100000000
# 触碰次数
touch_num = 0
for i in tqdm(range(1, exp_num+1)):
    X = random.uniform(0, D / 2)
    theta = random.uniform(0, np.pi / 2)
    if X < (L/2)*np.cos(theta):
        touch_num += 1
# 计算π
P = touch_num/exp_num
print('π = {}'.format((2*L)/(P*D)))

结果为:

π = 3.1412599467996216

大家可能会对theta = random.uniform(0, np.pi / 2)很疑问,我想求得是 π π π,但是代码中就已经给定 π π π(即np.pi),这不就犯规了吗?

其实不是,因为代码中我们要模拟现实的投针场景,所以theta = random.uniform(0, np.pi / 2)就是我们的现实,相当于是上帝提前设定好的,我们不知道的
我们的结果、我们想求的东西,就是希望去找到theta = random.uniform(0, np.pi / 2)中的 π π π(即np.pi)是多少,它是我们的目标,我们希望结果尽可能的接近他

换句话说,如果我把theta = random.uniform(0, np.pi / 2)中的 π π π(即np.pi)换成数字5的话(即改为theta = random.uniform(0, 5 / 2)

我们输出的结果就会非常接近5,因为我们此时想要拟合的目标是5

运行下面的代码(只改了theta那一行),输出结果为:π = 5.00038202918703

import random
import numpy as np
from tqdm import tqdm

# 平行线距离
D = 2
# 针的长度
L = 1
# 实验次数
exp_num = 100000000
# 触碰次数
touch_num = 0
for i in tqdm(range(1, exp_num+1)):
    X = random.uniform(0, D / 2)
    theta = random.uniform(0, 5 / 2)
    if X < (L/2)*np.cos(theta):
        touch_num += 1
# 计算π
P = touch_num/exp_num
print('π = {}'.format((2*L)/(P*D)))

π π π只是个外衣,不要被骗了哈哈哈

布丰投针给我们提供的是一种解决问题的思路,”通过数学推导与实验(蒙特卡洛方法)的配合,求出难以直接计算得到的值“,我认为这才是这个实验的巧妙之处~

你可能感兴趣的:(数学,概率论,数理统计)