いきなりですが問題です.
成功確率が (ただし[tex:0
直感でこの期待値は,すなわち逆数になるのではないかと考えます.なら,期待値は2,すなわち平均的に見れば,2回で終了する,ということです.なら,期待値は10です.もちろん1回で終了するケースも,何十回やっても終わってくれないケースもあるでしょうが,「平均的に」見たときの回数を教えてくれるのが,期待値というものです.
この期待値を数式で表すと,
すなわち
になります.ここから式変形に奮闘しましたが,どうも思っていた解になってくれません.計算ミスだと思うthere must be an error in calculationのですが,どこか分からない….
ここでシミュレーションに頼ってみました.まずはRubyで,それからCで書きました*1.
/* * expectation.c * 独立試行で「1回成功すればそこで終了」の回数の期待値を * シミュレーションにより求める. */ #include <stdio.h> #include <stdlib.h> #include <time.h> /* 期待値を求める */ void calc_expectation(int pinv, int exec) { int i; double sum; /* 試行回数の和 */ /* 引数チェック(0除算をしないように) */ if (pinv == 0) { printf("p = infinity?\n"); return; } if (exec == 0) { printf("execution = 0\n"); return; } for (i = 1; i <= exec; i++) { double count = 1; /* 成功するまでの試行回数 */ for (count = 1; (unsigned long int)random() % pinv != 0; count++) { printf("."); } printf("! %d\n", (int)count); sum += count; } printf("\n"); printf("p = 1/%d\n", pinv); printf("execution = %d\n", exec); printf("expectation = %f\n", sum / exec); } int main(int argc, char *argv[]) { int pinv = 2; /* 独立試行の成功確率の逆数 */ int exec = 10000; /* 実行回数 */ if (argc >= 2) { pinv = atoi(argv[1]); } if (argc >= 3) { exec = atoi(argv[2]); } srandom(time(NULL)); calc_expectation(pinv, exec); return 0; }
#!/usr/bin/env ruby # expectation.rb # 独立試行で「1回成功すればそこで終了」の回数の期待値を # シミュレーションにより求める. class Expectation def initialize(pinv_ = 2, exec_ = 10000) @pinv = pinv_.to_i # 独立試行の成功確率の逆数 @exec = exec_.to_i # 実行回数 @verbose = true # シミュレーション状況を出力するならtrue end def try # 1回成功するまで独立試行を行い,その回数を返す. count = 0 while true count += 1 if rand(@pinv) == 0 puts "! #{count}" if @verbose return count end print "." if @verbose end end def start sum = 0 # 試行回数の和 1.upto(@exec) do sum += try end e = sum.to_f / @exec.to_f # 期待値 puts "" puts "p = 1/#{@pinv}" puts "execution = #{@exec}" puts "expectation = #{e}" end end if __FILE__ == $0 pinv = ARGV.shift || 2 # 独立試行の成功確率の逆数 exec = ARGV.shift || 10000 # 実行回数 Expectation.new(pinv, exec).start end
とることのできるコマンドライン引数は,どちらも同じです.最初の引数は,成功確率の逆数で,整数で与えるものとします.2番目の引数は,「成功するまでその試行を繰り返」すのを1回の実行として,何回実行するかで,これももちろ整数です.コマンドライン引数を書かずに実行したときの値,すなわちデフォルト値は,それぞれ2と10000です.
冒頭で挙げたとおり,ベルヌーイ試行での生起確率は0より大きく1未満の値ですが,ここでの入力ではその逆数をとり,プログラムではpinvという変数(「p inverse」の略です)に格納します.
「成功判定」は,CとRubyとで若干違います.Cでは,randomの戻り値はlong int型の整数値なので,pinvで割ってその余りが0なら*2,成功としました.負の数を割らないよう,unsignedつきのキャストもしています.一方Rubyでは,「rand(@pinv)」と書けば,0以上@pinv未満の整数を返してくれるので,単純にその値を0と比較し,等しいなら成功としました.
さて実行.期待値はpinvになってくれるといいのですが,回数が多くして実行すると,確かにpinv,すなわち生起確率の逆数に近づいています.
…と,プログラミングに時間を費やしてから,計算していたメモに目をやると,間違いに気付き,無事にという結果に至りました.
ところでなぜこんな問題を考えたのかというと,以前に
1024ビットの乱数で,1のビットがちょうど512個になる確率は,40分の1程度.思っていたより高いなあというのが,率直なところです.
半分ビットの確率を求めるRubyスクリプト - わさっき
と書いたのですが,1024ビットの乱数を生成して,1のビットがちょうど512個になるまで生成するとしたとき,生成回数の期待値を確認したかったからでした.