Monte Carlo 在多个线程上计算 Pi
Monte Carlo to calculate Pi on multiple Threads
我在 Java 中写了一个简单的程序,通过 Monte Carlo 方法计算 Pi。由于您需要大量滴才能获得 Pi 'precise',而且它当然会变慢,所以我决定实施多线程。现在回答我的问题:有什么方法可以加快计算速度吗?并且一次只计算每个物理线程的一次迭代,还是我的多线程概念完全错误?
代码如下:
public class PiMC{
public static void main(String[] args) {
ExecutorService exec=Executors.newCachedThreadPool();
//Future object is used to get result from a thread
Future<Double> result0=exec.submit(new Thread1());
Future<Double> result1=exec.submit(new Thread1());
Future<Double> result2=exec.submit(new Thread1());
Future<Double> result3=exec.submit(new Thread1());
Future<Double> result4=exec.submit(new Thread1());
Future<Double> result5=exec.submit(new Thread1());
Future<Double> result6=exec.submit(new Thread1());
Future<Double> result7=exec.submit(new Thread1());
try
{
System.out.println(((result0.get() + result1.get() + result2.get() + result3.get() + result4.get()+ result5.get() + result6.get() + result7.get()) / Long.MAX_VALUE) * 4);
}
catch(InterruptedException e){System.out.println(e);}
catch(ExecutionException e){System.out.println(e);}
}
}
class Thread1 implements Callable {
@Override
public Double call() throws Exception {
long drops = Long.MAX_VALUE / 8;
//long drops = 500;
double in = 0;
for (long i = 0; i <= drops; i++) {
double x = Math.random();
double y = Math.random();
if (x * x + y * y <= 1) {
in++;
}
}
return in;
}
}
你知道 Long.MAX_VALUE / 8 有多大吗?它是 (2^63 - 1) / 8,大约是 1e18...相当大的数字(即使当今最好的计算机填满整个建筑物也至少需要 1000 秒,请参阅评论)。
更好的方法是将之前计算的值与 pi 的当前值进行比较并进行比较。如果差异为 0(发生是因为精度有限 --> eps 是最小的数字 > 0,其中 1 + eps != 1)取消执行并且 return 值:
int sum = 0, drops = 0;
double pi = 0, oldPi;
do {
oldPi = pi;
double x = Math.random(), y = Math.random();
if (x * x + y * y <= 1)
sum++;
drops++;
pi = 4.0 * sum / drops;
} while (pi != oldPi || pi < 3); // pi < 3 to avoid problems when the first
// drops are outside of the circle, pi == 0 would also work, BUT setting
// pi to a value different from 0 at the beginning can still fail with only pi != oldPi
如果您想使用多个线程,那将很困难,因为 pi 值的更新必须同步,我猜您不会有太大收获。然而,多个线程可以独立计算 pi,您可以比较(或平均)结果。
我在 Java 中写了一个简单的程序,通过 Monte Carlo 方法计算 Pi。由于您需要大量滴才能获得 Pi 'precise',而且它当然会变慢,所以我决定实施多线程。现在回答我的问题:有什么方法可以加快计算速度吗?并且一次只计算每个物理线程的一次迭代,还是我的多线程概念完全错误?
代码如下:
public class PiMC{
public static void main(String[] args) {
ExecutorService exec=Executors.newCachedThreadPool();
//Future object is used to get result from a thread
Future<Double> result0=exec.submit(new Thread1());
Future<Double> result1=exec.submit(new Thread1());
Future<Double> result2=exec.submit(new Thread1());
Future<Double> result3=exec.submit(new Thread1());
Future<Double> result4=exec.submit(new Thread1());
Future<Double> result5=exec.submit(new Thread1());
Future<Double> result6=exec.submit(new Thread1());
Future<Double> result7=exec.submit(new Thread1());
try
{
System.out.println(((result0.get() + result1.get() + result2.get() + result3.get() + result4.get()+ result5.get() + result6.get() + result7.get()) / Long.MAX_VALUE) * 4);
}
catch(InterruptedException e){System.out.println(e);}
catch(ExecutionException e){System.out.println(e);}
}
}
class Thread1 implements Callable {
@Override
public Double call() throws Exception {
long drops = Long.MAX_VALUE / 8;
//long drops = 500;
double in = 0;
for (long i = 0; i <= drops; i++) {
double x = Math.random();
double y = Math.random();
if (x * x + y * y <= 1) {
in++;
}
}
return in;
}
}
你知道 Long.MAX_VALUE / 8 有多大吗?它是 (2^63 - 1) / 8,大约是 1e18...相当大的数字(即使当今最好的计算机填满整个建筑物也至少需要 1000 秒,请参阅评论)。
更好的方法是将之前计算的值与 pi 的当前值进行比较并进行比较。如果差异为 0(发生是因为精度有限 --> eps 是最小的数字 > 0,其中 1 + eps != 1)取消执行并且 return 值:
int sum = 0, drops = 0;
double pi = 0, oldPi;
do {
oldPi = pi;
double x = Math.random(), y = Math.random();
if (x * x + y * y <= 1)
sum++;
drops++;
pi = 4.0 * sum / drops;
} while (pi != oldPi || pi < 3); // pi < 3 to avoid problems when the first
// drops are outside of the circle, pi == 0 would also work, BUT setting
// pi to a value different from 0 at the beginning can still fail with only pi != oldPi
如果您想使用多个线程,那将很困难,因为 pi 值的更新必须同步,我猜您不会有太大收获。然而,多个线程可以独立计算 pi,您可以比较(或平均)结果。