円周率をモンテカルロ法で求める vol.2
昨日、モンテカルロ法にて円周率を求めるプログラムをつくった。
乱数シュミレーションとしては、まぁまぁの数値を導き出していると個人的には思った。
さらに精度を上げようとして何回か同じ処理をして平均値を取ればいいかな?と思い
次のようにプログラムを変更してみました。
はじめに二重ループを使い平均値を求めるプログラムを組んでしまって
非常に効率が悪いことに気が付いたのは秘密です。(;´Д`)
相変わらず汚いコードですが素人のやることですからプロフェッショナルな人は
優しく解りやすくご指摘くださればうれしいです。
jp\yucchi\montecarlo_pi\Montecarlo_PI.java |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package jp.yucchi.montecarlo_pi; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; import java.util.logging.Level; import java.util.logging.Logger; public class Montecarlo_PI implements Callable<List<Double>> { public static void main(String[] args) { double TOTAL_THREAD = 1_000_000.0; int procs = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); ExecutorService executor = Executors.newFixedThreadPool(procs); List<Future<List<Double>>> futures = new ArrayList<>(); for (double i = 0; i < TOTAL_THREAD; i++) { futures.add(executor.submit(new Montecarlo_PI())); } executor.shutdown(); List<Double> mPi = new ArrayList<>(); for (Future<List<Double>> future : futures) { try { List<Double> pi = future.get(); mPi.addAll(pi); } catch (InterruptedException | ExecutionException ex) { Logger.getLogger(Montecarlo_PI.class.getName()).log(Level.SEVERE, null, ex); } } double totalPi = 0.0; for (Double pi : mPi) { totalPi += pi; } double avgPi = totalPi / mPi.size(); System.out.println("Mathクラスによる円周率は " + Math.PI); System.out.println("モンテカルロ法による円周率は " + avgPi); } @Override public List<Double> call() throws Exception { List<Double> pi = new ArrayList<>(); double hitCount = 0.0; double NEEDLE = 100_000_000.0; for (double i = 0; i < NEEDLE; i++) { double x = Math.random(); double y = Math.random(); if (Math.pow(x, 2.0) + Math.pow(y, 2.0) < 1.0) { hitCount++; } } double _pi = 4.0 * hitCount / NEEDLE; System.out.println("Montecarlo PI : " + _pi); pi.add(_pi); return pi; } } |
一億個の針を落として計算する処理を百万回して平均値をとってみました。
って・・・計算処理が終わってない( ̄。 ̄;)
しかたないから一億個の針を落とす計算処理を千回に変更してみました。
上記のソースコードの NEEDLE の値を 1000.0 に変更して実行してみました。
これでも終わりそうにないくらい時間がかかります。
不本意ですが計算処理回数を32回に変更しました。(..;)
実行結果は次のようになりほんの気持ち程度精度は上がりました。
run:
Montecarlo PI : 3.14146332
Montecarlo PI : 3.1416326
Montecarlo PI : 3.1415482
Montecarlo PI : 3.141632
Montecarlo PI : 3.14127944
Montecarlo PI : 3.14178148
Montecarlo PI : 3.1416116
Montecarlo PI : 3.14141588
Montecarlo PI : 3.1416632
Montecarlo PI : 3.14117084
Montecarlo PI : 3.14161116
Montecarlo PI : 3.14168484
Montecarlo PI : 3.14166664
Montecarlo PI : 3.14151984
Montecarlo PI : 3.14131844
Montecarlo PI : 3.14161456
Montecarlo PI : 3.14160796
Montecarlo PI : 3.14157636
Montecarlo PI : 3.14174076
Montecarlo PI : 3.14137984
Montecarlo PI : 3.14161576
Montecarlo PI : 3.14160444
Montecarlo PI : 3.14165568
Montecarlo PI : 3.14140136
Montecarlo PI : 3.1414314
Montecarlo PI : 3.14134932
Montecarlo PI : 3.14164312
Montecarlo PI : 3.14159468
Montecarlo PI : 3.141492
Montecarlo PI : 3.14139636
Montecarlo PI : 3.14149788
Montecarlo PI : 3.1414862
Mathクラスによる円周率は 3.141592653589793
モンテカルロ法による円周率は 3.14153397375
構築成功 (合計時間: 22 分 47 秒)
時間に余裕のあるときに計算処理回数を増やしてみて結果を確認したいと思います。
ちなみにこの計算は Intel Core i7-2600K (3.4GHz) の CPU を積んだハードウェアでしました。
OS は、Windows 7 64bit 版です。
Dual Xeon 4 Core (3.0GHz) のシステムより2倍くらい速いです!
ハイエンドマシンをお持ちの方は是非試してみてくださいね。(ё_ё)
実行結果の合計時間: 22 分 47 秒ってのは使用した NetBeans 7.2 開発版での実行時の値です。
TAGS: Java | 2012年6月13日12:02 AM | Comment : 0