java - 蒙特卡罗在多个线程上计算 Pi

标签 java multithreading montecarlo pi

我用Java编写了一个简单的程序,通过蒙特卡罗方法计算Pi。因为你需要大量的滴水才能让 Pi 变得“精确”,而且它当然会变慢,所以我决定实现多线程。现在我的问题是:有什么办法可以加快计算速度吗?并且每次只为每个物理线程计算一次迭代,还是我的多线程概念完全错误?

这是代码:

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)取消执行并返回值:

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 - 蒙特卡罗在多个线程上计算 Pi,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29624673/

相关文章:

ruby - `Thread.current.object_id` 可以在线程本身内部更改吗?

java - java中根据条件动态添加执行器

python - 加快内核估计的采样

OpenCL Intel Iris 集成显卡退出并出现 Abort Trap 6 : Timeout Issue

java - 有人能告诉我如何用 double 进行运算吗?

java - 使用不同的类加载器在 Java 中动态创建 lambda

c - 读取全局标志不适用于 CUDA 中的 CPU>GPU 数据交换

java - 在java中无替换地选择

java - Mockito 局部变量

java 14 nullpointerexception 没有详细信息