クラスを継承して改良しよう ~ビュフォンの針を落とす ep2~

python
python

「ビュフォンの針」のシミュレーションで円周率が出せた!!

けど、円周率出すのに、sinθ使っちゃったのがなぁ・・

記事①:Pythonで円周率を求めよう ~ビュフォンの針を落とす ep1~

前回は、「ビュフォンの針」の問題をシミュレーションにより解きました。
それなりにできたのですが、問題はsinθを使って解決しているところです。
今回、まずここを解決していきましょう。
(2021年4月17日:学習開始57日目 PyQさんで勉強中!

オンラインPython学習サービス「PyQ™(パイキュー)」


今回も、引き続き「ビュフォンの針」と戦います。
前回に引き続き「針」に関わる曲を聴きながらやっていきます。
前とは一転、メロデス=メロディックデスメタルの雄 Children of Bodom の超名盤 「Hate Crew Deathroll」から強力なパンチを食らわせる曲「Needled 24 / 7」を聞いて、テンションを挙げていきましょう!!(曲名から公式YouTubeに飛びます。)

さてさて、やっていきましょう!
(プログラムは最後に完成していますが、今回爆死回です!!)

1.前回の振り返りと今回やりたい事

冒頭でも書いていますが、前回、「ビュフォンの針」のシミュレーションにより、円周率をそこそこ求めることが出来ました。

まずは、簡単に「ビュフォンの針」の問題を振り返りましょう。
詳細は前回の記事にあるので省略しますが、内容は以下です。

①:間隔で平行線が描かれている床を用意します。
②:長さ(エル)の針を床に落とします。(針は床に刺さらずに倒れるものとします。)
③:床の平行線と針が交差する確率を求めます。

で、t > lの場合、針と床の線が交差する確率は、以下のようになり円周率が現れます。

で、前回は以下の図をもとに考えました。

要は、針先のポイント(x, y)と平行線との角度θから、平行線と重なるかどうかを判定しました。
上に記載した、「ビュフォンの針」のルールから考えると、特に問題はありません。
しかし、最終的に円周率を出したいので、その算出の途中にθを使うのはちょっと微妙です。

今回は、確率の算出に角度θを使わずに求めてみましょう!!

2.作戦会議

θを使わずに、問題を解いていくと決めました。
では、どのように解決すれば良いのでしょうか?

やること自体は、「ビュフォンの針」の内容から変わりません。
①「針を落とす」=「針先を決める」→「針末端座標を決める」
②平行線と交差しているかを判定する。
③繰り返し実行し、確率を算出する。

前回は、①の「針末端座標を決める」ところにθをつかう必要がありました。
そのため「針を落とす」ところでθを決定していました。
ここを改善する必要がありそうです。

では、「針末端座標」をどのように決めればよいでしょうか?
図で考えてみます。

前回は、「針先座標(x, y)」、「針の長さl」、「角度θ」から「針末端座標 (x_ep, y_ep)を求めていました。
今回は、「針先座標(x, y)」、「針の長さl」および「針末端x座標 x_ep 」から、「針末端y座標 y_ep 」を求める、というやり方を考えたいと思います。

もうひとつ、プログラムの書き方についてです。
前回作成した、class「ニードル」を「継承」して新たな子クラスを作成したいと思います。
継承をめちゃめちゃ雑に言うと、「元のclass(=親クラス)と同じ機能を別のclass(=子クラス)」を作って、「子クラスの変数、関数をいい感じに変える」って感じです。

ではやっていきましょう。

3.プログラムを書いていこう① ~改変ポイント整理~

ではプログラムを書いていきましょう。

クラスを継承して新たなクラスを作成します。
では、前回のプログラムを振り返りましょう。前回記事からclass「needle」部分を抜粋します。

import random
import math
~~~~~略~~~~~
class Needle:
    def __init__(self, n_len=1, x_lim = 1, y_lim = 1, x_posi = 0, y_posi = 0, theta =0):
        self.n_len = n_len #針の長さ n
        self.x_lim = x_lim #x最大値
        self.y_lim = y_lim #y最大値
        self.x_posi = x_posi #針先位置 x
        self.y_posi = y_posi #針先位置 y 
        self.theta = theta #針角度θ

    def throw(self):
        self.x_posi = random.uniform(0, self.x_lim) #x位置を0~xlimまでの小数に変える
        self.y_posi = random.uniform(0, self.y_lim) #y位置を0~ylimまでの小数に変える
        self.theta = random.uniform(0, 360) #θを0~360までの小数に変える

    def endpoint(self, xy = 'y'): #針先終点計算、xyはどちらを出力するか?
        #θをラジアンに変換、cos(ラジアン)、sin(ラジアン)
        #x終点 = x + l cos(θ)、y終点 = y + l sin(θ)
        x_ep = self.x_posi + self.n_len * math.cos(math.radians(self.theta))
        y_ep = self.y_posi + self.n_len * math.sin(math.radians(self.theta))
        if xy == 'x':
            return x_ep
        elif xy == 'y':
            return y_ep
        else:
            return 'error'
    
    def y_change(self, t_val, ep = ''):
        y_2 = self.y_posi #y_2にy_posi代入
        while True:
            if y_2 <= t_val: #y_2が間隔t以下
                break
            else:  #y_2が間隔tより大きい
                y_2 -= t_val #y_2から tを引く
        y_2_ep = y_2 + self.n_len * math.sin(math.radians(self.theta))
        if ep == 'ep':
            return y_2_ep #y変更後の終点
        else:
            return y_2 #y変更後のy
~~~~~略~~~~~


では、新たに作成するclass(=子クラス)に持たせたい機能(=親クラスからの改変ポイント)を考えていきましょう。
この「改変」ですが、「オーバーライド」といいます。かっけぇ・・・。
子クラスの名前はclass「needle_not_theta」とします。

改変ポイント①:クラス変数x_ep、y_epの導入
親class「needle」では、クラス変数として「n_len」「x_lim」「y_lim」「x_posi」「y_posi」「theta」を持っていました。
針の末端座標を意味する「x_ep」と「y_ep」は「endpoint」関数の中で算出されています。
子class「needle_not_theta」では、「x_ep」と「y_ep」をクラス変数として導入することにします。理由は、次の関数にかかわります。

改変ポイント②:throw関数でθを変えずにx_epを決める。y_epとθを計算する。
親class「needle」ではthrow関数で、針の先端位置「x_posi」「y_posi」と角度「theta」をランダムで決めました。
子class「needle_not_theta」では、針の先端位置「x_posi」「y_posi」と針の末端位置「x_ep」をランダムで決めます。図から考えてみましょう。

「x_ep」は「x_posi」を中心として長さlを持ちます。
つまり、「x_ep」の座標は、「x_posi ー l ~ x_posi + l」の間に収まります。

針の末端位置「y_ep」を計算します。
三平方の定理を使えば計算できます。

ここから、「y_ep」を算出できます。
しかし、この時点では「y_ep」の取りうる箇所は2カ所存在します。(図の赤丸位置)
そのため、y_ep = y + |y_ep – y| か、 y_ep = y |y_ep – y|を選択する必要があります。
上の式をみると、一カ所+かーを選択すれば良さそうです。

続いて「θ」を算出します。
「x_ep」と「y_ep」「l」が決まっているので、ここから「θ」が計算できますね。
三角関数のが逆関数arccosから算出できます。(sin、tanでは無くcosを選択した理由は後述)
ここでも解決すべき問題があります。0~360°の中に同じcosを取る角度が2カ所あります。
この解決を考えた結果、cosで計算しています。

θが180°以下、 つまりy_ep = y |y_ep – y|の場合は、arcosで計算できます。
θが180°以上、 つまりy_ep = y |y_ep – y|の場合は、360° – arccosで計算できます。

改変ポイント③:endpoint関数でx_ep、y_epを計算しない
親class「needle」はここで針の末端位置「x_ep」「y_ep」を計算しました。
子class「needle_not_theta」ではすでに計算済みですので、値を返すだけにします。

改変ポイント④:y_change関数をここまでの改変に合わせて調整する
基本的に親class「needle」と子class「needle_not_theta」でやることは同じです。
これまでの改変に合わせて調整します。

ではやっていきましょう。

4.プログラムを書いていこう② ~子クラス作成~

改変ポイントを改めてまとめてみましょう。

上から処理していきましょう。

改変ポイント①:クラス変数x_ep、y_epの導入

ここで子class「needle_not_theta」を作成し、親クラスを継承します。
x_epとy_epを定義、それ以外は引き継ぎます。

import random
import math

~~~~~略~~~~~
class Needle:
~~~~~略~~~~~
class Needle_not_theta(Needle): #クラスNeedle_not_theta クラスNeedleを継承
    def __init__(self, n_len=1, x_lim = 1, y_lim = 1, x_posi = 0, y_posi = 0, theta =0 , x_ep = 1, y_ep = 0):
        super().__init__(n_len, x_lim, y_lim, x_posi, y_posi, theta) #x_ep、y_ep以外は親クラスのまま super()で呼び出し
        self.x_ep = x_ep #x末端座標定義
        self.y_ep = y_ep #y末端座標定義

ここでsuper()は親クラスを呼び出す関数です。
複雑なことはやっていませんが、継承するうえで重要になる記載方法で!!

次に行きましょう。

改変ポイント②:throw関数でθを変えずにx_epを決める。y_epとθを計算する。

針を投げる関数です。
針先端のx_posiとy_posiは親クラスの関数と同じで良いです。
つづいて、針末端座標、x_epをランダムで選び、y_epを計算します。
まずはここまでやりましょう。考え方は先に記載した通りです。

import random
import math

~~~~~略~~~~~
class Needle:
~~~~~略~~~~~
class Needle_not_theta(Needle): #クラスNeedle_not_theta クラスNeedleを継承
~~~~~略~~~~~
    def throw(self):
        super().throw() #x_posi,y_posi, thetaをランダムで選択
        x_ep_len = random.uniform(-self.n_len, self.n_len) # x_posiとx末端座標までの差 -lからlの間で選択
        self.x_ep = self.x_posi + x_ep_len # 末端座標までの差 -lからlの間で選択
        y_ep_len = math.sqrt((self.n_len**2) - (x_ep_len**2)) # y_posiとy末端座標までの差 三平方の定理
        y_ep_pm = random.choice([-1, 1]) # y末端座標計算に使用 +1か-1を選択
        self.y_ep = self.y_posi + (y_ep_pm * y_ep_len) # y末端座標 = y先端 + y_ep_len離 or y先端 - y_ep_len


続いてθを求めます。
実は、super().throw()を先に実行していますので、いったんランダムで選ばれています。
この後の処理で上書きすることとします。

まず、cosθを求めます。
「斜辺=針の長さl」と「底辺=針のx座標の末端と先端の差」から計算できます。
次にcosθからθを求めます。θ = arccos(cosθ)で求まります
これを計算すると、0~180°が計算されます。
180°以上の場合を考えましょう。
すでに定義した「y_ep_pm」で「ー」になる場合、θは180°以上になります。(図参照)
この場合、θは360ー(いったん計算したθ)で計算できます。
ここまでを踏まえて、プログラムを書いてみましょう。

    def throw(self):
        super().throw() #x_posi,y_posi, thetaをランダムで選択
        x_ep_len = random.uniform(-self.n_len, self.n_len) # x_posiとx末端座標までの差 -lからlの間で選択
        self.x_ep = self.x_posi + x_ep_len # 末端座標までの差 -lからlの間で選択
        y_ep_len = math.sqrt((self.n_len**2) - (x_ep_len**2)) # y_posiとy末端座標までの差 三平方の定理
        y_ep_pm = random.choice([-1, 1]) # y末端座標計算に使用 +1か-1を選択
        self.y_ep = self.y_posi + (y_ep_pm * y_ep_len) # y末端座標 = y先端 + y_ep_len離 or y先端 - y_ep_len
        cos_theta = x_ep_len/self.n_len # cosθ = x座標距離 / 針長さl
        theta_dg = math.degrees(math.acos(cos_theta)) #cosθ > θ(ラジアン) > θ(degree)
        self.theta = y_ep_pm * theta_dg # 180°以上ならy_ep_pmは-1
        if self.theta < 0:
            self.theta +=360 #180°以上なら、-theta+360


次に行きましょう。

改変ポイント③:endpoint関数でx_ep、y_epを計算しない

ここは、計算「しない」なので簡単です。サクッと行きましょう。

import random
import math

~~~~~略~~~~~
class Needle:
~~~~~略~~~~~
class Needle_not_theta(Needle): #クラスNeedle_not_theta クラスNeedleを継承
~~~~~略~~~~~
    def endpoint(self, xy = 'y'):
        x_ep = self.x_ep #x_epはthrowで計算済み
        y_ep = self.y_ep #y_epはthrowで計算済み
        if xy == 'x':
            return x_ep
        elif xy == 'y':
            return y_ep
        else:
            return 'error'

改変ポイント④:y_change関数をここまでの改変に合わせて調整する

y_change関数は前回記事参照
y_2は親クラスと同様に計算します。y_2_epはもともとθから計算していました。
今回は角度から位置を算出するのは排除したいので、いままで決めた位置座標から計算します。

import random
import math

~~~~~略~~~~~
class Needle:
~~~~~略~~~~~
class Needle_not_theta(Needle): #クラスNeedle_not_theta クラスNeedleを継承
~~~~~略~~~~~
    def y_change(self, t_val, ep = ''):
        y_2 = super().y_change(t_val, ep = '') #y_2はneedleクラスと同じ計算
        y_2_ep = self.y_ep - (self.y_posi - y_2) #y_2_ep = y_ep - (y_posi - y_2)
        if ep == 'ep':
            return y_2_ep #y変更後の終点
        else:
            return y_2 #y変更後のy

できました。

一旦、ここまでのものを合算して、いろいろprintしてみます。

import random
import math

~~~~~略~~~~~
class Needle:
~~~~~略~~~~~
class Needle_not_theta(Needle): #クラスNeedle_not_theta クラスNeedleを継承
    def __init__(self, n_len=1, x_lim = 1, y_lim = 1, x_posi = 0, y_posi = 0, theta =0 , x_ep = 1, y_ep = 0):
        super().__init__(n_len, x_lim, y_lim, x_posi, y_posi, theta) #x_ep、y_ep以外は親クラスのまま super()で呼び出し
        self.x_ep = x_ep #x末端座標定義
        self.y_ep = y_ep #y末端座標定義

    def throw(self):
        super().throw() #x_posi,y_posi, thetaをランダムで選択
        x_ep_len = random.uniform(-self.n_len, self.n_len) # x_posiとx末端座標までの差 -lからlの間で選択
        self.x_ep = self.x_posi + x_ep_len # 末端座標までの差 -lからlの間で選択
        y_ep_len = math.sqrt((self.n_len**2) - (x_ep_len**2)) # y_posiとy末端座標までの差 三平方の定理
        y_ep_pm = random.choice([-1, 1]) # y末端座標計算に使用 +1か-1を選択
        self.y_ep = self.y_posi + (y_ep_pm * y_ep_len) # y末端座標 = y先端 + y_ep_len離 or y先端 - y_ep_len
        cos_theta = x_ep_len/self.n_len # cosθ = x座標距離 / 針長さl
        theta_dg = math.degrees(math.acos(cos_theta)) #cosθ > θ(ラジアン) > θ(degree)
        self.theta = y_ep_pm * theta_dg # 180°以上ならy_ep_pmは-1
        if self.theta < 0:
            self.theta +=360 #180°以上なら、-theta+360
    
    def endpoint(self, xy = 'y'):
        x_ep = self.x_ep #x_epはthrowで計算済み
        y_ep = self.y_ep #y_epはthrowで計算済み
        if xy == 'x':
            return x_ep
        elif xy == 'y':
            return y_ep
        else:
            return 'error'

    def y_change(self, t_val, ep = ''):
        y_2 = super().y_change(t_val, ep = '') #y_2はneedleクラスと同じ計算
        y_2_ep = self.y_ep - (self.y_posi - y_2) #y_2_ep = y_ep - (y_posi - y_2)
        if ep == 'ep':
            return y_2_ep #y変更後の終点
        else:
            return y_2 #y変更後のy

needle = Needle_not_theta(n_len=2, x_lim = 12, y_lim = 12,)
needle.throw() #針を投げて、x、y、x_ep, y_ep, θを再設定
print(f'投げ後x {needle.x_posi}')
print(f'投げ後y {needle.y_posi}')
print(f'投げ後θ {needle.theta}')
print('投げ後x末端', needle.endpoint('x'))
print('投げ後y末端',needle.endpoint('y'))
#三平方の定理から針の長さを計算 math.sqrt()で平方根を計算
hd_len_2jyou = (needle.x_posi - needle.endpoint('x'))**2 + (needle.y_posi - needle.endpoint('y'))**2
print(f'計算針長 {math.sqrt(hd_len_2jyou)}')
print('変換y先端', needle.y_change(3))
print('変換y末端',needle.y_change(1, ep = 'ep'))
hd_len_2jyou = (needle.x_posi - needle.endpoint('x'))**2 + (needle.y_posi - needle.endpoint('y'))**2
print(f'計算針長 {math.sqrt(hd_len_2jyou)}')

結果はこうなりました。

投げ後x 6.693850036916482
投げ後y 5.703015188140151
投げ後θ 286.16977791361944
投げ後x末端 7.250819109759437
投げ後y末端 3.7821337623627924
計算針長 2.0
変換y先端 2.703015188140151
変換y末端 -1.2178662376372076
計算針長 2.0

うまくできてそうです。

5.プログラムを書いていこう③ ~実行していこう~

すべてをまとめて実行してみましょう。
前回と変えているのは、
・子class「needle_not_theta」の追加
・buffon_main関数のneedle = Needle_not_theta
です。
まずはプログラムはこうなりました!!

import random
import math

class Input_para:
    def __init__(self, t_val = 0, l_val= 0, n_val =0):
        self.t_val = t_val #間隔:t
        self.l_val = l_val #針の長さ:l
        self.n_val = n_val #試行回数:n
    
    def inp_val(self, p_type = '', val_type = float): #P_type:t, l, n val_type:float, int
        while True:
            para_str = input(f'{p_type}を入力:')
            try:
                para_tc = val_type(para_str) #floatかintに変換
                return para_tc #floatかintで返す
            except ValueError: #誤った値が入力された場合
                print ('数字を入力してください')
            else:
                break

class Needle:
    def __init__(self, n_len=1, x_lim = 1, y_lim = 1, x_posi = 0, y_posi = 0, theta =0):
        self.n_len = n_len #針の長さ n
        self.x_lim = x_lim #x最大値
        self.y_lim = y_lim #y最大値
        self.x_posi = x_posi #針先位置 x
        self.y_posi = y_posi #針先位置 y 
        self.theta = theta #針角度θ

    def throw(self):
        self.x_posi = random.uniform(0, self.x_lim) #x位置を0~xlimまでの小数に変える
        self.y_posi = random.uniform(0, self.y_lim) #y位置を0~ylimまでの小数に変える
        self.theta = random.uniform(0, 360) #θを0~360までの小数に変える

    def endpoint(self, xy = 'y'): #針先終点計算、xyはどちらを出力するか?
        #θをラジアンに変換、cos(ラジアン)、sin(ラジアン)
        #x終点 = x + l cos(θ)、y終点 = y + l sin(θ)
        x_ep = self.x_posi + self.n_len * math.cos(math.radians(self.theta))
        y_ep = self.y_posi + self.n_len * math.sin(math.radians(self.theta))
        if xy == 'x':
            return x_ep
        elif xy == 'y':
            return y_ep
        else:
            return 'error'
    
    def y_change(self, t_val, ep = ''):
        y_2 = self.y_posi #y_2にy_posi代入
        while True:
            if y_2 <= t_val: #y_2が間隔t以下
                break
            else:  #y_2が間隔tより大きい
                y_2 -= t_val #y_2から tを引く
        y_2_ep = y_2 + self.n_len * math.sin(math.radians(self.theta))
        if ep == 'ep':
            return y_2_ep #y変更後の終点
        else:
            return y_2 #y変更後のy

class Needle_not_theta(Needle): #クラスNeedle_not_theta クラスNeedleを継承
    def __init__(self, n_len=1, x_lim = 1, y_lim = 1, x_posi = 0, y_posi = 0, theta =0 , x_ep = 1, y_ep = 0):
        super().__init__(n_len, x_lim, y_lim, x_posi, y_posi, theta) #x_ep、y_ep以外は親クラスのまま super()で呼び出し
        self.x_ep = x_ep #x末端座標定義
        self.y_ep = y_ep #y末端座標定義

    def throw(self):
        super().throw() #x_posi,y_posi, thetaをランダムで選択
        x_ep_len = random.uniform(-self.n_len, self.n_len) # x_posiとx末端座標までの差 -lからlの間で選択
        self.x_ep = self.x_posi + x_ep_len # 末端座標までの差 -lからlの間で選択
        y_ep_len = math.sqrt((self.n_len**2) - (x_ep_len**2)) # y_posiとy末端座標までの差 三平方の定理
        y_ep_pm = random.choice([-1, 1]) # y末端座標計算に使用 +1か-1を選択
        self.y_ep = self.y_posi + (y_ep_pm * y_ep_len) # y末端座標 = y先端 + y_ep_len離 or y先端 - y_ep_len
        cos_theta = x_ep_len/self.n_len # cosθ = x座標距離 / 針長さl
        theta_dg = math.degrees(math.acos(cos_theta)) #cosθ > θ(ラジアン) > θ(degree)
        self.theta = y_ep_pm * theta_dg # 180°以上ならy_ep_pmは-1
        if self.theta < 0:
            self.theta +=360 #180°以上なら、-theta+360
    
    def endpoint(self, xy = 'y'):
        x_ep = self.x_ep #x_epはthrowで計算済み
        y_ep = self.y_ep #y_epはthrowで計算済み
        if xy == 'x':
            return x_ep
        elif xy == 'y':
            return y_ep
        else:
            return 'error'

    def y_change(self, t_val, ep = ''):
        y_2 = super().y_change(t_val, ep = '') #y_2はneedleクラスと同じ計算
        y_2_ep = self.y_ep - (self.y_posi - y_2) #y_2_ep = y_ep - (y_posi - y_2)
        if ep == 'ep':
            return y_2_ep #y変更後の終点
        else:
            return y_2 #y変更後のy

def buffon_main(t_val, l_val, n_val):
    num = 0 #試行回数の設定
    hit = 0 #あたり回数の設定
    limit = 3*t_val #xとyの最大値は 3t
    while num < n_val: #試行回数 < 目標試行回数
        needle = Needle_not_theta(n_len = l_val, x_lim = limit, y_lim = limit) #針の設定
        needle.throw() #針を投げる = x, y, θの再設定
        if needle.theta <= 180: #θ <= 180
            if needle.y_change(t_val, 'ep') >= t_val:
                hit += 1 #交差カウント +1
            else:
                pass
        else: #θ > 180
            if needle.y_change(t_val, 'ep') <= 0:
                hit += 1 #交差カウント +1
            else:
                pass
        y_2 = needle.y_change(t_val, 'ep')
        #print(f'x:{needle.x_posi}, y:{needle.y_posi}, θ:{needle.theta}, y_2_ep:{y_2}')
        num += 1 #
    print(f'試行回数:{num}')
    print(f'交差本数:{hit}')
    prob = hit/num #交差する確率
    print(f'交差する確率 P = 2l/t(pi) = {prob}')
    pi = 2*l_val/(t_val*prob) #pi = 2*l/(t*prob)
    print(f'円周率 : {pi}')

para = Input_para()
para.t_val = para.inp_val('間隔 t ', float)
para.l_val = para.inp_val('針の長さ l ', float)
para.n_val = para.inp_val('試行回数 n ', int)
print(f'間隔 t :{para.t_val}, 針の長さ l : {para.l_val}, 試行回数 n : {para.n_val}')
buffon_main(para.t_val, para.l_val, para.n_val)


今回、継承したクラス以外の追加以外何もしていません。
これが「オブジェクト指向」と「継承」の威力です。

では実行してみましょう。前回同様t=4、l=3としてnを変えていってみましょう。

n =10、円周率2.14。まだまだ。

間隔 t を入力:4
針の長さ l を入力:3
試行回数 n を入力:10
間隔 t :4.0, 針の長さ l : 3.0, 試行回数 n : 10
試行回数:10
交差本数:7
交差する確率 P = 2l/t(pi) = 0.7
円周率 : 2.142857142857143


n = 1000、円周率2.61。まだかな?

間隔 t を入力:4
針の長さ l を入力:3
試行回数 n を入力:1000
間隔 t :4.0, 針の長さ l : 3.0, 試行回数 n : 1000
試行回数:1000
交差本数:573
交差する確率 P = 2l/t(pi) = 0.573
円周率 : 2.617801047120419

n = 10000、円周率2.53。前回はこのくらいから大体計算できたのですが、、、雲行き怪しい。

間隔 t を入力:4
針の長さ l を入力:3
試行回数 n を入力:10000
間隔 t :4.0, 針の長さ l : 3.0, 試行回数 n : 10000
試行回数:10000
交差本数:5909
交差する確率 P = 2l/t(pi) = 0.5909
円周率 : 2.538500592316805

n = 10000000、円周率2.54 ヤバい!!

間隔 t を入力:4
針の長さ l を入力:3
試行回数 n を入力:10000000
間隔 t :4.0, 針の長さ l : 3.0, 試行回数 n : 10000000
試行回数:10000000
交差本数:5891269
交差する確率 P = 2l/t(pi) = 0.5891269
円周率 : 2.5461407380990413

なにかミスったようです。

改めて、いろいろと見直して検証しましたが、プログラム自体には問題ありませんでした。
初めに計画した作戦どおりには動かせています。
ということは、そもそも作戦に誤りがあったようですね。

次回は、何がダメだったのかを検証していきます。

To Be Continued : ビュフォンの針を落とす ep3

PyQさんで勉強中!

コメント

タイトルとURLをコピーしました