[絶対に儲かる賭け?] サンクトペテルブルグのパラドックスを律儀に試す


「サンクトペテルブルグのパラドックス」は、現実的にはあまり儲からなそうな賭けの期待値が、計算上無限大に発散するとされる有名なパラドックスです。

パラドックスを知らない人のために賭けの要点を書いておくと、以下のようになります。

「コインを投げ続け、表が出たらゲーム終了。表が出たのが1回目なら1円獲得、2回目なら2円、3回目なら4円…というように、裏が1回出るたびにもらえる金額が倍になる。いくらの賭け金ならこの賭けに参加するべきか。」

儲け額の期待値Wは以下のように計算されます。1/2で1円、1/4で2円、となるので…
  W=\sum_{k=0}^{\infty}\left(2^{k-1}\frac{1}{2^k}\right) = \frac{1}{2}+\frac{1}{2}+\frac{1}{2}+\dots = \infty

ここまで見てだまされないぞと思った人は、しっかり悩んでみてください。

Coins

Taken by xJason.Rogersx, Flicker.

先日友人との間で話題になって、実際のところおおよそどんな具合で儲かるのかやってみようということでさくっと書いてみたものです。確率についてなんやかんやと議論するのも楽しいですが、ゴリ押しでデータを集めるのもまた面白いものがあります。あと探しても意外とそういう資料が見当たらなかったので。


ソースコード

いつもどおりC++です。C++11の機能を使っていますので、例えばgccとかでコンパイルしたい場合は -std=++11 とか -std=c++0x とかのオプションをつけてください。

#include <ctime>
#include <iostream>
#include <random>
#include <functional>

int main(int argc, char** argv){
  if(argc != 2){
    std::cerr << "Wrong argument!" << std::endl;
    return -1;
  }
  long long int loopNum = 1;
  for(int i = 0; i < atoi(argv[1]); i++){
    loopNum *= 2;
  }
  std::cout << "Loop: " << loopNum << std::endl;

  time_t timer;
  time(&timer);
  auto rand = std::bind(std::uniform_int_distribution(0,1),
      std::mt19937(static_cast<unsigned int>(timer)));
  long long int total = 0;
  for(long long int trial = 0; trial < loopNum; trial++){
    long long int earn = 1;
    while(rand()){
      earn*= 2;
    }
    total += earn;
  }
  std::cout << "Earned: "
    << static_cast<double>(total)/static_cast<double>(loopNum)
    << std::endl;
  return 0;
}

特記するようなものもありません。コマンドライン引数から2の何乗回計算するかを決めて、律儀に試行を繰り返して平均獲得金額を求めています。

カウントがlong long int型なので2の50乗回程度までは問題ないと思いますが、そのはるか手前の2の30乗前後(数億程度)で計算時間がきつくなってくると思います。
まあ乱数も毎回1ビットしか使っていないしシングルスレッドだしで、高速化する余地はまだ残っています。


結果

大量に試行した結果は以下のようになります。あくまで愚直に。力強く。

セントペテルスブルグの賭け

横が1セットあたりの試行回数、縦が1回あたりの平均獲得金額です。両方logスケールなのに注意。
(表が出るまでを1回の賭けとし、1セットでn回行うと定義しています。平均獲得金額は儲け額をnで割った値。)

不思議なグラフです。まず、回数を増やすと平均獲得金額は順調に上がっていくことがわかります。1,000,000,000回以上やるつもりなら、1回あたり10円以上儲かることがほぼ確実になります。このままグラフを右に伸ばしていったらどうなるでしょう。

もうひとつ面白いことがあって、それはばらつきが減らないことです。例えば右上にある点、だいたい10,000,000回で平均獲得金額が10,000円を超えていますが、つまりこの1セットで単純にトータル一千億円以上儲けているということです。とんでもない大当たりです。

胴元と挑戦者、どちらの席につきたいですか?


今回は横軸がlogスケールで均等になるようにサンプリングしています。離散的な値しかとらないので左側はすかすかに見えますが、実際は点が重なっているだけです。
また、左上から右下へのぼんやりとした斜線が大量に見られます。これは「1回大当たり」を成し遂げたときの線になっています。回数を増やすと同じ大当たりでも「1回あたりの獲得金額」は減っていくので右下がりになるという具合です。その代わり「もっとすごい大当たり」をひく確率も出てきます。

モンテカルロ法などでは試行回数を増やすと値が落ち着くのですが、この問題はおもしろいことにいくら試行回数を増やしてもばらつきが収まらないようになっています。よくできています。

儲け額の分散も出してみようと一度書きかけたのですが、ちょっと考えてからこの問題に対して無駄な試みであることがわかりました。

コンピュータはしばしば想像力を働かせる道具として役に立つのですが、今回のように神通力の効かないヤバそうな問題ではちょっとわけが違ってきます。こんな問題でも扱えてしまう数学の力は偉大です。

結果の意味とこの賭けの本当の期待値についてはいろいろ考えてみて下さい。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です