4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

豊田高専コンピュータ部Advent Calendar 2019

Day 23

モンテカルロ法による円周率計算の精度

Last updated at Posted at 2019-12-22

はじめに

モンテカルロ法とは、乱数を使用した試行を繰り返す方法の事だそうです。この方法で円周率を求める方法があることが良く知られていますが...ふと、思いました。愚直な方法より本当に精度良く求まるのだろうか?...ということで実際に実験してみましょう。

モンテカルロ法による求め方

1 * 1の正方形を想定し、その中にこれまた半径1の円の四分の一を納めます。
この正方形の中に乱数を使用し適当に点をたくさん取ります。点を置いた数をNとします。Nが十分に大きければまんべんなく点を取ることができるといえます。
その点のうち、円の中に納まっている点を数えてAとすると、正方形の面積が1、四分の一の円の面積がπ/4であることから、
A / N = π / 4  であり
π = 4 * A / N   と求められます。
この求め方は擬似乱数の性質上振れ幅がかなり大きい(理論上、どれほどたくさん試行しても値は0-4の間を取るとしかいえない)ので、極端な場合を捨てるために3回行って中央値をとることにしました。
実際のコード:

Monte.java
import java.util.Random;

public class Monte {
    public static void main(String[] args) {
        for (int i = 0; i < 3 ; i++) {
            monte();
        }
    }
    public static void monte() {
        Random r = new Random(System.currentTimeMillis());
        int cnt = 0;
        final int n = 400000000; //試行回数
        double x,y;
        for (int i = 0; i < n; i++) {
            x = r.nextDouble();
            y = r.nextDouble();
            //この点は円の中にあるか?(原点から点までの距離が1以下か?)
            if(x * x + y * y <= 1){
               cnt++; 
            }
        }
        System.out.println((double)cnt / (double)n * 4D);
    }
}

対抗馬な求め方

1 * 1の正方形を想定し、その中にこれまた半径1の円の四分の一を納めます。
この正方形の中に等間隔に端から端まで点をたくさん取ります。点を置いた数をNとします。Nが十分に大きければまんべんなく点を取ることができるといえます。(一辺辺り、Nの平方根だけの点が現れます。)
その点のうち、円の中に納まっている点を数えてAとすると、正方形の面積が1、四分の一の円の面積がπ/4であることから、
A / N = π / 4  であり
π = 4 * A / N   と求められます。
文章の使いまわし
実際のコード:

Grid.java
public class Grid {
    public static void main(String[] args) {
        int cnt = 0;
        final int ns = 20000; //試行回数の平方根
        for (double x = 0; x < ns; x++) {
            for (double y = 0; y < ns; y++) {
                if(x / (double)(ns - 1) * x / (double)(ns - 1) +
                    y / (double)(ns - 1) * y / (double)(ns - 1) <= 1D){
                    cnt++; 
                }
            }
        }
        System.out.println((double)cnt / ((double)ns * (double)ns) * 4D);
    }
}

結果

モンテカルロ法の結果

100 10000 1000000 100000000 400000000(参考)
一回目 3.16 3.1396 3.139172 3.14166432 3.14149576
二回目 3.2 3.1472 3.1426 3.14173924 3.1414574
三回目 3.08 3.1436 3.142624 3.14167628 3.1415464
結果(中央値) 3.16 3.1436 3.1426 3.14167628 3.14149576

全体の結果

100(10^2) 10000(100^2) 1000000(1000^2) 100000000(10000^2) 400000000(参考)(20000^2)
モンテカルロ法 3.16 3.1436 3.1426 3.14167628 3.14149576
対抗馬(グリッド) 2.92 3.1156 3.139156 3.141361 3.14147708
理想値 3.1415926535 3.1415926535 3.1415926535 3.1415926535 3.1415926535
誤差率(モンテ)[%] 0.568 0.064 0.032 0.003 -0.003
誤差率(グリッド)[%] -7.054 -0.827 -0.078 -0.007 -0.004

まとめ

(私の環境では100000000辺りからパソコンが重くなりました。)
試行回数が少ないうちは、やはりモンテカルロ法の方が精度良く求まっているといえるでしょう。しかし、100000000辺りから精度の伸びが落ち始めていて、これぐらいが擬似乱数では関の山と言えるでしょうか。

おわりに

総攻撃よりランダムな攻撃の方がいい時もある!
使う擬似乱数の精度に依りますが、乱数を使用するのも一興ですね。でも、限界もあるので、とにかく完全に精度良く求めたいなら、他の方法もあります、というところです。

4
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?