みけCATのにっき(仮)
つれづれなるまゝに、日くらし、PCにむかひて、心に移りゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
(本当か!?)
出典

DXライブラリでモンテカルロ法

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

DXライブラリでモンテカルロ法

投稿記事 by みけCAT » 14年前

最近学校の情報の時間にモンテカルロ法を習ったので、DXライブラリで作ってみました。
実行すると0x7fffffff回の試行を行い、結果を画面とresult.txtに出力します。

CODE:

#include "DxLib.h"
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        ChangeWindowMode( TRUE ) ; // ウインドウモードに変更
        if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 エラーが起きたら終了
		SetDrawScreen( DX_SCREEN_BACK ) ;           // 描画先を裏画面に設定
		SetAlwaysRunFlag(TRUE);
 		unsigned int i;
 		unsigned int in;
 		int White;
 		double x,y;
 		double pi_4;
 		double pi;
 		White=GetColor(255,255,255);
 		in=0;
 		for(i=0;i<0x7fffffff;i++) {
 			x=(double)GetRand(1000000000)/1000000000;
 			y=(double)GetRand(1000000000)/1000000000;
 			if(x*x+y*y<1)in++;
 			/*進行状況の表示*/
 			if((i & 0xffffff)==0) {
 				ClearDrawScreen();
 				DrawString(50,20,"計算中",White);
 				DrawFormatString(50,50, White , "%1.2f%%" ,
 					(double)i/0x7fffffff*100);
 				DrawBox(10,100,630,130,White,FALSE);
 				DrawBox(10,100,10+(int)(620*(double)i/0x7fffffff),
 					130,White,TRUE);
 				ScreenFlip();
 				if(ProcessMessage()!=0)break;
 			}
 		}
 		/*結果の表示*/
 		pi_4=(double)in/0x7fffffff;
 		pi=pi_4*4;
 		ClearDrawScreen();
 		DrawString(50,20,"計算完了",White);
 		DrawFormatString(50,50,White,"試行回数:%d回",0x7fffffff);
 		DrawFormatString(50,80,White,"円の中に入った回数:%d回",in);
 		DrawFormatString(50,110,White,"円の中に入った割合:%1.15f",pi_4);
 		DrawFormatString(50,140,White,"円周率:%1.15f",pi);
 		ScreenFlip();
 		/*ファイルにも出力*/
 		FILE* out;
 		out=fopen("result.txt","w");
 		if(out!=NULL) {
 			fprintf(out,"試行回数:%d回\n",0x7fffffff);
 			fprintf(out,"円の中に入った回数:%d回\n",in);
 			fprintf(out,"円の中に入った割合:%1.15f\n",pi_4);
 			fprintf(out,"円周率:%1.15f\n",pi);
 			fclose(out);
 		}
 
        WaitKey() ;             // キーの入力待ち(『WaitKey』を使用) 
        DxLib_End() ;           // DXライブラリ使用の終了処理
        return 0 ;              // ソフトの終了
}
結果の例は以下の通りです。

試行回数:2147483647回
円の中に入った回数:1686644070回
円の中に入った割合:0.785404831727616
円周率:3.141619326910464

もう一度実行してみました。

試行回数:2147483647回
円の中に入った回数:1686620758回
円の中に入った割合:0.785394027200512
円周率:3.141576108802048

やっぱりモンテカルロ法の性質上精度は悪いですね。

アバター
GRAM
記事: 164
登録日時: 14年前

Re: DXライブラリでモンテカルロ法

投稿記事 by GRAM » 14年前

うーんモンテカルロ法が悪いというよりかは
(double)GetRand(1000000000)/1000000000←ここにも問題がありそうですね。
まずそもそも格子点では精度に限界がある上、あえて0~1に丸め込むと精度が落ちます・・・
系の大きさを広げて可能な限り整数で計算するのが常套手段です

GetRandにどのような方法が使われているのかはわかりませんが、大量に繰り返すのなら何回かに一回は初期化しなおさないと問題が起こることがあります。