Javaプログラミング学習サイト ゆるゆるプログラミング

2020/12/22 公開

・格子座標から円周率πを計算

円周率πを計算で求める方法を紹介します。

ここでは、単位円を外接する正方形を格子状に区切り、格子全体の座標数と、円の中に入っている座標の比率を利用して円周率πを求める方法を紹介します。

単位円の中心座標を(0,0)とすると、外接する正方形の左上の座標は(-1,1)、右下の座標は(1,-1)です。

単位円を外接する正方形

x軸y軸をそれぞれ等分割し格子を作成します。下の例は、xとyを8分割し、1列に9個の座標を配置したものです。

単位円を外接する正方形

この正方形の1辺の長さは2で、面積は4(=2x2)です。単位円面積π(=1x1xπ)です。

よって、以下の比が成り立ちます。

 外接正方形面積 : 格子全体の座標数 = 単位円面積 : 円内の格子座標数

これを単位円面積を計算する式に変形すると、

 単位円面積=外接正方形面積×(円内の格子座標数÷格子全体の座標数)

となります。

この式は、格子の数が多ければ大きいほど円周率πに近づきます。

下図の例は、格子の座標数が全部で81で、円周率πの計算結果は2.42となりました。格子の座標数が少ないので精度が悪いです。円周率3.14には程遠いです。

格子の座標数から円周率πを計算

それでは、格子を使った円周率πを求めるプログラムを見ていきましょう。

以下は、Javaソースコードです。x軸y軸を20000分割して計算しています。

GridPI.java ← クリックしてダウンロードページに移動
001:    public class GridPI {
002:    	public static void main( String[] args ) {
003:    		// 変数の宣言
004:    		int    cellnum;
005:    		int    x, y;
006:    		double in_num;
007:    		double left, right;
008:    		double top, bottom;
009:    		double celllen;
010:    		double cellx, celly;
011:    		double l2;
012:    
013:    		// 単位円に外接する正方形の左上と右下の座標を代入
014:    		// 左上の座標
015:    		left = -1.0;
016:    		top = 1.0;
017:    
018:    		// 右下の座標
019:    		right = 1.0;
020:    		bottom = -1.0;
021:    
022:    		// 1辺の格子の数
023:    		cellnum = 20000;
024:    
025:    		// セルの幅を計算(x軸だけで計算)
026:    		celllen = ( right - left ) / (double)( cellnum - 1 );
027:    
028:    		// 円周率πの計算のメイン
029:    		// 円内の座標の個数を初期化
030:    		in_num = 0.0;
031:    
032:    		// 格子のy座標の初期値
033:    		celly = top;
034:    		for ( y = 0; y < cellnum; y++ ) {
035:    			// 格子のx座標の初期値
036:    			cellx = left;
037:    			for ( x = 0; x < cellnum; x++ ) {
038:    				// 単位円の中心座標(0,0)と
039:    				//セルの直線距離の2乗を計算
040:    				l2 = cellx * cellx + celly * celly;
041:    
042:    				// 単位円の中かを判定
043:    				if ( 1.0 >= l2 ) {
044:    					// 単位円の中と判定
045:    					// 単位円の線上も中と判定
046:    					++ in_num;
047:    				}
048:    				// 格子のx座標にセルの幅を足す
049:    				cellx += celllen;
050:    			}
051:    			// 格子のy座標からセルの幅を引く
052:    			celly -= celllen;
053:    		}
054:    
055:    		// 外接正方形の面積を計算(計算結果は4.0)
056:    		double sq_area = ( right - left ) * ( top - bottom ); 		
057:    
058:    		// 格子全体の座標数
059:    		double all_num = (double)cellnum * (double)cellnum;
060:    
061:    		// 円周率πを計算
062:    		double pi = sq_area * in_num / all_num;
063:    
064:    		// 結果を出力
065:    		System.out.println( pi );
066:    	}
067:    }

GridPIを実行

C:\talavax\javasample>java GridPI

GridPI.javaの出力結果

3.14127716

実際の円周率πは、

 3.141592653589793238462・・・

です。分割数20000でも小数点以下第3桁までしか一致しません。この方法は、精度は悪く実用的ではないです。

