2025年7月16日水曜日

モンテカルロ法を用いて円周率を確率的に求めるPythonコード

 はい、モンテカルロ法を用いて円周率を確率的に求めるPythonコードを作成します。


円周率を確率で求めるPythonコード

このコードは、モンテカルロ法と呼ばれるシミュレーション手法を用いて円周率を近似します。

考え方:

  1. 辺の長さが1の正方形を考えます。その面積は 1times1=1 です。

  2. この正方形の中に、半径1の扇形(円の4分の1)を考えます。この扇形は、正方形の左下隅を原点とし、半径1の円の第一象限部分です。

  3. この扇形の面積は pitimes12times(1/4)=pi/4 です。

  4. 正方形の中にランダムに点を打つと、その点が扇形の中に入る確率は、扇形の面積と正方形の面積の比に等しくなります。

    つまり、確率 P=(pi/4)/1=pi/4 です。

  5. したがって、もし N 回点を打ち、そのうち M 回が扇形の中に入ったとすると、M/Napproxpi/4 となり、piapprox4times(M/N) で円周率を近似できます。

このコードでは、正方形の辺の長さを1とし、原点を (0,0) とします。そして、ランダムに生成される点のx座標とy座標も0から1の範囲とします。この場合、半径1の真円は、実際には原点中心の半径1の円の第1象限(xとyが両方正の領域)になります。

Python
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}")

コードの解説

  1. import random: ランダムな数値を生成するために random モジュールをインポートします。

  2. 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 の推定値が得られます。

  3. if __name__ == "__main__": ブロック:

    • この部分は、スクリプトが直接実行された場合にのみ実行されます。

    • 異なる数の num_dartsestimate_pi 関数を呼び出し、結果を出力して、矢の数を増やすほど推定値が実際の円周率 (math.pi) に近づくことを示しています。

このモンテカルロ法は、計算量が多くなるほど精度が向上しますが、数学的な計算方法に比べて収束が遅いという特徴があります。しかし、乱数を使った直感的なシミュレーションで円周率を求めることができる点がユニークです。

0 件のコメント:

コメントを投稿