LoginSignup
8
1

More than 5 years have passed since last update.

モンテカルロ法をAndroidで遊んでみた

Posted at

猫の居る会社で有名なqnoteに入社させていただき、半年が経とうとしております。
最近では猫社員とも打ち解けてきており、モニターの前に陣取られてしまうこともしばしばです。

目的

世間ではカジノ法案の採決で与野党が揉めているようですが、カジノといったらランダムの世界ですよね。今回はAndroidでモンテカルロ法を使用し円周率を求め、Mathクラスのrandom()メソッドで取得できる値に偏りがないか確認したいと思います。

モンテカルロ法と円周率

モンテカルロ法をWikipediaで調べるとこんな感じに書かれております。

シミュレーションや数値計算を乱数を用いて行う手法の総称。

モンテカルロ法で円周率を求める場合は、XとYを半径以下の乱数として点を打ちます。一辺が半径の正方形内に分布し、これらの点の総数と円内の数の比が正方形と扇状の円の面積比になることを利用して円周率を求めます。

  • 1.0×1.0の正方形にランダムで点を打つ
  • 打たれた点の座標XとYをそれぞれ二乗し足す
  • その数が1.0より小さければ扇状の円の中、大きければ外とする
  • 全体に打った点の数と扇状の円の中に入った点の数を割り4倍すると円周率!
GraphicsView.java
import android.content.Context;
import android.graphics.*;
import android.util.Log;
import android.view.View;

public class GraphicsView extends View {

    Paint paint = new Paint();
    int NUMBER = 1000000;
    double[] randX, randY;

    public GraphicsView(Context context) {
        super(context);
        randX = getRandom();
        randY = getRandom();

    }

    private double[] getRandom() {
        double[] rand = new double[NUMBER];
        for (int i = 0; i < NUMBER; i++) {
            rand[i] = Math.random();
        }
        return rand;
    }


    @Override
    protected void onDraw(Canvas canvas) {

        int n1 = 0; 
        double pi = 0.0; 

        for (int i = 0; i < NUMBER; i++) {
            int intx0 = (int) (randX[i] * 500);
            int inty0 = (int) (randY[i] * 500);

            if (randX[i] * randX[i] + randY[i] * randY[i] < 1.0) { /* 円の中に入っているか */
                n1 = n1 + 1;
                paint.setColor(Color.rgb(255, 0, 0));
                canvas.drawPoint(intx0, inty0, paint);
            } else {
                paint.setColor(Color.rgb(0, 0, 0));
                canvas.drawPoint(intx0, inty0, paint);
            }
            pi = (double) n1 / (i + 1) * 4;
        }
        Log.v("LogPi", "円周率:"+pi);
    }

}

実際に描画した画面(打点数10万)
Screenshot_20161212-144826.png
この時の求めた円周率は3.134でした。
もしランダムメソッドから得られる値に偏りが合った場合、ここで求められる円周率が大幅に狂っていきます。
3.134という値は。。。いや駄目ですね。算数のテストで使用したら間違いなくバツですね。
モンテカルロ法はサンプル数が多いほど、ある程度まで精度が上がる性質があるので、次は300万回の打点を行ってみます。

実際に描画した画面(打点数300万)
Screenshot_20161212-144535.png
求められた円周率は3.1412。。。3.14になったのでOKとしてください。モンテカルロ方は正確な値を求められる方法ではないのでこんな感じです。

余談

randXとrandYの配列の他にrandZを用意し
変更前
if (randX[i] * randX[i] + randY[i] * randY[i] < 1.0) {


変更後
if (randX[i] * randX[i] + randY[i] * randY[i] + randZ[i] * randZ[i] < 1.0) {

とすると、先程までは2次元の円が描画されていましたが、
Screenshot_20161212-145819.png
球体で描画されます。
同じ方法でもう一次元足して上げると4次元の球体が描画。。。されているのかな??

8
1
0

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
8
1