001:    public class GridPI {

クラス名を、GridPIとしています。

002:    	public static void main( String[] args ) {

このmainメソッドからプログラムを実行します。

003:    		// 変数の宣言
004:    		int    cellnum;
005:    		int    x, y;
006:    		double in_num;
007:    		double left, right;
008:    		double top, bottom;
009:    		double celllen;
010:    		double cellx, celly;
011:    		double l2;

このプログラムで使う変数を宣言しています。

013:    		// 単位円に外接する正方形の左上と右下の座標を代入
014:    		// 左上の座標
015:    		left = -1.0;
016:    		top = 1.0;

単位円を外接する正方形の左上の座標を代入しています。

018:    		// 右下の座標
019:    		right = 1.0;
020:    		bottom = -1.0;

単位円を外接する正方形の右下の座標を代入しています。

022:    		// 1辺の格子の数
023:    		cellnum = 20000;

x軸y軸の格子の数を格納する変数cellnumに20000を代入しています。

025:    		// セルの幅を計算(x軸だけで計算)
026:    		celllen = ( right - left ) / (double)( cellnum - 1 );

正方形x軸方向の長さを格子の数から1を引いた値( cellnum - 1 )で割って格子の間隔を計算し、変数celllenに代入しています。

028:    		// 円周率πの計算のメイン
029:    		// 円内の座標の個数を初期化
030:    		in_num = 0.0;

ここから円周率πの計算です。円の内側の個数の初期値に0を代入しています。

032:    		// 格子のy座標の初期値
033:    		celly = top;
034:    		for ( y = 0; y < cellnum; y++ ) {
035:    			// 格子のx座標の初期値
036:    			cellx = left;
037:    			for ( x = 0; x < cellnum; x++ ) {

for文正方形に含まれる全ての格子座標(cellx,celly)を求めています。

038:    				// 単位円の中心座標(0,0)と
039:    				//セルの直線距離の2乗を計算
040:    				l2 = cellx * cellx + celly * celly;
041:    
042:    				// 単位円の中かを判定
043:    				if ( 1.0 >= l2 ) {
044:    					// 単位円の中と判定
045:    					// 単位円の線上も中と判定
046:    					++ in_num;
047:    				}

単位円の中心座標(0,0)と(cellx,celly)の直線距離の2乗を計算した値を変数l2に代入し、その値が単位円半径2乗(1.0=1.0x1.0)以下の場合に円の中に入っていると判定し、変数in_numに1を足しています。

048:    				// 格子のx座標にセルの幅を足す
049:    				cellx += celllen;
050:    			}
051:    			// 格子のy座標からセルの幅を引く
052:    			celly -= celllen;

変数xのfor文でcellxにcelllenを足しています。変数yのfor文でcellyからcelllenを引いています。これで左上から右下の順番で格子座標(cellx,celly)を求めています。

055:    		// 外接正方形の面積を計算(計算結果は4.0)
056:    		double sq_area = ( right - left ) * ( top - bottom ); 		

単位円に外接する正方形面積を計算した結果を変数sq_areaに代入しています。

058:    		// 格子全体の座標数
059:    		double all_num = (double)cellnum * (double)cellnum;

格子全ての座標数を計算した結果を変数all_numに代入しています。

061:    		// 円周率πを計算
062:    		double pi = sq_area * in_num / all_num;

円周率πを計算して、変数piに代入しています。

064:    		// 結果を出力
065:    		System.out.println( pi );

円周率πコンソール出力しています。、

以上です。

■関連コンテンツ

点が円内かを判定 点が円の中か?外か?
値のコンソール表示 print()、println()とは?
π(パイ)の意味と、Math.PIの使い方について解説-画像

円周率π(パイ)

π(パイ)の意味と、Math.PIの使い方について解説

半径1の円-画像

単位円

単位円は半径が1の円のことです。単位円と三角関数(sinθ、cosθ)の関係についても解説しています。

繰り返し処理に使用するfor文について解説-画像

for文

繰り返し処理に使用するfor文をJavaのソースコードを使って説明しています。

条件による処理の分岐に使用するif文について解説-画像

if文

条件による処理の分岐に使用するif文について解説

円の半径と円周率を使って面積を計算する方法を解説-画像

円の面積計算

半径を与えて円の面積を計算するプログラムを解説します。円の面積は、半径×半径×円周率でで計算できます。

■新着情報

2021.2.10 三角形を描く(テキスト版) その2 三角形を描く(テキスト版) その2

■広告

 

 

 

 

 

 

 

 

 

Topへ