Anton
Anton

Reputation: 67

Monte Carlo to calculate Pi on multiple Threads

I wrote a simple Program in Java to calculate Pi via the Monte Carlo method. Since You need a lot of drops to get Pi 'precise' and it gets, of course, slower I decided to implement Multi-Threading. Now to my question: Is there any way to speed the calculation up? And calculates it only one iteration per physical thread at a time or am I completley wrong in my concept of multithreading?

Here is the code:

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;
    }
}

Upvotes: 2

Views: 2684

Answers (1)

maraca
maraca

Reputation: 8743

You realize how big Long.MAX_VALUE / 8 is? It is (2^63 - 1) / 8 which is about 1e18... quite a big number (even whith todays best computers filling whole buildings it takes at least 1000s, see comment).

The better approach would be to compare the previous calculated value with the current value for pi and compare them. If the difference is 0 (Happens because precision is limited --> eps is the smallest number > 0 where 1 + eps != 1) cancel execution and return the value:

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

If you want to use more than one thread it is difficult, because the update of the value for pi has to be synchronized you wouldn't gain much I guess. However several threads could calculate pi independently and you could compare (or average) the results.

Upvotes: 2

Related Questions