import numpy as np
import matplotlib.pylab as plt
class Buffon_needle_problem:
def __init__(self,x,y,n,m):
self.x = x #width of the needle
self.y = y #witdh of the space
self.r = []#coordinated of the centre of the needle
self.z = []#measure of the alingment of the needle
self.n = n#no of throws
self.m = m#no of simulations
self.pi_approx = []
def samples(self):
# throwing the needles
for i in range(self.n):
self.r.append(np.random.uniform(0,self.y))
self.z.append(np.random.uniform(0,self.x/2.0))
return [self.r,self.z]
def simulation(self):
self.samples()
# m simulation
for j in range(self.m):
# n throw
hits = 0 #setting the succes to 0
for i in range(self.n):
#condition for a hit
if self.r[i]+self.z[i]>=self.y or self.r[i]-self.z[i] <= 0.0:
hits += 1
else:
continue
hits = 2*(self.x/self.y)*float(self.n/hits)
self.pi_approx.append(hits)
return self.pi_approx
y = Buffon_needle_problem(1,2,40000,5)
print (y.simulation())
对于那些不熟悉布冯问题的人,这里是http://mathworld.wolfram.com/BuffonsNeedleProblem.html
或
实现相同的想法(和输出) http://pythonfiddle.com/historically-accurate-buffons-needle/
我的预期输出应该是pi的值,但是我的代码给了我4左右。任何人都可以指出逻辑错误吗?
答案 0 :(得分:1)
针的对齐采样应该是均匀的余弦。请参阅以下链接以了解该方法:http://pdg.lbl.gov/2012/reviews/rpp2012-rev-monte-carlo-techniques.pdf
此外,该计划存在一些逻辑问题。这是一个工作版本。
#!/bin/python
import numpy as np
def sample_cosine():
rr=2.
while rr > 1.:
u1=np.random.uniform(0,1.)
u2=np.random.uniform(0,1.)
v1=2*u1-1.
rr=v1*v1+u2*u2
cc=(v1*v1-u2*u2)/rr
return cc
class Buffon_needle_problem:
def __init__(self,x,y,n,m):
self.x = float(x) #width of the needle
self.y = float(y) #witdh of the space
self.r = [] #coordinated of the centre of the needle
self.z = [] #measure of the alignment of the needle
self.n = n #no of throws
self.m = m #no of simulations
self.p = self.x/self.y
self.pi_approx = []
def samples(self):
# throwing the needles
for i in range(self.n):
self.r.append(np.random.uniform(0,self.y))
C=sample_cosine()
self.z.append(C*self.x/2.)
return [self.r,self.z]
def simulation(self):
# m simulation
for j in range(self.m):
self.r=[]
self.z=[]
self.samples()
# n throw
hits = 0 #setting the success to 0
for i in range(self.n):
#condition for a hit
if self.r[i]+self.z[i]>=self.y or self.r[i]-self.z[i]<0.:
hits += 1
else:
continue
est =self.p*float(self.n)/float(hits)
self.pi_approx.append(est)
return self.pi_approx
y = Buffon_needle_problem(1,2,80000,5)
print (y.simulation())
答案 1 :(得分:1)
仅当两行之间的距离是针长的两倍时,布冯针才能正确工作。确保进行交叉检查。
我已经看到许多baffon的在线模拟都在犯此错误。它们只是将两条相邻线之间的距离等于针的长度。这是他们的主要逻辑错误。
答案 2 :(得分:0)
我想说的问题是你是通过一个简单的线性函数定义针的对齐方式,而实际上针的中心有效长度是由正弦函数定义的。
您想通过使用从其角度计算它的函数来计算针的有效长度(与线成90°)。
类似的东西:
self.z.append(np.cos(np.random.uniform(-np.pi/2, np.pi/2))*self.x)
这将给出在-90°和+ 90°之间的随机角度的余弦,即针的长度。
作为参考,cos(+/-90) = 0
和cos(0) = 1
,因此在90°时,针的长度实际上为零,而在0°时,其全长。
我没有在这台机器上安装mathplotlib或numpy,所以我看不出这是否修复了它,但这绝对是必要的。
答案 3 :(得分:0)
看起来你提交了一个简单的舍入错误。下面的代码有效,但结果并不是非常接近pi ...
import numpy as np
import matplotlib.pylab as plt
class Buffon_needle_problem:
def __init__(self,x,y,n,m):
self.x = x #width of the needle
self.y = y #witdh of the space
self.r = []#coordinated of the centre of the needle
self.z = []#measure of the alingment of the needle
self.n = n#no of throws
self.m = m#no of simulations
self.pi_approx = []
def samples(self):
# throwing the needles
for i in range(self.n):
self.r.append(np.random.uniform(0,self.y))
self.z.append(np.random.uniform(0,self.x/2.0))
return [self.r,self.z]
def simulation(self):
#self.samples()
# m simulations
for j in range(self.m):
self.r=[]
self.z=[]
for i in range(self.n):
self.r.append(np.random.uniform(0,self.y))
self.z.append(np.random.uniform(0,self.x/2.0))
# n throws
hits = 0 # setting the succes to 0
for i in range(self.n):
# condition for a hit
if self.r[i]+self.z[i]>=self.y or self.r[i]-self.z[i] <= 0.0:
hits += 1
else:
continue
hits = 2.0*(float(self.x)/self.y)*float(self.n)/float(hits)
self.pi_approx.append(hits)
return self.pi_approx
y = Buffon_needle_problem(1,2,40000,5)
print (y.simulation())
另请注意,您使用相同的样本进行所有模拟!
答案 4 :(得分:0)
我用Python turtle来近似Pi的值:
from turtle import *
from random import *
setworldcoordinates(-100, -200, 200, 200)
ht(); speed(0); color('blue')
drops = 20 # increase number of drops for better approximation
hits = 0 # hits counter
# draw parallel lines with distance 20 between adjacent lines
for i in range(0, 120, 20):
pu(); setpos(0, i); pd()
fd(100) # length of line
# throw needles
color('red')
for j in range(drops):
pu()
goto(randrange(10, 90), randrange(0,100))
y1 = ycor() # keep ycor of start point
seth(360*random())
pd(); fd(20) # draw needle of length 20
y2 = ycor() # keep ycor of end point
if y1//20 != y2//20: # decisive test: if it is a hit then ...
hits += 1 # increase the hits counter by 1
print(2 * drops / hits)
Output samples
With 50 drops 3.225806451612903
with 200 drops 3.3057851239669422
with 1000 drops 3.1645569620253164
答案 5 :(得分:-1)
不回答原始问题,如果你只是想要pi估计,这里有一些简单的代码,我昨天在Uni Sydney(Aust)的计算修订练习中,反对我早期的倾向,为了降低复杂性,我们只建模了线与零之间的距离和从零到90度的随机角度之间的随机点。
import random
from numpy import pi, sin
def buffon(L, D, N):
'''
BUFFON takes L (needle length),
D = distance between lines and N = number of drops,
returns probability of hitting line
generate random number 'd' between 0 and D
generate theta between 0 and pi/2
hit when L*sin(theta)) - d is great than D
'''
hit = 0;
for loop in range(N) :
theta = pi*random.random()/2
if L * sin(theta) > D - D*random.random(): # d = random*D
hit += 1
return hit/N
#% Prob_hit = 2*L/(D*pi) hence: Pi_est = 2*L / (P_hit*D);
L = 1
D = 4
N = int(1e8)
Pi_est = 2*L / (buffon(L,D,N)*D)
在MatLab中,我想在Python中尝试它,看看我是否可以使用任何理解列表,任何想法来加快这一点欢迎。
答案 6 :(得分:-1)
需要注意的是,Monte Carlo 方法对于这种计算(计算数字 pi)并不是最好的。无论如何,为了获得更准确的圆周率,有必要抛出相当多的针(或点,在四分之一圆的情况下)。蒙特卡罗方法的主要缺点是其不可预测性。
https://github.com/Battle-Of-Two-K/Buffon-s-Noodle-Problem
https://github.com/Battle-Of-Two-K/Calculating-Pi-by-Monte-Carlo-Method