2010年3月24日水曜日

封筒の話(さらに続き)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

ここで、封筒に入れる金額は、ホストは以下のように決定します。ホストは、さいころを5か6が出るまで連続して振ります。この時、1〜4の目が出た数をn とします。

「この時、1〜4の目が出た回数をn とします」と読まないといけないのね。
しかしでかい方をあけた確率が0.6になってる。変すぎ。
[nori@shinano]~/Desktop/study/python/hack% python two2envelopes.py 100000
[1, 16685, 16685, 33370, 0] 2.0 0.0
[2, 27613, 55226, 60634, 16606] 1.09792489045 0.601383406367
[4, 18749, 74996, 82270, 11287] 1.09699183956 0.60200544029
[8, 12305, 98440, 107588, 7441] 1.09292970337 0.604713531085
[16, 8234, 131744, 144736, 4948] 1.09861549672 0.600923002186
[32, 5508, 176256, 194928, 3283] 1.10593681917 0.596042120552
[64, 3664, 234496, 263456, 2141] 1.1234989083 0.584334061135
[128, 2399, 307072, 337280, 1442] 1.09837432263 0.60108378491
[256, 1624, 415744, 453248, 985] 1.09020935961 0.606527093596
[512, 1074, 549888, 599808, 651] 1.09078212291 0.606145251397
[1024, 729, 746496, 821760, 437] 1.10082304527 0.599451303155
[2048, 469, 960512, 1048576, 284] 1.09168443497 0.605543710021
[4096, 296, 1212416, 1374208, 171] 1.13344594595 0.577702702703
[8192, 197, 1613824, 1667072, 127] 1.03299492386 0.644670050761
[16384, 162, 2654208, 3072000, 91] 1.15740740741 0.561728395062
[32768, 96, 3145728, 3342336, 60] 1.0625 0.625
[65536, 79, 5177344, 6324224, 41] 1.22151898734 0.518987341772
[131072, 39, 5111808, 5111808, 26] 1.0 0.666666666667
[262144, 27, 7077888, 7864320, 16] 1.11111111111 0.592592592593
[524288, 21, 11010048, 11796480, 13] 1.07142857143 0.619047619048
['sum', 99970, 40770819, 44700102]
修正後のコード
import sys
import random

class Die:
  def roll(self):
    r = random.randint(1, 6)
    assert r > 0
    assert r < 7
    return r
  def odd(self):
    return bool(random.randint(0, 1))

die = Die()

class Envelope:
  def __init__(self):
    r = die.roll()
    n = 0
    while r < 5:
      n += 1
      r = die.roll()
    self.values = (1 << n, 1 << (n + 1))
    self.first_opend = die.odd()

  def open(self):
    return self.values[self.first_opend]

  def swap(self):
    return self.values[not self.first_opend]
    

def experiment(t):
  result = {}
  for i in range(t):
    e = Envelope()
    v = e.open()
    s = e.swap()
    r = result.get(v, None)
    if r is None:
      r = [0, 0, 0, 0] #occurence, none-swap case, swap case, respectivly
    r[0] += 1
    r[1] += v
    r[2] += s
    r[3] += int(e.first_opend)
    result[v] = r
  return result

r = experiment(int(sys.argv[1]))

xs = [[i, r[i][0], r[i][1], r[i][2], r[i][3]] for i in r]
xs.sort(key=lambda x: x[0])

total = ['sum', 0, 0, 0]
for i in range(20):
  r=xs[i]
  total[1] += r[1]
  total[2] += r[2]
  total[3] += r[3]
  print r, 1.0*r[3]/r[2], 1.0*r[4]/r[1]
print total

2 件のコメント:

spbackgammon さんのコメント...
このコメントは投稿者によって削除されました。
spbackgammon さんのコメント...

ある封筒の組があったときに大きい方を開けた確率を計算して1/2になるのをたしかめたいんだろうけど、このプログラムでしてるのは最初に開けた金額 2^n を含む 封筒(2^(n-1),2^n), (2^n, 2^(n+1)) のそれぞれの場合で大きい方を開けた数をカウントしたのを集計して2^nの頻度で割っている。だから前者の封筒の組が出た数の分だけ分子にカウントされて後者の封筒の組の場合は0。それぞれ封筒の組が生成される比は 3:2 だから 60%になるよ。