0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

python3を使った、サンクトペテルブルグのパラドックスの一考察

Last updated at Posted at 2023-01-17

コインを表が出るまで投げ続け、投げた回数を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とする

ev0.py
#!/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億回のゲームのシミュレーションを行った解をここに載せる。

プログラム

ev.py
#!/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
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?