(やや)dan病な誕生日のパラドックス


20

バックグラウンド

誕生日のパラドックスは、(ほとんどの人々の)数学的な直感を覆す確率論で人気のある問題です。問題のステートメントは次のとおりです。

与えられたNの人々 、それらの少なくとも2つが同じ誕生日(年を無視)を持っている確率は何ですか。

この問題は通常、うるう日を完全に無視することで簡素化されます。この場合、N = 23の答えは一般的な例として)P(23)≈0.5072972です。リンクされたウィキペディアの記事は、この確率に到達する方法を説明しています。あるいは、このNumberphileビデオは本当に良い仕事をします。

ただし、この課題に対しては、正しく実行したいので、うるう年を無視しないください。2月29日を追加する必要があるため、これはやや複雑ですが、この特定の誕生日は他のすべての誕生日よりも少ない可能性があります。

また、完全なうるう年のルールを使用します。

  • 年が400で割り切れる場合は、うるう年です。
  • それ以外の場合、1年が100で割り切れる場合、うるう年ではありません。
  • それ以外の場合、1年が4で割り切れる場合はうるう年です。
  • そうでなければ、it年ではありません。

混乱した?つまり、1700年、1800年、1900年、2100年、2200年、2300年はうるう年ではなく、1600年、2000年、2400年は(4で割り切れる他の年と同様)です。このカレンダーは400年ごとに繰り返され、これらの400年にわたる誕生日の均一な分布を想定します。

N = 23の修正結果は、現在P(23)≈0.5068761です。

チャレンジ

整数1 ≤ N < 100を指定するNと、うるう年の規則を考慮して、少なくとも2人の人が同じ誕生日を持っている確率を決定します。結果は、小数点以下6桁までの精度の浮動小数点数または固定小数点数でなければなりません。末尾のゼロを切り捨てることは許容されます。

プログラムまたは関数を作成し、STDIN(または最も近い代替)、コマンドライン引数または関数引数を介して入力を取得し、STDOUT(または最も近い代替)、関数の戻り値または関数(out)パラメーターを介して結果を出力できます。

ソリューションは、わずか数秒で99の入力すべてに対して出力を生成できる必要があります。これは主に、大量のサンプルを使用するモンテカルロ法を除外するためです。したがって、非常に遅い難解な言語で主に高速で正確なアルゴリズムを使用している場合は、この規則に余裕を持たせます。

テストケース

結果の全表は次のとおりです。

 1 => 0.000000
 2 => 0.002737
 3 => 0.008195
 4 => 0.016337
 5 => 0.027104
 6 => 0.040416
 7 => 0.056171
 8 => 0.074251
 9 => 0.094518
10 => 0.116818
11 => 0.140987
12 => 0.166844
13 => 0.194203
14 => 0.222869
15 => 0.252642
16 => 0.283319
17 => 0.314698
18 => 0.346578
19 => 0.378764
20 => 0.411063
21 => 0.443296
22 => 0.475287
23 => 0.506876
24 => 0.537913
25 => 0.568260
26 => 0.597796
27 => 0.626412
28 => 0.654014
29 => 0.680524
30 => 0.705877
31 => 0.730022
32 => 0.752924
33 => 0.774560
34 => 0.794917
35 => 0.813998
36 => 0.831812
37 => 0.848381
38 => 0.863732
39 => 0.877901
40 => 0.890932
41 => 0.902870
42 => 0.913767
43 => 0.923678
44 => 0.932658
45 => 0.940766
46 => 0.948060
47 => 0.954598
48 => 0.960437
49 => 0.965634
50 => 0.970242
51 => 0.974313
52 => 0.977898
53 => 0.981043
54 => 0.983792
55 => 0.986187
56 => 0.988266
57 => 0.990064
58 => 0.991614
59 => 0.992945
60 => 0.994084
61 => 0.995055
62 => 0.995880
63 => 0.996579
64 => 0.997169
65 => 0.997665
66 => 0.998080
67 => 0.998427
68 => 0.998715
69 => 0.998954
70 => 0.999152
71 => 0.999314
72 => 0.999447
73 => 0.999556
74 => 0.999645
75 => 0.999717
76 => 0.999775
77 => 0.999822
78 => 0.999859
79 => 0.999889
80 => 0.999913
81 => 0.999932
82 => 0.999947
83 => 0.999959
84 => 0.999968
85 => 0.999976
86 => 0.999981
87 => 0.999986
88 => 0.999989
89 => 0.999992
90 => 0.999994
91 => 0.999995
92 => 0.999996
93 => 0.999997
94 => 0.999998
95 => 0.999999
96 => 0.999999
97 => 0.999999
98 => 0.999999
99 => 1.000000

(もちろん、丸めのためにP(99)1.0のみです。確率はP(367)まで正確に1.0に達しません。)


7
1.意欲的になりたい場合は、誕生日が年間を通じて均一に分配されないことを考慮する必要があります。2.うるう年の規則の正確な関連性は、人間の寿命についてどのような仮定がなされるかに依存します。400年のサイクル全体で償却するという考えはありますか?
ピーターテイラー

1
@PeterTaylorはい、400年のサイクル全体で均一に分布すると仮定します。N人のセットが同時に生きているとは言いませんでした。;)
マーティン・エンダー

回答:


6

Pyth、31 34バイト

Jt.2425K366-1c.xX0rK-KQ*JQ^+KJQ

デモンストレーションテストハーネス

