はい、モンテカルロ法を用いて円周率を確率的に求めるPythonコードを作成します。
円周率を確率で求めるPythonコード
このコードは、モンテカルロ法と呼ばれるシミュレーション手法を用いて円周率を近似します。
考え方:
辺の長さが1の正方形を考えます。その面積は 1times1=1 です。
この正方形の中に、半径1の扇形(円の4分の1)を考えます。この扇形は、正方形の左下隅を原点とし、半径1の円の第一象限部分です。
この扇形の面積は pitimes12times(1/4)=pi/4 です。
正方形の中にランダムに点を打つと、その点が扇形の中に入る確率は、扇形の面積と正方形の面積の比に等しくなります。
つまり、確率 P=(pi/4)/1=pi/4 です。
したがって、もし N 回点を打ち、そのうち M 回が扇形の中に入ったとすると、M/Napproxpi/4 となり、piapprox4times(M/N) で円周率を近似できます。
このコードでは、正方形の辺の長さを1とし、原点を (0,0) とします。そして、ランダムに生成される点のx座標とy座標も0から1の範囲とします。この場合、半径1の真円は、実際には原点中心の半径1の円の第1象限(xとyが両方正の領域)になります。
import random
def estimate_pi(num_darts):
"""
モンテカルロ法を用いて円周率を推定する関数
Args:
num_darts (int): 的に当てる矢の総数
Returns:
float: 推定された円周率の値
"""
inside_circle_count = 0
for _ in range(num_darts):
# 0から1の範囲でランダムなx座標とy座標を生成
x = random.uniform(0, 1)
y = random.uniform(0, 1)
# 原点からの距離を計算(三平方の定理: 距離^2 = x^2 + y^2)
distance_squared = x**2 + y**2
# 距離が半径1以内(つまり距離の2乗が1以内)であれば円の中に入ったと判定
if distance_squared <= 1:
inside_circle_count += 1
# 円周率の推定値を計算 (円の面積 / 正方形の面積 = πr^2 / s^2)
# 今回はr=1, s=1の正方形に半径1の円の1/4が入っていると考えるため、
# (円の中に入った点の数 / 全体の点の数) * 4 となる
pi_estimate = 4 * (inside_circle_count / num_darts)
return pi_estimate
# 試しに計算してみる
if __name__ == "__main__":
# 矢の数を増やすほど精度が向上します
num_darts_1 = 1000
pi_approx_1 = estimate_pi(num_darts_1)
print(f"矢の数 {num_darts_1} 本の場合の円周率の推定値: {pi_approx_1}")
num_darts_2 = 100000
pi_approx_2 = estimate_pi(num_darts_2)
print(f"矢の数 {num_darts_2} 本の場合の円周率の推定値: {pi_approx_2}")
num_darts_3 = 1000000
pi_approx_3 = estimate_pi(num_darts_3)
print(f"矢の数 {num_darts_3} 本の場合の円周率の推定値: {pi_approx_3}")
num_darts_4 = 10000000 # さらに多くの矢を試す
pi_approx_4 = estimate_pi(num_darts_4)
print(f"矢の数 {num_darts_4} 本の場合の円周率の推定値: {pi_approx_4}")
import math
print(f"\n実際の円周率 (math.pi): {math.pi}")
コードの解説
import random
: ランダムな数値を生成するためにrandom
モジュールをインポートします。estimate_pi(num_darts)
関数:num_darts
:シミュレーションで投げる矢(ランダムな点)の総数です。この数が多いほど、円周率の推定精度は高まります。inside_circle_count = 0
: 円の中に入った矢の数を数えるカウンターです。for _ in range(num_darts):
: 指定された矢の数だけループを回します。x = random.uniform(0, 1)
、y = random.uniform(0, 1)
: 0から1の範囲で均等に分布するランダムな浮動小数点数(x座標とy座標)を生成します。これにより、正方形内のどこかに矢がランダムに放たれたことをシミュレートします。distance_squared = x**2 + y**2
: 原点 (0,0) から矢が落ちた点 (x,y) までの距離の2乗を計算します。これは、三平方の定理 () を利用しています。if distance_squared <= 1:
: 矢が半径1の円(の第1象限部分)の中に入ったかどうかを判定します。距離の2乗が1以下であれば、円の中に入っていると判断できます(距離が1以下と同じ意味)。inside_circle_count += 1
: 円の中に入った矢の数を1増やします。pi_estimate = 4 * (inside_circle_count / num_darts)
: 最後に円周率を推定します。inside_circle_count / num_darts
: これは、円(扇形)の中に矢が入った確率です。この確率は pi/4 に近似されるため、それを4倍することで pi の推定値が得られます。
if __name__ == "__main__":
ブロック:この部分は、スクリプトが直接実行された場合にのみ実行されます。
異なる数の
num_darts
でestimate_pi
関数を呼び出し、結果を出力して、矢の数を増やすほど推定値が実際の円周率 (math.pi
) に近づくことを示しています。
このモンテカルロ法は、計算量が多くなるほど精度が向上しますが、数学的な計算方法に比べて収束が遅いという特徴があります。しかし、乱数を使った直感的なシミュレーションで円周率を求めることができる点がユニークです。
0 件のコメント:
コメントを投稿