【问题标题】:Fortan code for Monte Carlo Integration within boundary point a and b边界点 a 和 b 内的蒙特卡洛积分的 Fortan 代码
【发布时间】:2019-03-01 14:54:29
【问题描述】:

我了解蒙特卡罗模拟是通过绘制随机点并计算曲线外点和曲线内点之间的比率来估计面积。

假设曲线半径为一,我已经很好地计算了 pi 的值。

这里是代码

program pi
implicit none

integer :: count, n, i
real :: r, x, y
count = 0
n=500
CALL RANDOM_SEED
DO i = 1, n
 CALL RANDOM_NUMBER(x)
 CALL RANDOM_NUMBER(y)
 IF (x*x + y*Y <1.0) count = count + 1
END DO
r = 4 * REAL(count)/n
print *, r
end program pi

但要找到整合,教科书说要应用相同的想法。但是如果我想找到

的集成,我迷失了如何编写代码
f(x)=sqrt(1+x**2) over a = 1 and b = 5

在半径为 1 之前,我确实假设点在 x*2+y**2 条件下落入,但如何解决以上问题?

任何帮助都非常有帮助

【问题讨论】:

  • 积分的一种解释是它是曲线、x 轴和积分极限(在您的情况下为 1 和 5)之间的区域。因此,您的任务变成了生成点并测试它们是否在该区域内,该区域有 3 个直边和一个弯曲边。如果您正在集成的函数在限制之间穿过 x 轴,则会变得更加困难,但我认为您的函数不会。画个草图,摸摸头,那么代码就比较简单了。
  • @HighPerformanceMark 感谢您的回复....我刚刚开始了解 fortran,因为它是作为您在主程序中的 Compulary 主题引入的。我很了解梯形、simson、newton rhapson 和二等分法,以及获得 pi 的蒙特卡洛部分......但是得到这个......我在过去的 3 个小时里都在挣扎......这超出了我的范围。 ..你能帮忙..我会通过程序结构进一步学习并开发我自己的......
  • 我的评论和你的评论之间的时间表明你没有花很长时间遵循我评论最后一句中的建议。除此之外,不,我不愿意回答这个问题,评论是我现在能给你的所有帮助。我希望有人比我有更多的时间,也许性格更慷慨,很快就会出现并为你编写代码。请耐心等待,距您提出问题仅 15 分钟,而且 SO 上的 Fortran 观察者并不多。
  • 这实际上与使用 Monte Carlo 计算 pi 非常相似。在区间上绘制函数图以查看更多信息。
  • @VladimirF 教科书也说同样的想法也适用于此。当它在 0 和 1 之间时我理解问题,我可以应用 (y

标签: fortran gfortran fortran90 fortran77


【解决方案1】:

我先写代码再解释:

Program integral
implicit none
real f
integer, parameter:: a=1, b=5, Nmc=10000000   !a the lower bound, b the upper bound, Nmc the size of the sampling (the higher, the more accurate the result)
real:: x, SUM=0

do i=1,Nmc                  !Starting MC sampling
  call RANDOM_NUMBER(x)     !generating random number x in range [0,1]
  x=a+x*(b-a)               !converting x to be in range [a,b]
  SUM=SUM+f(x)              !summing all values of f(x). EDIT: SUM is also an instrinsic function in Fortran so don't call your variable this, I named it so, to illustrate its purpose
enddo

print*, (b-a)*(SUM/Nmc)     !final result of your integral
end program integral

function f(x)           !defining your function
  implicit none
  real, intent(in):: x
  real:: f

  f=sqrt(1+x**2)
end function f

那么发生了什么:

积分可以写成 。其中:

(这个 g(x) 是 [a,b] 中变量 x 的均匀概率分布)。我们可以把积分写成:

.

所以,最后,我们得到积分应该是:

因此,您所要做的就是在 [a,b] 范围内生成一个随机数,然后计算此 x 的函数值。然后做很多次(Nmc 次),并计算总和。然后用 Nmc 除以求平均值,然后乘以 (b-a)。这就是代码的作用。

互联网上有很多关于这个的东西。 here's 一个很好的可视化示例

编辑:第二种方式,与 Pi 方法相同:

Nin=0                    !Number of points inside the function (under the curve)
do i=1,Nmc
  call random_number(x)
  call random_number(y)
  x=a+x*(b-a)
  y=f_min+y(f_max-f_min)
  if (f(x)<y) Nin=Nin+1
enddo
print*, (f_max-f_min)*(b-a)*(real(Nin)/Nmc)

所有这些,然后您可以将它包含在一个外部 do 循环中,对 (f_max-f_min)(b-a)(real(Nin)/Nmc) 求和,最后打印它的平均值。 对于此示例,您所做的实际上是创建一个从 a 到 b(x 维度)和从 f_min 到 f_max(y 维度)的封闭框,然后对该区域内的点进行采样并计算函数中的点( Nin)。显然,您必须知道函数在 [a,b] 范围内的最小值 (f_min) 和最大值 (f_max)。或者,您可以为 f_min f_max 使用任意低/高值,但是这样会浪费很多点,并且您的错误会更大。

【讨论】:

  • 最好将x定义为一个数组并调用random_number(x),这通常比一次获取相同数量的随机数要快得多。最好不要建议初学者使用内部函数的名称(例如SUM)作为变量的名称,尤其是在SUM 可用于对结果数组的值求和的情况下。如今,将f 留在程序外部,而不是内部或与使用相关的,并不是最佳做法。
  • @HighPerformanceMark 您对 SUM 的看法是正确的,我编辑了我的答案。我只是想清楚每个变量的作用。至于功能,如果是我的(更大的)程序,我可能会将其卡在模块中并使用模块或使用接口。我只是想举一个干净的例子,并没有真正关注它的编程细节,你当然指出这一点是对的。
  • (达到字符限制:) 至于随机数生成,我做了一个测试,似乎call random_number(x) (x an array) 比调用它 N 次为变量快X。 do 循环为 0.484 秒,数组为 1.68 秒(对于 N=100000000)。另外,如果您将 x 设置为数组,您开始遇到大尺寸的问题,然后您必须使用可分配数组,这并不复杂,但同样不希望他专注于 MC 采样以外的其他事情。
  • 嗯,你报告的有趣数据,与我最近的经历相反。是的,大数组可能是个问题,但10^9 (?) 样本无论如何都可能是多余的。
猜你喜欢
  • 2014-03-26
  • 1970-01-01
  • 2012-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-05
  • 2018-02-10
  • 1970-01-01
相关资源
最近更新 更多