これは古いバージョンと同様に機能しますが、(366 + n *(.2425-1))値を個別に生成して乗算する代わりに、366から365-n + 2に及ぶリストを生成することを除きます。次に、366を変更して(366 + n *(.2425-1))になり、リストの積を取得します。また、365と.2425の代わりに、定数366と-.7575が使用されます。


古いバージョン:

Pyth、34バイト

J.2425K365-1c*+hK*QtJ.xrK-hKQ^+KJQ

同じ誕生日の人がいないペアを作成するには、2つの方法があります。全員が異なる誕生日を持ち、2月29日には誰も誕生日を持たず、29日には誰かが誕生日を持ち、他の人は異なる誕生日を持ちます。通常の誕生日。

最初に発生する確率は(365 * 364 * ... 365-n + 1)/(365.2425 ^ n)です。

2回目に発生する確率は(365 * 364 * ... 365-n + 2)* .2425 * n /(365.2425 ^ n)

これらは、(365 * 364 * ... 365-n + 2)*(365-n + 1 + .2425 * n)/(365.2425 ^ n)=(365 * 364 * ... 365- n + 2)*(365 + 1 +(.2425-1)* n)/(365.2425 ^ n)。

これはペアがない確率であるため、少なくとも1つのペアの確率は1から上記の数を引いたものです。

J = .2425
K = 365
.xrK-hKQ = (365 * 364 * ... 365 - n + 2)
+hK*QtJ = (365 + 1 + n * (.2425 - 1))
^+KJQ = (365.2425 ^ n)

5

パイソン、179 178 144 143 140 136 135 133

f=.2425
g=365+f
a=lambda n:(n and(365-n)*a(n-1)or 365)/g
b=lambda n:(n<2and f or(367-n)*b(n-1)+a(n-2)*f)/g
p=lambda n:1-a(n-1)-b(n)

p(n)結果を与えます。に変更.2425fractions.Fraction(97,400)て正確な結果を取得します。


2との間にスペースは必要ありませんand
isaacg

あなたは入れることができない1/ためg、分裂代わりにそれで?
xnor

@xnorうん、時間の経過とともにこれらの事柄は失われます:)かつて最適化だったものは、その後最適ではなくなります。
orlp

あなたが導入する可能性e=365や電子によって電子による365および367を置き換える+ 2
ウィレム

@willemそれは短くはありません。
orlp

2

パイソン155 153 151 142 140バイト

d=146097
b=d/400
c=97/d
e=lambda n:n<2and 1-97/d or e(n-1)*(366-n)/b
f=lambda n:n<2and c or f(n-1)*(367-n)/b+e(n-1)*c
a=lambda n:1-e(n)-f(n)

コールa(n)の結果について。正確な結果を得るにdは、小数で折り返します。

ここでテスト

hereと同じ手法を使用しますが、定数を変更します。


2との間にスペースは必要ありませんand
isaacg

私はそれが98であると思った(私は計算ミスを怒っているかもしれないが...)
ティム

1

80386マシンコード、43バイト

コードのHexdump:

68 75 6e 33 3b 68 5a eb 07 3b 8b c4 49 d9 e8 d9
e8 d8 00 d9 e8 d9 40 04 de ea d8 c9 d9 00 de eb
e2 f3 d8 ca d9 e8 d8 e1 58 58 c3

私は次の式から始めました(補完的な確率のため):

\ prod \ limits_ {i = 0} ^ {k-2}(1- \ frac {97 + 400 * i} {d})*(1- \ frac {303 *(k-1)} {d})

(ここd = 366 * 400 - 303は400年の日数です)

以下に、それを実装するc ++コードを示します(すでに最適化されています)。

double it_opt(int k)
{
    double d = 366 * 400 - 303; // number of days in 400 years
    double result = 1; // probability of no coincidences
    const float const1 = float(400 / d);
    const float const2 = float(303 / d);
    double v1 = 1 + const2;
    double v2 = 1;

    for (int i = 0; i < k - 1; ++i)
    {
        v1 -= const1;
        result *= v1;
        v2 -= const2;
    }
    result *= v2;
    return 1 - result;
}

コードは、最小限の定数を必要とするように配置されています-2つのみ(400 / dおよび303 / d)。使用するfloatスペースが少ないため(定数あたり4バイト)、タイプを使用してそれらを表します。さらに、乗算する必要はありませんでしconst2k - 1(そのためにはに変換k - 1する必要がありますfloat)。コードconst2は代わりに繰り返し減算します。

アセンブリ言語のリストは次のとおりです。

    ; // fastcall convention - parameter k is in ecx
    ; // result must be returned in st
    push dword ptr 0x3b336e75; // const1 = [esp + 4]
    push dword ptr 0x3b07eb5a; // const2 = [esp]
    mov eax, esp;              // use [eax] instead of [esp] - 1 byte less
    dec ecx;                   // calculate k - 1
    fld1;                      // initiaze result = 1
    fld1;                      // initialize v1
    fadd [eax];
    fld1;                      // initialilze v2
myloop:
    fld dword ptr [eax + 4];
    fsubp st(2), st;            // update v1
    fmul st, st(1);             // update result
    fld dword ptr [eax];
    fsubp st(3), st;            // update v2
    loop myloop;                // loop
    fmul st, st(2);             // update result by v2
    fld1;
    fsub st, st(1);             // complement result
    pop eax;                    // restore stack
    pop eax;                    // restore stack
    ret;                        // return
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.