利用单位圆与边长为1的正方形面积之比来计算
π的近似值具体思想如下:
如图1所示,单位圆的1/4为一个扇形G,它是边长为1
的正方形的一部分.考虑扇形面积在正方形面积中所占的比例k,
得出其结果为π/4,然后乘以4就可以得到π的值.这里如何计算比例
k,运用蒙特卡罗方法的随机投点思想.在正方形中随机投入很多点,
使所投点落图1在正方形中每一个位置的机会均等,
然后考察有多少点落在扇形内.其中落在扇形内的点的个数
m与投点总数n之比就是k的近似值.
于是通过java可以完成相应的程序编写.
详细的程序如下.
public class MontePi {
public static void main(String[] args) {
double x,y=0;
long n=0,i=0;
for(i=0;i<100000000;i++){
x= Math.random()*(1-0)+0; //产生0-1的随机数
y=Math.random();
if(x*x+y*y<1) n++;
}
System.out.println(i+":"+n);
double pi=4*(double)n/(double)i;
System.out.println(pi);
}
}
可能的输出结果为:
100000000:78551476
3.14205904
ps:蒙特卡罗分析计算圆周率并不是好方法,显然达不到公元5世纪祖冲之的推算精度。但是在其他领域有独特作用,比如:项目管理里面的风险分析。
蒙特卡罗方法实现了两大优点:
一是简单,省却了繁复的数学推导和演算过程,使得一般人也能够理解和掌握
二是快速。简单和快速,是蒙特卡罗方法在现代项目管理中获得应用的技术基础。
蒙特卡罗分析由于概率计算是相对独立互不影响的,所以很容易发展成大规模并行计算的算法。下面是一个多线程计算圆周率的版本:
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Random;
public class ThreadMontePi implements Runnable {
static ArrayList> array1=new ArrayList>() ; //保存结果数据
private String name;
private int threadnum;
public void setName(int threadnum) {
this.name = threadnum + "";
this.threadnum = threadnum;
}
public void run() {
long randSeed = System.currentTimeMillis() - threadnum * 10; // 按时间取随机数种子
//System.out.println(randSeed); //显示随机数种子
Random rand = new Random(randSeed);
double x, y = 0;
long n = 0, i = 0;
for (i = 0; i < 100000000; i++) {
x = (double) rand.nextInt(10000000); // 产生0-10000000的随机整数,不包含10000000
x = x / 10000000d;
// x= Math.random()*(1-0)+0; //产生0-1的随机数,不包含1
// y=Math.random();
y = (double) rand.nextInt(10000000); // 产生0-10000000的随机整数,不包含10000000
y = y / 10000000d;
if (x * x + y * y < 1)
n++;
// System.out.println(y);
}
System.out.println(name + ":" + i + ":" + n);
Hashtable tabt=new Hashtable();
tabt.put("i", i);
tabt.put("n", n);
array1.set(threadnum, tabt);
double pi = 4 * (double) n / (double) i;
System.out.println(name + ":" + pi);
// System.out.println("hello " + name);
}
public static void main(String[] args) {
//初始化array1
array1.add(new Hashtable());
array1.add(new Hashtable());
array1.add(new Hashtable());
array1.add(new Hashtable());
//启动3个线程计算
ThreadMontePi myThread1 = new ThreadMontePi();
ThreadMontePi myThread2 = new ThreadMontePi();
ThreadMontePi myThread3 = new ThreadMontePi();
myThread1.setName(1);
Thread thread = new Thread(myThread1);
thread.start();
myThread2.setName(2);
Thread thread2 = new Thread(myThread2);
thread2.start();
myThread3.setName(3);
Thread thread3 = new Thread(myThread3);
thread3.start();
//判断线程结束,收集计算结果
boolean flag = true;
while (flag) {
Thread.State state = thread.getState();
Thread.State state2 = thread2.getState();
Thread.State state3 = thread3.getState();
if (java.lang.Thread.State.TERMINATED == state
&& java.lang.Thread.State.TERMINATED == state2
&& java.lang.Thread.State.TERMINATED == state3)
break;
}
Hashtable tabt=(Hashtable)array1.get(1);
System.out.println("thread1:"+tabt.get("i")+","+tabt.get("n"));
Hashtable tabt2=(Hashtable)array1.get(2);
System.out.println("thread2:"+tabt2.get("i")+","+tabt2.get("n"));
Hashtable tabt3=(Hashtable)array1.get(3);
System.out.println("thread3:"+tabt3.get("i")+","+tabt3.get("n"));
long sumI=tabt.get("i")+tabt2.get("i")+tabt3.get("i");
long sumN=tabt.get("n")+tabt2.get("n")+tabt3.get("n");
double pi = 4 * (double) sumN / (double) sumI;
System.out.println("sumPi:"+pi); //输出最终计算结果
}
}
可能的输出结果为:
2:100000000:78545069 2:3.14180276 3:100000000:78536096 3:3.14144384 1:100000000:78540560 1:3.1416224 thread1:100000000,78540560 thread2:100000000,78545069 thread3:100000000,78536096 sumPi:3.141623