(Một chút) Nghịch lý sinh nhật Pedantic


20

Lý lịch

Các nghịch lý ngày sinh nhật là một vấn đề phổ biến trong lý thuyết xác suất mà bất chấp trực giác toán học (hầu hết mọi người). Báo cáo vấn đề là:

Với N người, xác suất ít nhất hai người trong số họ có cùng ngày sinh (không tính đến năm).

Vấn đề thường được đơn giản hóa bằng cách bỏ qua những ngày nhuận hoàn toàn. Trong trường hợp này, câu trả lời cho N = 23P (23) ≈ 0,5072972 (như một ví dụ phổ biến). Bài viết Wikipedia được liên kết giải thích làm thế nào để đi đến xác suất này. Ngoài ra, video Numberphile này làm rất tốt.

Tuy nhiên, đối với thử thách này, chúng tôi muốn thực hiện đúng và không bỏ qua năm nhuận. Điều này hơi phức tạp hơn một chút, vì bây giờ ngày 29 tháng 2 cần phải được thêm vào, nhưng sinh nhật đặc biệt này ít có khả năng hơn tất cả những người khác.

Chúng tôi cũng sẽ sử dụng quy tắc năm nhuận đầy đủ :

  • Nếu một năm chia hết cho 400 thì đó là một năm nhuận.
  • Khác, nếu một năm chia hết cho 100 thì đó không phải là năm nhuận.
  • Khác, nếu một năm chia hết cho 4 thì đó là một năm nhuận.
  • Khác, đó không phải là một năm nhuận.

Bối rối? Điều đó có nghĩa là các năm 1700, 1800, 1900, 2100, 2200, 2300 không phải là năm nhuận, nhưng 1600, 2000, 2400 là (cũng như mọi năm khác chia hết cho 4). Lịch này lặp lại sau mỗi 400 năm, và chúng tôi sẽ giả định phân phối đồng đều các ngày sinh trong 400 năm đó.

Kết quả đã sửa cho N = 23 bây giờ là P (23) ≈ 0,5068761 .

Các thách thức

Cho một số nguyên 1 ≤ N < 100, xác định xác suất trong số Nít nhất hai người có cùng ngày sinh theo các quy tắc năm nhuận. Kết quả phải là số dấu phẩy động hoặc điểm cố định, chính xác đến ít nhất 6 chữ số thập phân. Có thể chấp nhận cắt các số 0 ở cuối.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả thông qua STDOUT (hoặc thay thế gần nhất), tham số trả về hàm hoặc tham số hàm (out).

Giải pháp của bạn phải có khả năng tạo đầu ra cho tất cả 99 đầu vào trong vài giây. Điều này chủ yếu để loại trừ các phương pháp Monte Carlo với hàng tấn mẫu, vì vậy nếu bạn đang sử dụng thuật toán chính xác và nhanh bằng ngôn ngữ bí truyền quá chậm, tôi sẵn sàng bỏ qua quy tắc này.

Các trường hợp thử nghiệm

Dưới đây là bảng kết quả đầy đủ:

 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

(Tất nhiên, P (99) chỉ là 1.0 do làm tròn. Xác suất sẽ không đạt chính xác 1.0 cho đến khi P (367) .)


7
1. Nếu bạn sẽ trở thành người phạm tội thì bạn nên tính đến việc sinh nhật không được phân phối đồng đều trong suốt cả năm. 2. Sự liên quan chính xác của các quy tắc năm nhuận phụ thuộc vào những giả định được thực hiện về tuổi thọ của con người. Là ý tưởng để khấu hao trong toàn bộ chu kỳ 400 năm?
Peter Taylor

1
@PeterTaylor Có, giả sử phân phối đồng đều trong toàn bộ chu kỳ 400 năm. Tôi chưa bao giờ nói bộ N người còn sống cùng một lúc. ;)
Martin Ender

Câu trả lời:


6

Bình thường, 31 34 byte

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

Trình diễn , thử nghiệm khai thác

Điều này hoạt động tương tự như phiên bản cũ, ngoại trừ thay vì tạo riêng biệt giá trị (366 + n * (.2425 - 1)) và nhân nó lên, nó bắt đầu bằng cách tạo một danh sách kéo dài từ 366 đến 365 - n + 2, sau đó sửa đổi 365 tại chỗ để trở thành (366 + n * (.2425 - 1)), sau đó lấy sản phẩm của danh sách. Ngoài ra, các hằng số 366 và -7575 được sử dụng thay vì 365 và 0,2425.


Phiên bản cũ:

Bình thường, 34 byte

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

Có hai cách có thể để không có cặp người nào có cùng ngày sinh: mọi người có ngày sinh nhật khác nhau và không ai có sinh nhật vào ngày 29 tháng 2 và ai đó có sinh nhật vào ngày 29 và mọi người khác có ngày khác sinh nhật vào những ngày bình thường.

Xác suất xảy ra lần đầu tiên là (365 * 364 * ... 365 - n + 1) / (365.2425 ^ n).

Xác suất xảy ra lần thứ hai là (365 * 364 * ... 365 - n + 2) * .2425 * n / (365.2425 ^ n)

Chúng có thể được viết cùng nhau dưới dạng (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).

Đây là xác suất không có cặp nào, vì vậy xác suất có ít nhất một cặp là một trừ đi số trên.

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

5

Con trăn, 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)đưa ra kết quả. Thay đổi .2425để fractions.Fraction(97,400)có được một kết quả chính xác.


Bạn không cần một không gian giữa 2and.
isaacg

Bạn không thể đưa vào 1/cho gvà chia cho nó để thay thế?
xnor

@xnor Yep, theo thời gian những thứ này bị mất :) Điều gì đã từng là tối ưu hóa trở thành tối ưu sau này.
orlp

bạn có thể giới thiệu e=365và thay thế 365 bằng e và 367 bằng e + 2
Willem

@willem Điều đó không ngắn hơn.
orlp

2

Python 155 153 151 142 140 byte

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)

Gọi a(n)cho kết quả. Để có kết quả chính xác, bọc dtrong một phần nhỏ.

Kiểm tra tại đây

Sử dụng kỹ thuật tương tự như ở đây , nhưng với hằng số sửa đổi.


Bạn không cần một không gian giữa 2and.
isaacg

Tôi nghĩ rằng đó là 98 (mặc dù tôi có thể mắc một lỗi tính toán ...)
Tim

1

Mã máy 80386, 43 byte

Mã thập phân của mã:

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

Tôi bắt đầu từ công thức sau (cho xác suất bổ sung):

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

(đây d = 366 * 400 - 303là số ngày trong 400 năm)

Đây là mã c ++ thực hiện nó (nó đã được tối ưu hóa một chút):

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;
}

Mã được sắp xếp để nó yêu cầu số lượng hằng số tối thiểu - chỉ có hai ( 400 / d303 / d). Tôi sử dụng floatkiểu để biểu diễn chúng vì nó chiếm ít không gian hơn (4 byte cho mỗi hằng số). Ngoài ra, tôi không muốn nhân const2bằng k - 1(vì đó sẽ yêu cầu chuyển đổi k - 1để float); const2thay vào đó, mã sẽ trừ đi.

Dưới đây là danh sách ngôn ngữ lắp ráp:

    ; // 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.