(Дещо) Парадоксальний день народження


20

Фон

Парадокс дня народження є популярною проблемою в теорії ймовірностей, кидає виклик ( у більшості людей) математична інтуїція. Постановка проблеми:

Враховуючи N людей, яка ймовірність того, що принаймні двоє з них мають один і той же день народження (не зважаючи на рік).

Проблему зазвичай спрощують цілком ігноруючи високосні дні. У цьому випадку відповідь для N = 23 - це P (23) ≈ 0,5072972 (як загальний приклад). Зв'язана стаття Вікіпедії пояснює, як досягти такої ймовірності. Крім того, це відео номер Numberphile робить дуже гарну роботу.

Однак для цього завдання ми хочемо зробити це правильно і не ігнорувати високосні роки. Це трохи складніше, адже зараз потрібно додати 29 лютого, але саме цей день народження є менш імовірним, ніж усі інші.

Ми також будемо використовувати правила повного високосного року :

  • Якщо рік ділиться на 400, це високосний рік.
  • Інакше, якщо рік ділиться на 100, це не високосний рік.
  • Інше, якщо рік ділиться на 4 - це високосний рік.
  • Інше, це не високосний рік.

Плутати? Це означає, що роки 1700, 1800, 1900, 2100, 2200, 2300 не є високосними, але 1600, 2000, 2400 є (як і будь-який інший рік, що ділиться на 4). Цей календар повторюється кожні 400 років, і ми будемо вважати рівномірний розподіл днів народження протягом цих 400 років.

Коригуваний результат для N = 23 зараз P (23) ≈ 0,5068761 .

Змагання

Враховуючи ціле число 1 ≤ N < 100, визначте ймовірність того, що серед Nлюдей принаймні двоє мають той самий день народження, враховуючи правила високосного року. Результатом має бути число з плаваючою комою або фіксованою точкою, що має бути не менше 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 через округлення. Ймовірність не досягне рівно 1,0 до P (367) .)


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)), а потім приймає добуток списку. Також застосовуються константи 366 і -755 замість 365 і .2425.


Стара версія:

Pyth, 34 байти

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

Є два можливі способи, щоб не було пари людей з одним і тим же днем ​​народження: у кожного день народження різний, і ніхто не має день народження 29 лютого, а у когось день народження 29-го, а у всіх інших - різні дні народження в звичайні дні.

Ймовірність виникнення першої (365 * 364 * ... 365 - n + 1) / (365.2425 ^ n).

Імовірність появи другого (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).

Це ймовірність відсутності пар, тому ймовірність принаймні однієї пари - це мінус вище вказаного числа.

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)дає результат. Змініть, .2425щоб fractions.Fraction(97,400)отримати точний результат.


Вам не потрібно пробіл між 2і and.
isaacg

Ви можете не ставити в 1/протягом gі розділити на ній замість цього?
xnor

@xnor Так, з часом ці речі втрачаються :) Те, що колись було оптимізацією, згодом стає неоптимальним.
orlp

ви можете ввести e=365та замінити 365 на e та 367 на e + 2
Віллем

@willem Це не коротше.
orlp

2

Python 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на дріб.

Тестуйте тут

Використовується та ж техніка, що і тут , але з модифікованими константами.


Вам не потрібно пробіл між 2і and.
isaacg

Я подумав, що це 98 (хоча, можливо, я зненацька помилка розрахунку ...)
Тім

1

80386 код машини, 43 байти

Шестнадцятковий код:

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 \ limit_ {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;
}

Код влаштований таким чином, що він вимагає мінімальної кількості констант - лише дві ( 400 / dі 303 / d). Я використовую floatтип для їх представлення, оскільки він займає менше місця (4 байти на константу). Крім того, я не хотів помножуватися const2на k - 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.