Skip to content

Commit 02e8869

Browse files
Add baffling-birthdays
1 parent 4970454 commit 02e8869

13 files changed

Lines changed: 3700 additions & 0 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,14 @@
453453
"prerequisites": [],
454454
"difficulty": 5
455455
},
456+
{
457+
"slug": "baffling-birthdays",
458+
"name": "Baffling Birthdays",
459+
"uuid": "07082d28-7689-4c2b-a613-3087031a4b39",
460+
"practices": [],
461+
"prerequisites": [],
462+
"difficulty": 6
463+
},
456464
{
457465
"slug": "knapsack",
458466
"name": "Knapsack",
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Instructions
2+
3+
Your task is to estimate the birthday paradox's probabilities.
4+
5+
To do this, you need to:
6+
7+
- Generate random birthdates.
8+
- Check if a collection of randomly generated birthdates contains at least two with the same birthday.
9+
- Estimate the probability that at least two people in a group share the same birthday for different group sizes.
10+
11+
~~~~exercism/note
12+
A birthdate includes the full date of birth (year, month, and day), whereas a birthday refers only to the month and day, which repeat each year.
13+
Two birthdates with the same month and day correspond to the same birthday.
14+
~~~~
15+
16+
~~~~exercism/caution
17+
The birthday paradox assumes that:
18+
19+
- There are 365 possible birthdays (no leap years).
20+
- Each birthday is equally likely (uniform distribution).
21+
22+
Your implementation must follow these assumptions.
23+
~~~~
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Introduction
2+
3+
Fresh out of college, you're throwing a huge party to celebrate with friends and family.
4+
Over 70 people have shown up, including your mildly eccentric Uncle Ted.
5+
6+
In one of his usual antics, he bets you £100 that at least two people in the room share the same birthday.
7+
That sounds ridiculous — there are many more possible birthdays than there are guests, so you confidently accept.
8+
9+
To your astonishment, after collecting the birthdays of just 32 guests, you've already found two guests that share the same birthday.
10+
Accepting your loss, you hand Uncle Ted his £100, but something feels off.
11+
12+
The next day, curiosity gets the better of you.
13+
A quick web search leads you to the [birthday paradox][birthday-problem], which reveals that with just 23 people, the probability of a shared birthday exceeds 50%.
14+
15+
Ah. So _that's_ why Uncle Ted was so confident.
16+
17+
Determined to turn the tables, you start looking up other paradoxes; next time, _you'll_ be the one making the bets.
18+
19+
~~~~exercism/note
20+
The birthday paradox is a [veridical paradox][veridical-paradox]: even though it feels wrong, it is actually true.
21+
22+
[veridical-paradox]: https://en.wikipedia.org/wiki/Paradox#Quine's_classification
23+
~~~~
24+
25+
[birthday-problem]: https://en.wikipedia.org/wiki/Birthday_problem
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"baffling_birthdays.s"
8+
],
9+
"test": [
10+
"baffling_birthdays_test.c"
11+
],
12+
"example": [
13+
".meta/example.s"
14+
]
15+
},
16+
"blurb": "Estimate the birthday paradox's probabilities.",
17+
"source": "Erik Schierboom",
18+
"source_url": "https://github.com/exercism/problem-specifications/pull/2539"
19+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
.text
2+
.globl shared_birthday
3+
.globl estimate
4+
5+
/* extern bool shared_birthday(const char **birthdates); */
6+
shared_birthday:
7+
stp xzr, xzr, [sp, #-64]! /* 32 halfwords on stack */
8+
stp xzr, xzr, [sp, #16]
9+
stp xzr, xzr, [sp, #32]
10+
stp xzr, xzr, [sp, #48]
11+
12+
mov x2, x0
13+
mov x0, xzr
14+
mov w1, #1
15+
mov w10, #10
16+
mov w15, 528 /* 11 * '0' */
17+
18+
.birthdate:
19+
ldr x9, [x2], #8
20+
cbz x9, .return
21+
22+
ldrb w11, [x9, #8]
23+
ldrb w13, [x9, #9]
24+
madd w13, w10, w11, w13
25+
sub w13, w13, w15 /* day 1..31 */
26+
lsl w13, w13, #1
27+
28+
ldrb w11, [x9, #5]
29+
ldrb w12, [x9, #6]
30+
madd w12, w10, w11, w12
31+
sub w12, w12, w15 /* month 1..12 */
32+
lsl w12, w1, w12 /* 1 << month */
33+
34+
ldrh w11, [sp, x13]
35+
orr w12, w11, w12
36+
strh w12, [sp, x13]
37+
cmp w11, w12
38+
bne .birthdate
39+
40+
mov x0, #1
41+
42+
.return:
43+
add sp, sp, #64
44+
ret
45+
46+
/* extern double estimate(int group_size); */
47+
estimate:
48+
mov w9, #1
49+
mov w10, #100
50+
mov w11, #365
51+
scvtf d0, w9 /* probability of no shared birthday */
52+
scvtf d1, w9
53+
scvtf d2, w11 /* descending numerator */
54+
scvtf d3, w11 /* constant denominator */
55+
scvtf d4, w10
56+
57+
cbz w0, .complement
58+
59+
.multiply:
60+
fmul d0, d0, d2 /* multiply by 365, 364, 363, ... */
61+
fdiv d0, d0, d3 /* divide by 365 */
62+
fsub d2, d2, d1
63+
add w0, w0, #-1 /* number of remaining birthdates */
64+
cbnz w0, .multiply
65+
66+
.complement:
67+
fsub d0, d1, d0 /* probability of shared birthday */
68+
fmul d0, d0, d4 /* convert to percentage */
69+
ret
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[716dcc2b-8fe4-4fc9-8c48-cbe70d8e6b67]
13+
description = "shared birthday -> one birthdate"
14+
15+
[f7b3eb26-bcfc-4c1e-a2de-af07afc33f45]
16+
description = "shared birthday -> two birthdates with same year, month, and day"
17+
18+
[7193409a-6e16-4bcb-b4cc-9ffe55f79b25]
19+
description = "shared birthday -> two birthdates with same year and month, but different day"
20+
21+
[d04db648-121b-4b72-93e8-d7d2dced4495]
22+
description = "shared birthday -> two birthdates with same month and day, but different year"
23+
24+
[3c8bd0f0-14c6-4d4c-975a-4c636bfdc233]
25+
description = "shared birthday -> two birthdates with same year, but different month and day"
26+
27+
[df5daba6-0879-4480-883c-e855c99cdaa3]
28+
description = "shared birthday -> two birthdates with different year, month, and day"
29+
30+
[0c17b220-cbb9-4bd7-872f-373044c7b406]
31+
description = "shared birthday -> multiple birthdates without shared birthday"
32+
33+
[966d6b0b-5c0a-4b8c-bc2d-64939ada49f8]
34+
description = "shared birthday -> multiple birthdates with one shared birthday"
35+
36+
[b7937d28-403b-4500-acce-4d9fe3a9620d]
37+
description = "shared birthday -> multiple birthdates with more than one shared birthday"
38+
39+
[70b38cea-d234-4697-b146-7d130cd4ee12]
40+
description = "random birthdates -> generate requested number of birthdates"
41+
include = false
42+
43+
[d9d5b7d3-5fea-4752-b9c1-3fcd176d1b03]
44+
description = "random birthdates -> years are not leap years"
45+
include = false
46+
47+
[d1074327-f68c-4c8a-b0ff-e3730d0f0521]
48+
description = "random birthdates -> months are random"
49+
include = false
50+
51+
[7df706b3-c3f5-471d-9563-23a4d0577940]
52+
description = "random birthdates -> days are random"
53+
include = false
54+
55+
[89a462a4-4265-4912-9506-fb027913f221]
56+
description = "estimated probability of at least one shared birthday -> for one person"
57+
58+
[ec31c787-0ebb-4548-970c-5dcb4eadfb5f]
59+
description = "estimated probability of at least one shared birthday -> among ten people"
60+
61+
[b548afac-a451-46a3-9bb0-cb1f60c48e2f]
62+
description = "estimated probability of at least one shared birthday -> among twenty-three people"
63+
64+
[e43e6b9d-d77b-4f6c-a960-0fc0129a0bc5]
65+
description = "estimated probability of at least one shared birthday -> among seventy people"
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
ifeq ($(origin AS),default)
2+
AS = aarch64-linux-gnu-as
3+
endif
4+
ifeq ($(origin CC),default)
5+
CC = aarch64-linux-gnu-gcc
6+
endif
7+
8+
CFLAGS ?= -g -Wall -Wextra -pedantic -Werror
9+
LDFLAGS =
10+
11+
ALL_LDFLAGS = -pie -Wl,--fatal-warnings
12+
13+
ALL_CFLAGS = -std=c99 -fPIE $(CFLAGS)
14+
ALL_LDFLAGS += $(LDFLAGS)
15+
16+
C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
17+
AS_OBJS = $(patsubst %.s,%.o,$(wildcard *.s))
18+
ALL_OBJS = $(filter-out example.o,$(C_OBJS) $(AS_OBJS) vendor/unity.o)
19+
20+
CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $<
21+
22+
PLATFORM = $(shell uname -m)
23+
ifeq ($(PLATFORM),aarch64)
24+
MAYBE_QEMU =
25+
else
26+
MAYBE_QEMU = qemu-aarch64 -L /usr/aarch64-linux-gnu
27+
endif
28+
29+
all: tests
30+
@$(MAYBE_QEMU) ./$<
31+
32+
tests: $(ALL_OBJS)
33+
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS)
34+
35+
%.o: %.s
36+
@$(AS) -o $@ $<
37+
38+
%.o: %.c
39+
@$(CC_CMD)
40+
41+
vendor/unity.o: vendor/unity.c vendor/unity.h vendor/unity_internals.h
42+
@$(CC_CMD)
43+
44+
clean:
45+
@rm -f *.o vendor/*.o tests
46+
47+
.PHONY: all clean
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.text
2+
.globl shared_birthday
3+
.globl estimate
4+
5+
shared_birthday:
6+
ret
7+
8+
estimate:
9+
ret
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include "vendor/unity.h"
2+
3+
#include <stddef.h>
4+
#include <stdbool.h>
5+
6+
extern bool shared_birthday(const char **birthdates);
7+
8+
// estimated probability of shared birthday
9+
extern double estimate(int group_size);
10+
11+
void setUp(void) {
12+
}
13+
14+
void tearDown(void) {
15+
}
16+
17+
void test_one_birthdate(void) {
18+
const char *birthdates[] = {"2000-01-01", NULL};
19+
TEST_ASSERT_FALSE(shared_birthday(birthdates));
20+
}
21+
22+
void test_two_birthdates_with_same_year_month_and_day(void) {
23+
TEST_IGNORE();
24+
const char *birthdates[] = {"2000-01-01", "2000-01-01", NULL};
25+
TEST_ASSERT_TRUE(shared_birthday(birthdates));
26+
}
27+
28+
void test_two_birthdates_with_same_year_and_month_but_different_day(void) {
29+
TEST_IGNORE();
30+
const char *birthdates[] = {"2012-05-09", "2012-05-17", NULL};
31+
TEST_ASSERT_FALSE(shared_birthday(birthdates));
32+
}
33+
34+
void test_two_birthdates_with_same_month_and_day_but_different_year(void) {
35+
TEST_IGNORE();
36+
const char *birthdates[] = {"1999-10-23", "1988-10-23", NULL};
37+
TEST_ASSERT_TRUE(shared_birthday(birthdates));
38+
}
39+
40+
void test_two_birthdates_with_same_year_but_different_month_and_day(void) {
41+
TEST_IGNORE();
42+
const char *birthdates[] = {"2007-12-19", "2007-04-27", NULL};
43+
TEST_ASSERT_FALSE(shared_birthday(birthdates));
44+
}
45+
46+
void test_two_birthdates_with_different_year_month_and_day(void) {
47+
TEST_IGNORE();
48+
const char *birthdates[] = {"1997-08-04", "1963-11-23", NULL};
49+
TEST_ASSERT_FALSE(shared_birthday(birthdates));
50+
}
51+
52+
void test_multiple_birthdates_without_shared_birthday(void) {
53+
TEST_IGNORE();
54+
const char *birthdates[] = {"1966-07-29", "1977-02-12", "2001-12-25", "1980-11-10", NULL};
55+
TEST_ASSERT_FALSE(shared_birthday(birthdates));
56+
}
57+
58+
void test_multiple_birthdates_with_one_shared_birthday(void) {
59+
TEST_IGNORE();
60+
const char *birthdates[] = {"1966-07-29", "1977-02-12", "2001-07-29", "1980-11-10", NULL};
61+
TEST_ASSERT_TRUE(shared_birthday(birthdates));
62+
}
63+
64+
void test_multiple_birthdates_with_more_than_one_shared_birthday(void) {
65+
TEST_IGNORE();
66+
const char *birthdates[] = {"1966-07-29", "1977-02-12", "2001-12-25", "1980-07-29", "2019-02-12", NULL};
67+
TEST_ASSERT_TRUE(shared_birthday(birthdates));
68+
}
69+
70+
void test_for_one_person(void) {
71+
TEST_IGNORE();
72+
TEST_ASSERT_FLOAT_WITHIN(0.05, 0.0, estimate(1));
73+
}
74+
75+
void test_among_ten_people(void) {
76+
TEST_IGNORE();
77+
TEST_ASSERT_FLOAT_WITHIN(0.05, 11.694818, estimate(10));
78+
}
79+
80+
void test_among_twentythree_people(void) {
81+
TEST_IGNORE();
82+
TEST_ASSERT_FLOAT_WITHIN(0.05, 50.729723, estimate(23));
83+
}
84+
85+
void test_among_seventy_people(void) {
86+
TEST_IGNORE();
87+
TEST_ASSERT_FLOAT_WITHIN(0.05, 99.915958, estimate(70));
88+
}
89+
90+
int main(void) {
91+
UNITY_BEGIN();
92+
RUN_TEST(test_one_birthdate);
93+
RUN_TEST(test_two_birthdates_with_same_year_month_and_day);
94+
RUN_TEST(test_two_birthdates_with_same_year_and_month_but_different_day);
95+
RUN_TEST(test_two_birthdates_with_same_month_and_day_but_different_year);
96+
RUN_TEST(test_two_birthdates_with_same_year_but_different_month_and_day);
97+
RUN_TEST(test_two_birthdates_with_different_year_month_and_day);
98+
RUN_TEST(test_multiple_birthdates_without_shared_birthday);
99+
RUN_TEST(test_multiple_birthdates_with_one_shared_birthday);
100+
RUN_TEST(test_multiple_birthdates_with_more_than_one_shared_birthday);
101+
RUN_TEST(test_for_one_person);
102+
RUN_TEST(test_among_ten_people);
103+
RUN_TEST(test_among_twentythree_people);
104+
RUN_TEST(test_among_seventy_people);
105+
return UNITY_END();
106+
}

0 commit comments

Comments
 (0)