コインを表が出るまで投げ続け、投げた回数をNとすると、
2^(N-1)円もらえるとするゲームにおいて、期待値を計算すると、
無限大に発散してしまう。
W=Σk=1,∞(1/2^k・2^(k-1))=∞
これは、直感と反するので、サンクトペテルスブルグのパラドックスと呼ばれる。
一旦、コインを投げる回数の期待値Sを求め、
それから賞金の期待値(もどき)μを算出する方法(方法1)を取ってみる。…①
S=Σk=1,∞ (1/2^k)=2
S=2なので、μ=2^(S-1)=2
故に、答えは2である。
と、いうのは誤っている。(よくある間違い)
一般に、期待値において、f(g(x))=g(f(x))は成り立たないので、
一旦、コインを投げる回数の期待値を求め、
それから賞金の期待値(もどき)を算出するのは誤っている。
しかし、これのどこが間違っているのかは解らない。
意味論的には合ってるが、数学的には間違っている。
1回のゲームでもらえる金額は、2^nなので、ここに、間違いのポイントがある。
ウイリアム・フェラーも標本抽出で算出したが、期待値無限大が正解である。
ゲームの回数が有限に限られるならば、期待値は遥かに小さな値に収束する
無限大の繰り込みができるかどうかは不明
ダニエル・ベルヌーイはこのパラドックスを提示し、賞金の対数を取ることによって、効用という解を求めたが、賞金の金額が大きくなるほど1円の価値が小さくなるというのでは、人間の主観が入ってくるので、客観的な回答にはならない。
方法1とn回シミュレーションを繰り返した場合の平均値を求めるプログラムを載せる。
ここではn=10000とする
#!/usr/bin/python3
import os
import binascii
import random
from getkey import getkey,keys
#方法1
# ∞=10000とした場合のSの近似値
# S=Σk=1,10000 (1/2^k)
#
s=0
for i in range(10000):
s=s+1/2**i
print("方法1:",2**(s-1))
print("Hit any key")
key=getkey()
# 10000回ゲームを繰り返した場合の平均の算出
N=10000
l=[]
r=[]
f=open("/dev/random",'rb') # /dev/randomを開く
# n回シミュレーションをした場合の結果のリストを作る
for i in range(N):
k=0
while(True):
k=k+1
n=f.read(1)
r1=binascii.hexlify(n)
r2=int(r1,16)
if r2%2: break
r+=[k]
l+=[2**(k-1)]
# 平均を取る
a=sum(l)/N
b=sum(r)/N
print("シミュレーション")
print("回数:",r)
print("利得額:",l)
print("コインを投げる平均回数: ",b)
print("μ(%d)=%f"%(N,2**(b-1)))
print("平均利得額: ",a)
プログラムの実行結果
$ ev.py
方法1:2.0
Hit any key
シミュレーション
回数: [3, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 3, 2, 1, 2, 1, 1, 2, 1, 2, 2, 4, 3, 1, 3, 4, 5, 3, 1, 3, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 3, 4, 1, 1, 5, 5, 4, 1, 1, 2, 5, 1, 1, 1, 1, 2, 1, 2, 1, 2, 3, 2, 3, 2, 2, 1, 2, 1, 1, 2, 3, 1, 1, 1, 3, 1, 10, ,長いので略,8, 1, 7, 1, 1, 1]
利得額: [4.0, 1.0, 2.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 4.0, 2.0, 1.0, 2.0, 1.0, 1.0, 2.0, 1.0, 2.0, 2.0, 8.0, 4.0, 1.0, 4.0, 8.0, 16.0, 4.0, 1.0, 4.0, 4.0, 1.0, 1.0, 1.0, 1.0, 4.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 4.0, 1.0, 1.0, 4.0, 8.0, 1.0, 1.0, 16.0, 16.0, 8.0, 1.0, 1.0, 2.0, 16.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 4.0, 2.0, 4.0, 2.0, 2.0, 1.0, 2.0, 1.0, 1.0, 2.0, 4.0, 1.0, 1.0, 1.0, 4.0, 1.0, 512.0, 長いので略 , 128.0, 1.0, 64.0, 1.0, 1.0, 1.0]
コインを投げる平均回数: 1.9905
μ(10000)=1.974132271
平均利得額: 6.5987
$
ここで、10000回シミュレーションをしたとき、
コインを投げる平均回数は1.9905になっているので、
μ(10000回のシミュレーションにおいて)=2^(1.9905-1)≒1.974132271で、
平均利得額6.5987とは大きな開きがある。
rの平均:(r[0]+r[1]+r[2]+r[3]+r[4]+...+r[9999])/10000=1.9905
rの平均は、(r1+r2+r2+...+rn)/nで表される。
回数rが全て2ならば、(∑(i=1,n){2^(2-1)})n=(∑(i=1,n){2})n=2である。
lの平均la=(l[0]+l[1]+l[2]+...+l[9999])/10000=6.5987 //シミュレーション
=(∑(i=1,n){l[i]})/n=(∑(i=1,n){2^(r[i]-1)})/nとする。
極限において、①の、l=μ、r=Sとすると、l=2^(r-1)である。
コンピュータ・シミュレーションによる解
10億回のゲームのシミュレーションを行った解をここに載せる。
プログラム
#!/usr/bin/python3
import os
import binascii
import random
from getkey import getkey,keys
N=1000000000
# N回ゲームを繰り返した場合の平均の算出
l=0
r=0
f=open("/dev/random",'rb') # /dev/randomを開く
# n回シミュレーションをした場合の結果のリストを作る
for i in range(N):
k=0
while(True):
k=k+1
n=f.read(1)
r1=binascii.hexlify(n) #16進の文字列に変換
r2=int(r1,16) # 整数に変換
if r2%2:
break
print(i,chr(13),end='',flush=True)
r+=k
l+=2**(k-1)
f.close() # /dev/randomを閉じる
# 平均を取る
a=l/N
b=r/N
print("シミュレーション回数:",N)
print("コインを投げる平均回数: ",b)
print("平均利得額: ",a)
実行結果
シミュレーション回数: 1000000000
コインを投げる平均回数: 2.000005233
平均利得額: 19.908359876