我正在学习数值方法课程,并且我被要求实施着名的蒙特卡罗算法来找到你能找到的here。
使用任意数量的试验编写代码没有任何困难:
REAL(8) FUNCTION distance(xvalue, yvalue) RESULT(dist)
IMPLICIT NONE
REAL(8), INTENT(in) :: xvalue, yvalue
dist = SQRT(xvalue**2 + yvalue**2)
END FUNCTION distance
PROGRAM ass2
IMPLICIT NONE
INTEGER, DIMENSION(1) :: SEED
REAL(8) :: p, x, y
REAL(8), EXTERNAL :: distance
REAL(8) :: pi_last, pi
INTEGER :: npc, npt, i
npc = 0
npt = 0
pi = 1.0
SEED(1) = 12345
CALL RANDOM_SEED
DO i=1, 1000000000
CALL RANDOM_NUMBER(p)
x = p
CALL RANDOM_NUMBER(p)
y = p
npt = npt + 1
IF (distance(x, y) < 1.0) THEN
npc = npc + 1
END IF
pi_last = pi
pi = 4.0*(npc*1.0)/(npt*1.0)
END DO
PRINT*, 'Pi:', pi
END PROGRAM ass2
我注意到它大约收敛为sqrt(N步)。现在我必须以一定的精度停止算法,所以我在IF语句中创建了一个带有EXIT的无限DO循环:
REAL(8) FUNCTION distance(xvalue, yvalue) RESULT(dist)
IMPLICIT NONE
REAL(8), INTENT(in) :: xvalue, yvalue
dist = SQRT(xvalue**2 + yvalue**2)
END FUNCTION distance
PROGRAM ass2
IMPLICIT NONE
INTEGER, DIMENSION(1) :: SEED
REAL(8) :: p, x, y
REAL(8), EXTERNAL :: distance
REAL(8) :: pi_last, pi
INTEGER :: npc, npt, i
npc = 0
npt = 0
pi = 1.0
SEED(1) = 12345
CALL RANDOM_SEED
DO
CALL RANDOM_NUMBER(p)
x = p
CALL RANDOM_NUMBER(p)
y = p
npt = npt + 1
IF (distance(x, y) < 1.0) THEN
npc = npc + 1
END IF
pi_last = pi
pi = 4.0*(npc*1.0)/(npt*1.0)
IF ( ABS(pi - pi_last) < 0.000001 .AND. pi - pi_last /= 0) THEN
EXIT
END IF
END DO
PRINT*, 'Pi:', pi
END PROGRAM ass2
问题是这会返回不具有我要求的精度的pi值。我得到它背后的逻辑:如果我得到两个连续的值远离pi但彼此接近,则条件将被满足并且程序将退出DO语句。问题是我不知道如何修改它以获得由我决定的精度。所以问题是:
如何以能够决定输出中pi的精度的方式实现此算法?
编辑:好的,我实现了你的两个解决方案并且它们可以工作,但仅适用于10 ^( - 1),10 ^( - 3)和10 ^( - 5)。我认为这是伪随机序列的问题,如果对于10 ^( - 2)和10 ^( - 4)它返回不正确的pi值。答案 0 :(得分:4)
仅指定所需的精度是不够的 - 您还需要允许一些不符合精度目标的机会。然后你可以用(例如)Hoeffding's inequality求解试验次数,以满足你想要的概率所需的精度(正如你所观察到的那样,n需要关于一个超过精度的平方根才能成功恒定概率)。
答案 1 :(得分:3)
在理想设置中(完美的随机数生成器在数学意义上生成实数),变量npc
是一个随机变量binomial distribution B(n,π/ 4),其中n是{{ 1}}来自你的程序。其期望值为n *π/ 4,因此您可以正确计算π的近似值npt
。现在,无论您计算多少循环迭代,此近似值都可以取0到4之间的所有值,因为pi=4*npc/npt
可以取0到npc
之间的所有值。对于π范围内的范围,您只能给出概率(使用c作为npt
的简写; P表示事件的概率):
P(| pi-π|&lt; d)= P(-d = P(c 〜= F N (n *(π+ d)/ 4) -
F N (n *(π-d)/ 4)= 2F(d *√(n /(π(4-π)))) - 1 其中F N 是正态分布N(nπ/ 4;nπ/ 4(1-π/ 4))的概率函数,其中approximates the above binomial distribution和F是概率函数标准正态分布。现在给出偏差d和概率p,你可以计算n s.t.最后一个词不低于p: n = ceil(π(4-π)(F -1 ((p + 1)/ 2)/ d)^ 2)) 然后使用n次循环迭代,您可以使用给定的概率计算π的近似pi到期望的精度。 如果我们想要达到p = 99%的概率,那么上面的公式简化为 n~ = 17.89 / d 2 , 所以对于精度d = 0.0001大致n = 1.789E9迭代是必要的! 注意:由于计算机无法满足上述理想设置,因此使用此算法可以达到(理论上)对精度的限制。计算机中只能表示有限的浮点数,因此您的点npc
位于某种网格上。可以使用此算法计算的π的最佳近似值归结为在[0,1] x [0,1]中的所有网格点上执行循环。好的旧C函数rand()具有31位的分辨率(至少在VS stdlib中)。因此,计算超过n = 31 2 点是没有意义的,当要求99%的正确性时,它给出最大精度√(17.89 / n)= 1.97E-9。