蒙特卡罗集成在FORTRAN中找到具有一定精度的pi

时间:2015-10-11 13:56:21

标签: algorithm fortran montecarlo pi

我正在学习数值方法课程,并且我被要求实施着名的蒙特卡罗算法来找到你能找到的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值。

2 个答案:

答案 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。