誕生日のパラドックス(たんじょうびのパラドックス)とは「何人集まればその中に同じ誕生日の人がいる確率が 50%を超えるか?」という問題から生じるパラドックスである。普通に考えれば365日の半分、だいたい180人前後と考えるが、答えは23人である。直感的な答えよりもずっと少なくはないだろうか。 誕生日のパラドックスは論理的な矛盾に基づいているという意味でのパラドックスではなく、結果が一般的な直感と反しているという意味でのパラドックスである。
誕生日のパラドックス - Wikipedia
何週か前の情報セキュリティの授業で,一方向ハッシュ関数を説明したときに,取り上げました.今見てみると,「2月29日は考えない」「誕生日は365日とも等確率」のほか,「双子は対象外」という仮定をおかないといけないのですね.
Rubyで計算を試みてみます.上記Wikipediaエントリの中で定義しているに対して,,,…を順に計算し*1,これが最初に1/2を下回ったところで,計算を打ち切ります.
$ ruby -e 'p=1.0;m=365;1.upto(m){|i|p=p*(m-i+1)/m;puts "#{i}:#{p}";if p<0.5;break end}'
1:1.0 2:0.9972602739726028 3:0.9917958341152185 4:0.9836440875334497 5:0.9728644263002063 6:0.9595375163508884 7:0.9437642969040244 8:0.9256647076483308 9:0.905376166110833 10:0.8830518222889221 11:0.8588586216782667 12:0.8329752111619353 13:0.8055897247675702 14:0.7768974879950266 15:0.7470986802363133 16:0.7163959947471498 17:0.6849923347034391 18:0.6530885821282105 19:0.6208814739684632 20:0.5885616164194198 21:0.5563116648347941 22:0.5243046923374498 23:0.49270276567601445
たしかに23人と出ました.
ちょっとワンライナーに手を加えてみます.というのも,pはFloatで,「p=p*(m-i+1)/m」の乗除算を繰り返していくうちに,誤差が蓄積する可能性があります.計算式は分数ですから,Rationalを使い,出力時にはto_fを差し込むことにします.
$ ruby -e 'p=Rational(1,1);m=365;1.upto(m){|i|p=p*(m-i+1)/m;puts "#{i}:#{p.to_f}";if p<0.5;break end}'
1:1.0 2:0.9972602739726028 3:0.9917958341152187 4:0.9836440875334497 5:0.9728644263002064 6:0.9595375163508885 7:0.9437642969040246 8:0.925664707648331 9:0.9053761661108333 10:0.8830518222889223 11:0.858858621678267 12:0.8329752111619356 13:0.8055897247675706 14:0.776897487995027 15:0.7470986802363135 16:0.7163959947471501 17:0.6849923347034393 18:0.6530885821282107 19:0.6208814739684633 20:0.5885616164194201 21:0.5563116648347942 22:0.5243046923374499 23:0.49270276567601456
23で計算を終えるのは変わりませんが,末尾の桁が先ほどのと少々,違っていました.
ところでRationalって組み込みクラスでしたっけ? リファレンスを引く前に,Ruby 1.8と1.9でワンライナーを動かしてみますか.上の2つのコマンドは,Ruby 1.9で実行しました.Ruby 1.8で動かすと
-e:1: undefined method `Rational' for main:Object (NoMethodError)
と出ました.じゃあ修正.
$ ruby -rrational -e 'p=Rational(1,1);m=365;1.upto(m){|i|p=p*(m-i+1)/m;puts "#{i}:#{p.to_f}";if p<0.5;break end}'
Ruby 1.8での結果は以下のとおり.
1:1.0 2:0.997260273972603 3:0.991795834115219 4:0.98364408753345 5:0.972864426300206 6:0.959537516350888 7:0.943764296904025 8:0.925664707648331 9:0.905376166110833 10:0.883051822288922 11:0.858858621678267 12:0.832975211161936 13:0.805589724767571 14:0.776897487995027 15:0.747098680236314 16:0.71639599474715 17:0.684992334703439 18:0.653088582128211 19:0.620881473968463 20:0.58856161641942 21:0.556311664834794 22:0.52430469233745 23:0.492702765676015
「-rrational」つきのワンライナーは,Ruby 1.9でもエラー・警告なく実行できて,出力は,なしのと同じでした.
といったところで,リファレンスも見ておきましょう.違っていましたね.
Ruby 1.8.7 リファレンスマニュアル>ライブラリ一覧
rational 有理数を扱うためのライブラリです。
Ruby 1.9.1 リファレンスマニュアル>組み込みライブラリ
class Rational 有理数を扱うクラスです。