使用带有线程参数的Gregory-Leibniz公式计算π值时出错。

20 浏览
0 Comments

使用带有线程参数的Gregory-Leibniz公式计算π值时出错。

我正在尝试使用多线程和指定线程数来实现Java中的Gregory-Leibniz算法。但是最后计算出来的PI的值是43,我失败了。请问有人可以给我帮助吗?如果不需要输入线程数,那就没问题,但是输入线程数会破坏我的程序,我不确定该如何解决这个问题。

这是我用来指定线程数的代码:

System.out.print("Insert Number of threads:");
int numetothreads = scannerObj.nextInt();
System.out.println("Nº threads : " + numetothreads);
ExecutorService es = Executors.newFixedThreadPool(numetothreads);
long ti = System.currentTimeMillis();
Future parte1 = es.submit(new CarlzParalel(1, 100000000));
Future parte2 = es.submit(new CarlzParalel(100000001, 200000000));
Future parte3 = es.submit(new CarlzParalel(200000001, 300000000));
Future parte4 = es.submit(new CarlzParalel(400000001, 500000000));

这是我用来指定线程数的代码:

public class CarlzParalel implements Callable {
    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 {
        Scanner scannerObj = new Scanner(System.in);
        System.out.print("Insert number of threads:");
        int numetothreads = scannerObj.nextInt();
        System.out.println("Nº threads : " + numetothreads);
        ExecutorService es = Executors.newFixedThreadPool(numetothreads);
        long ti = System.currentTimeMillis();
        Future parte1 = es.submit(new CarlzParalel(1, 100000000));
        Future parte2 = es.submit(new CarlzParalel(100000001, 200000000));
        Future parte3 = es.submit(new CarlzParalel(200000001, 300000000));
        Future parte4 = es.submit(new CarlzParalel(400000001, 500000000));
        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();
        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();
        }
        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());
    }
}

插入线程数:4

线程数:4

Pi的值是43.41189321992768

并发耗时10325毫秒

Pi的值是43.41189321992768

非并发耗时42131毫秒

性能提升百分比:24.506895160333247%

处理器数量:4

0
0 Comments

在使用Gregory-Leibniz公式计算pi值时,出现了错误,下面是错误的原因和解决方法:

错误原因:

1. 分子的代码始终返回1,而不是返回1或-1;

2. 分母的计算错误;

3. 循环的起始值应该是1而不是0。

解决方法:

1. 将分子的代码修改为:double numerator = n % 2 == 0 ? 1 : -1;

2. 将分母的计算修改为:double denominator = n * 2 + 1;

3. 将循环的起始值修改为begin - 1。

修改后的方法如下:

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

另外需要注意的是:

1. 输入缺少300000001到400000000的范围;

2. double类型对于精度较高的计算不太适用,可以考虑使用BigDecimal,但速度会明显降低;

3. 对于精度和double类型的计算结果,反向求和的结果可能不同。

感谢您的帮助!我会尝试改进我的代码,使用BigDecimal看起来是个不错的主意,因为我需要更大的间隔。谢谢!

0
0 Comments

问题出现的原因:在call()方法中,计算π值的公式有误,导致最终计算出的π值不准确。

解决方法:修改call()方法中的计算公式,以确保得到正确的π值。

以下是修改后的代码:

public static class CarlzParallel implements Callable {
    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 parte1 = es.submit(new CarlzParallel(1, 100000000));
    Future parte2 = es.submit(new CarlzParallel(100000001, 200000000));
    Future parte3 = es.submit(new CarlzParallel(200000001, 300000000));
    Future 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(π);
}

修改后,再次运行代码,将会得到正确的π值。

0