使用蒙特卡罗方法求圆周率π的设计实现及结果分析

文章目录

  • 前言
  • 问题描述
  • 基本思路
  • 算法描述
  • 代码实现
  • 结果分析
  • 参考文献
  • 附录
    • 附1:源代码
    • 附2:实验数据

前言

蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是二十世纪四十年代中期由于科学技术的发展和电子计算机的发明,而被提出的一种以概率统计理论为指导的一类非常重要的数值计算方法。是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。与它对应的是确定性算法。蒙特·卡罗方法在金融工程学,宏观经济学,计算物理学(如粒子输运计算、量子热力学计算、空气动力学计算)等领域应用广泛[1]

问题描述

使用蒙特·卡罗方法求圆周率。

基本思路

如下图所示,随机生成大量的点都在矩形区域内,然后会有部分点落在圆内,两者的比值基本等于面积比值。以此为关系,建立公式求出PI的值。
使用蒙特卡罗方法求圆周率π的设计实现及结果分析_第1张图片

算法描述

给定集合两个点的集合S1和S2如下所示。
S 1 = { ( x , y ) ∣ x ∈ [ − 1 , 1 ] , y ∈ [ − 1 , 1 ] } S 2 = { ( x , y ) ∣ x 2 + y 2 ≤ 1 } S1 = \{(x,y) | x∈[-1,1], y ∈ [-1, 1] \}\\ S2 = \{(x,y) | x^2 + y^2 ≤ 1\} S1={ (x,y)x[1,1],y[1,1]}S2={ (x,y)x2+y21}
其中,S1表示下图中矩形内的所有点,S2表示下图所示圆内的所有点。

利用蒙特·卡罗方法,随机生成 M个落在S1内的点,设这些点中落在S2中的点有N个。由于随机生成的点是平均分布在区域内的,所以矩形面积与圆形面积的比值可以近似表示为 N/M(当M趋于无穷大时可以取等号)。所以可得
π r 2 / ( 2 r ) 2 = S 1 / S 2 ≈ N / M \pi r^2/(2r)^2 = S1/S2 \approx N/M πr2/(2r)2=S1/S2N/M
利用最左右两式化简后可得
π = 4 N / M \pi = 4N/M π=4N/M

代码实现

整个代码编写使用Java实现,代码附在文章尾。

结果分析

原始整理的数据参见附录2。对结果进行统计分析数据如下

测试 1M 10M 100M 1000M 10000M
平均值 3.141794181818 3.141524254545 3.141551778182 3.141571543273 3.141580096378
与PI绝对误差 2.0153E-04 6.8399E-05 4.0875E-05 2.1110E-05 1.2557E-05
方差 1.2234E-03 3.9009E-04 1.5801E-04 4.8368E-05 3.5344E-05

根据以上结果我们可以看到:

  • 根据与PI的绝对误差,测试次数的增加会提高计算的精度。
  • 增加测试次数,结果的方差也越来越小,结果趋于稳定。

参考文献

[1] 蒙特·卡罗方法, 百度百科, https://baike.baidu.com/item/蒙特·卡罗方法.

附录

附1:源代码


public class Test{
     

	public static void main(String[] args) {
     
		int[] mts = {
      1, 10, 100, 1000, 10000 };
		for (int test = 0; test < mts.length; test++) {
     
			for (int runTimes = 0; runTimes < 11; runTimes++) {
     
				long t1 = System.currentTimeMillis();
				double pi = calPI(mts[test]);
				long t2 = System.currentTimeMillis();
				System.out.printf("%d\t%.12f\t%d\n", mts[test], pi, t2 - t1);
			}
		}
	}
	
	static double calPI(int mtimes) {
     
		long totalTimes = mtimes * 1000 * 1000;
		long count = 0;
		for (int i = 0; i < totalTimes; i++) {
     
			double x = Math.random() * 2 - 1;
			double y = Math.random() * 2 - 1;
			if (x * x + y * y <= 1)
				count++;
		}
		return 4.0 * count / totalTimes;
	}
}

附2:实验数据

实验结果整理如下。

测试 1M 10M 100M 1000M 10000M
测试1 3.142360000000 3.140679200000 3.141713720000 3.141578804000 3.141550627983
测试2 3.141624000000 3.141345600000 3.141670440000 3.141563544000 3.141606392772
测试3 3.140448000000 3.141157600000 3.141164000000 3.141456096000 3.141563572064
测试4 3.142236000000 3.141332400000 3.141526360000 3.141613740000 3.141643920110
测试5 3.143396000000 3.141452400000 3.141528480000 3.141518756000 3.141553674651
测试6 3.140520000000 3.142040400000 3.141332640000 3.141573840000 3.141586141230
测试7 3.142640000000 3.141797200000 3.141588600000 3.141583848000 3.141533528067
测试8 3.142236000000 3.141986800000 3.141593600000 3.141609088000 3.141603950332
测试9 3.143776000000 3.141757600000 3.141688680000 3.141602520000 3.141629583186
测试10 3.139856000000 3.141356000000 3.141621560000 3.141639432000 3.141572680861
测试11 3.140644000000 3.141861600000 3.141641480000 3.141547308000 3.141536988900

你可能感兴趣的:(算法设计与分析,蒙特卡罗,算法设计与分析,圆周率计算)