0

Im trying to implement the Gregory-Leibniz in Java using multi threads and specifying the number of threads to use. I failing because in the end PI is giving me value of 43.

Can anyone give me an hand please? I would be fine if i didnt haveto inut the number of threads, but inputing the number of threads is ruining my program and not sure how to solve this.

    System.out.print("Insert Number of threads:");
    int numetothreads = scannerObj.nextInt();
    System.out.println("Nº threads : " + numetothreads);
    //https://stackoverflow.com/questions/949355/executors-newcachedthreadpool-versus-executors-newfixedthreadpool
    ExecutorService es = Executors.newFixedThreadPool(numetothreads);
    long ti = System.currentTimeMillis();


    //separate in 4 and join after
    Future<Double> parte1 = es.submit(new CarlzParalel(1, 100000000));
    Future<Double> parte2 = es.submit(new CarlzParalel(100000001, 200000000));
    Future<Double> parte3 = es.submit(new CarlzParalel(200000001, 300000000));
    Future<Double> parte4 = es.submit(new CarlzParalel(400000001, 500000000));

This is what im using to specify the number of threads

public class CarlzParalel implements Callable<Double> {

    private int begin;
    private int end;

    public CarlzParalel(int begin, int end) {
        this.begin= begin;
        this.end = end;
    }

    public Double call() throws Exception {
        double sum = 0.0;
        double fator;
        for (int i = begin; i <= end; i++) {
            if (i % 2 == 0) {
                fator = Math.pow(1.0, i + 1);
            } else {
                fator = Math.pow(1.0, -i + 1);
            }
            sum += fator / (2.0 * (double) i - 1.0);
        }

        return sum;
    }


    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //cria um pool de threads para realizar o cálculo
        Scanner scannerObj = new Scanner(System.in);

        //System.out.println("Nº threads : " + listathreads);
        //ExecutorService es = Executors.newCachedThreadPool();
        System.out.print("Insert number of threads:");
        int numetothreads = scannerObj.nextInt();
        System.out.println("Nº threads : " + numetothreads);
        //https://stackoverflow.com/questions/949355/executors-newcachedthreadpool-versus-executors-newfixedthreadpool
        ExecutorService es = Executors.newFixedThreadPool(numetothreads);
        long ti = System.currentTimeMillis();


        //separate in 4 then join all
        Future<Double> parte1 = es.submit(new CarlzParalel(1, 100000000));
        Future<Double> parte2 = es.submit(new CarlzParalel(100000001, 200000000));
        Future<Double> parte3 = es.submit(new CarlzParalel(200000001, 300000000));
        Future<Double> parte4 = es.submit(new CarlzParalel(400000001, 500000000));

        /*
        Future<Double> parte1 =  es.submit(new CarlzParalel(1,100000000));
        Future<Double> parte2 = es.submit(new CarlzParalel(100000001,200000000));
        Future<Double> parte3 = es.submit(new CarlzParalel(200000001,300000000));
        Future<Double> parte4 = es.submit(new CarlzParalel(300000001,400000000));*/

        //join the values
        double pi = 4.0 * (parte1.get() + parte2.get() + parte3.get() + parte4.get());

        es.shutdown();

        System.out.println("Pi is " + pi);
        long tf = System.currentTimeMillis();
        long tcc = tf-ti;
        System.out.println("Time with concurrency " + tcc);

        ti = System.currentTimeMillis();

        //separate in 4 then join all without concurrency

        try {
            Double parteA = (new CarlzParalel(1, 100000000)).call();
            Double parteB = (new CarlzParalel(100000001, 200000000)).call();
            Double parteC = (new CarlzParalel(200000001, 300000000)).call();
            Double parteD = (new CarlzParalel(400000001, 500000000)).call();
            pi = 4.0 * (parteA + parteB + parteC + parteD);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //join them all

        System.out.println("PI is " + pi);
        tf = System.currentTimeMillis();
        long tsc = tf - ti;
        double divisao = (double) tcc / (double) tsc;
        double gain = (divisao) * 100;
        System.out.println("Time with no concurrency " + tsc);
        System.out.println("Gain % – TCC/TSC * 100 = " + gain + " %");
        System.out.println("Number of processores: " + Runtime.getRuntime().availableProcessors());


    }
}
Insert number of threads:4
Nº threads : 4
Pi is 43.41189321992768
Time wasted with concurrency 10325
Pi is 43.41189321992768
Time wasted without concurrecy 42131
gainz% – TCC/TSC * 100 = 24.506895160333247 %
Nº threads: 4
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
FCorreia
  • 91
  • 2
  • 11

2 Answers2

3

Assuming you are trying to calculate the formula:

enter image description here

Then your summing method looks incorrect.

The numerator code you have will always return 1. If you are trying to get it to return 1 or -1 there are several ways you can do it such as:

   double numerator = n % 2 == 0 ? 1 : -1;

The denominator also looks wrong to me, I would probably favour something like:

   double denominator = n * 2 + 1;

And as you are starting with 1 rather than 0, the for loop would need to be modified to subtract 1 from the input parameters. All together the method would look as follows:

    public Double call() throws Exception {
        double sum = 0.0;
        for (int i = begin - 1; i < end; i++) {
            double numerator = i % 2 == 0 ? 1 : -1;
            double denominator = i * 2 + 1;
            sum += numerator / denominator;
        }
        return sum;
    }

However

  1. Your inputs are missing the range from 300000001 to 400000000

  2. double isn't really suitable for any sort of precision. Out of the box you could use BigDecimal but it will obviously be at least a factor slower.

With regard to precision and doubles, I wouldn't be surprised if the results of below are different:

    double pi = 4.0 * (parte1.get() + parte2.get() + parte3.get() + parte4.get());
    System.out.println("Pi is " + pi);


    // reverse the order of the sum
    double 4.0 * (parte4.get() + parte3.get() + parte2.get() + parte1.get());
    System.out.println("Pi is " + pi);

Marc G. Smith
  • 876
  • 6
  • 8
  • Thank you so much for your help. Going to try to improve my code, BigDecimal looks like a good idea because i need bigger intervals. Thanks! – FCorreia Jun 20 '19 at 11:16
0

Not sure what is wrong with your math in call but that is certainly where the issue is.

public static class CarlzParallel implements Callable<Double> {

    private int begin;
    private int end;

    public CarlzParallel(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    public Double call() throws Exception {
        double sum = 0.0;
        for (int i = begin; i <= end; i++) {
            double dividend = (i % 2) == 0 ? -1 : 1;
            double divisor = (2 * i) - 1;
            sum += dividend / divisor;
        }
        return sum;
    }

}

private void test() {
    ExecutorService es = Executors.newFixedThreadPool(4);
    //separate in 4 then join all
    Future<Double> parte1 = es.submit(new CarlzParallel(1, 100000000));
    Future<Double> parte2 = es.submit(new CarlzParallel(100000001, 200000000));
    Future<Double> parte3 = es.submit(new CarlzParallel(200000001, 300000000));
    Future<Double> parte4 = es.submit(new CarlzParallel(400000001, 500000000));
    double π = 0;
    try {
        es.shutdown();
        while(!es.awaitTermination(5, TimeUnit.SECONDS)) {
            System.out.println("Waiting ...");
        }
        π = 4.0 * (parte1.get() + parte2.get() + parte3.get() + parte4.get());
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println(π);
}

prints

3.141592650755993
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213