使用带有线程参数的Gregory-Leibniz公式计算π值时出错。
使用带有线程参数的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(); Futureparte1 = 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
在使用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看起来是个不错的主意,因为我需要更大的间隔。谢谢!
问题出现的原因:在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(π); }
修改后,再次运行代码,将会得到正确的π值。