Birthday problem: Difference between revisions

Add Scala implementation
(Added XPL0 example.)
(Add Scala implementation)
 
(4 intermediate revisions by 3 users not shown)
Line 1:
[[Category:Probability and statistics]]
[[Category:Discrete math]]
{{Wikipedia pre 15 June 2009|pagename=Birthday Problem|lang=en|oldid=296054030|timedate=21:44, 12 June 2009}}
{{draft task}}
[[Category:Probability and statistics]]
[[Category:Discrete math]]
 
 
Line 21:
* Wolfram entry:   {{Wolfram|Birthday|Problem}}
<br><br>
 
=={{header|11l}}==
{{trans|D}}
 
<langsyntaxhighlight lang="11l">F equal_birthdays(sharers, groupsize, rep)
V eq = 0
L 0 .< rep
Line 52 ⟶ 51:
group_est = gs
print(‘#. independent people in a group of #. share a common birthday. (#3.1)’.format(sharers, gs, eq))
L.break</langsyntaxhighlight>
 
{{out}}
Line 61 ⟶ 60:
5 independent people in a group of 313 share a common birthday. ( 50.4)
</pre>
 
=={{header|Ada}}==
 
This solution assumes a 4-year cycle, with three 365-day years and one leap year.
 
<langsyntaxhighlight Adalang="ada">with Ada.Command_Line, Ada.Text_IO, Ada.Numerics.Discrete_random;
 
procedure Birthday_Test is
Line 138 ⟶ 136:
" persons sharing a common birthday.");
end loop;
end Birthday_Test;</langsyntaxhighlight>
 
{{out}}
Line 159 ⟶ 157:
An interesting observation:
The probability for groups of 313 persons having 5 persons sharing a common birthday is almost exactly 0.5. Note that a solution based on 365-day years, i.e., a solution ignoring leap days, would generate slightly but significantly larger probabilities.
 
=={{header|ALGOL 68}}==
{{works with|ALGOL 68|Revision 1}}
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.6 algol68g-2.6].}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}}
'''File: Birthday_problem.a68'''<langsyntaxhighlight lang="algol68">#!/usr/bin/a68g --script #
# -*- coding: utf-8 -*- #
 
Line 228 ⟶ 225:
required common +:= 1
FI
OD # group size #</langsyntaxhighlight>'''Output:'''
<pre>
upb year: 365.2500; upb common: 5; upb sample size: 100000;
Line 242 ⟶ 239:
required common: 5; group size: 314; %age of years with required common birthdays: 50.66%;
</pre>
 
=={{header|C}}==
Computing probabilities to 5 sigmas of confidence. It's very slow, chiefly because to make sure a probability like 0.5006 is indeed above .5 instead of just statistical fluctuation, you have to run the simulation millions of times.
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Line 340 ⟶ 336:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>
Line 348 ⟶ 344:
5 collision: 313 people, P = 0.500641 +/- 0.000128174
</pre>
 
=={{header|C++}}==
{{trans|Java}}
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <random>
#include <vector>
Line 407 ⟶ 402:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>2 independant people in a group of 23 share a common birthday. ( 50.6)
Line 413 ⟶ 408:
4 independant people in a group of 186 share a common birthday. ( 50.0)
5 independant people in a group of 313 share a common birthday. ( 50.5)</pre>
 
=={{header|D}}==
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.random, std.algorithm, std.conv;
 
/// For sharing common birthday must all share same common day.
Line 464 ⟶ 458:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>2 independent people in a group of 23 share a common birthday. ( 50.5)
Line 474 ⟶ 468:
Alternative version:
{{trans|C}}
<langsyntaxhighlight lang="d">import std.stdio, std.random, std.math;
 
enum nDays = 365;
Line 559 ⟶ 553:
writefln("%d collision: %d people, P = %g +/- %g", nCollisions, np, p, d);
}
}</langsyntaxhighlight>
{{out}}
<pre>2 collision: 23 people, P = 0.521934 +/- 0.00728933
Line 574 ⟶ 568:
{{libheader| System.SysUtils}}
{{Trans|C}}
<syntaxhighlight lang="delphi">
<lang Delphi>
program Birthday_problem;
 
Line 679 ⟶ 673:
writeln('Press enter to exit');
readln;
end.</langsyntaxhighlight>
{{out}}
<pre>Wait for calculate
Line 687 ⟶ 681:
5 collision: 313 people, P = 0,50093354 +/- 0,00031116
Press enter to exit</pre>
=={{header|FreeBASIC}}==
{{trans|XPL0}}
<syntaxhighlight lang="freebasic">Function Simulacion(N As Integer) As Integer
Dim As Integer i, dias(365)
For i = 0 To 365-1
dias(i) = 0
Next i
Dim As Integer R, personas = 0
Do
R = Rnd * 365
dias(R) += 1
personas += 1
If dias(R) = N Then Return personas
Loop
End Function
 
Dim As Integer N, grupo, t
For N = 2 To 5
grupo = 0
For t = 1 To 10000
grupo += Simulacion(N)
Next t
Print Using "Average of # people in a population of ### share birthdays"; N; Int(grupo/10000)
Next N
Sleep</syntaxhighlight>
=={{header|Go}}==
{{trans|C}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 800 ⟶ 819:
n, np, p, d)
}
}</langsyntaxhighlight>
<pre>
2 collision: 23 people, P = 0.5081 ± 0.0016
Line 808 ⟶ 827:
</pre>
'''Also based on the C version:'''
<langsyntaxhighlight lang="go">package main
 
import (
Line 892 ⟶ 911:
}
return
}</langsyntaxhighlight>
{{Out}}
<pre>
Line 900 ⟶ 919:
5 collision: 313 people, P = 0.5011 ± 0.0002
</pre>
 
=={{header|Hy}}==
 
We use a simple but not very accurate simulation method.
 
<langsyntaxhighlight lang="lisp">(import
[numpy :as np]
[random [randint]])
Line 934 ⟶ 952:
(print (birthday 3))
(print (birthday 4))
(print (birthday 5))</langsyntaxhighlight>
 
=={{header|J}}==
 
Quicky approach (use a population of 1e5 people to get a quick estimate and then refine against a population of 1e8 people):
 
<langsyntaxhighlight Jlang="j">PopSmall=: 1e5 ?@# 365
PopBig=: 1e8 ?@# 365
 
Line 960 ⟶ 977:
assert. (2+y) > |approx-refine
refine, refine PopBig probShared y
)</langsyntaxhighlight>
 
Task cases:
 
<langsyntaxhighlight Jlang="j"> estGroupSz 2
23 0.507254
estGroupSz 3
Line 971 ⟶ 988:
187 0.502878
estGroupSz 5
313 0.500903</langsyntaxhighlight>
 
So, for example, we need a group of 88 to have at least a 50% chance of 3 people in the group having the same birthday in a year of 365 days. And, in that case, the simulated probability was 51.0737%
 
=={{header|Java}}==
Translation of [[Birthday_problem#Python|Python]] via [[Birthday_problem#D|D]]
{{works with|Java|8}}
<langsyntaxhighlight lang="java">import static java.util.Arrays.stream;
import java.util.Random;
 
Line 1,031 ⟶ 1,047:
}
}
}</langsyntaxhighlight>
 
<pre>2 independent people in a group of 23 share a common birthday. ( 50,6)
Line 1,037 ⟶ 1,053:
4 independent people in a group of 187 share a common birthday. ( 50,1)
5 independent people in a group of 314 share a common birthday. ( 50,2)</pre>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
{{trans|Python}}
 
<langsyntaxhighlight lang="julia">function equalbirthdays(sharers::Int, groupsize::Int; nrep::Int = 10000)
eq = 0
for _ in 1:nrep
Line 1,080 ⟶ 1,095:
push!(gsizes, gsize)
@printf("%i independent people in a group of %s share a common birthday. (%5.3f)\n", sh, gsize, freq)
end</langsyntaxhighlight>
 
{{out}}
Line 1,087 ⟶ 1,102:
4 independent people in a group of 187 share a common birthday. (0.500)
5 independent people in a group of 314 share a common birthday. (0.507)</pre>
 
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">// version 1.1.3
 
import java.util.Random
Line 1,135 ⟶ 1,149:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,145 ⟶ 1,159:
5 independent people in a group of 314 share a common birthday (50.2%)
</pre>
 
=={{header|Lasso}}==
<langsyntaxhighlight Lassolang="lasso">if(sys_listunboundmethods !>> 'randomgen') => {
define randomgen(len::integer,max::integer)::array => {
#len <= 0 ? return
Line 1,176 ⟶ 1,189:
'Threshold: '+#threshold+', qty: '+#qty+' - probability: '+#probability+'\r'
#qty += 1
^}</langsyntaxhighlight>
 
{{out}}
Line 1,200 ⟶ 1,213:
Threshold: 5, qty: 314 - probability: 50.000000
</pre>
 
=={{header|Nim}}==
{{trans|Kotlin}}
<langsyntaxhighlight Nimlang="nim">import random, sequtils, strformat
 
proc equalBirthdays(nSharers, groupSize, nRepetitions: int): float =
Line 1,242 ⟶ 1,254:
break
 
main()</langsyntaxhighlight>
 
{{out}}
Line 1,249 ⟶ 1,261:
4 independent people in a group of 187 share a common birthday (50.2%)
5 independent people in a group of 313 share a common birthday (50.2%)</pre>
 
=={{header|PARI/GP}}==
<langsyntaxhighlight lang="parigp">simulate(n)=my(v=vecsort(vector(n,i,random(365))),t,c=1); for(i=2,n,if(v[i]>v[i-1],t=max(t,c);c=1,c++)); t
find(n)=my(guess=365*n-342,t);while(1, t=sum(i=1,1e3,simulate(guess)>=n)/1e3; if(t>550, guess--); if(t<450, guess++); if(450<=t && t<=550, return(guess)))
find(2)
find(3)
find(4)
find(5)</langsyntaxhighlight>
 
=={{header|Perl}}==
{{trans|Raku}}
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use List::AllUtils qw(max min uniqnum count_by any);
Line 1,285 ⟶ 1,295:
}
 
printf "$_ people in a group of %s share a common birthday. (%.4f)\n", simulation($_) for 2..5</langsyntaxhighlight>
{{out}}
<pre>2 people in a group of 23 share a common birthday. (0.5083)
Line 1,291 ⟶ 1,301:
4 people in a group of 187 share a common birthday. (0.5034)
5 people in a group of 313 share a common birthday. (0.5008)</pre>
 
=={{header|Phix}}==
{{trans|D}}
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)[very/too slow]-->
<span style="color: #008080;">constant</span> <span style="color: #000000;">nDays</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">365</span>
Line 1,365 ⟶ 1,374:
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d collision: %d people, P = %g +/- %g\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">nCollisions</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">np</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 1,382 ⟶ 1,391:
6 collision: 460 people, P = 0.502901 +/- 0.000580137
</pre>
 
=={{header|PL/I}}==
<langsyntaxhighlight PLlang="pl/Ii">*process source attributes xref;
bd: Proc Options(main);
/*--------------------------------------------------------------------
Line 1,434 ⟶ 1,442:
End;
End;
End;</langsyntaxhighlight>
Output:
<pre>
Line 1,508 ⟶ 1,516:
1182 496957 503043 50.304% <-
1183 494414 505586 50.559% <-</pre>
 
=={{header|Python}}==
Note: the first (unused), version of function equal_birthdays() uses a different but equally valid interpretation of the phrase "common birthday".
<langsyntaxhighlight lang="python">
from random import randint
 
Line 1,551 ⟶ 1,558:
break
group_est.append(groupsize)
print("%i independent people in a group of %s share a common birthday. (%5.1f)" % (sharers, groupsize, eq))</langsyntaxhighlight>
 
{{out}}
Line 1,561 ⟶ 1,568:
===Enumeration method===
The following enumerates all birthday distributation of n people in a year. It's patentedly unscalable.
<langsyntaxhighlight lang="python">from collections import defaultdict
days = 365
 
Line 1,601 ⟶ 1,608:
n, good, combos = find_half(x)
print "%d of %d people sharing birthday: %d out of %d combos"% (x, n, good, combos)
</syntaxhighlight>
</lang>
{{out}}
<pre>2 of 23 people sharing birthday: 43450860051057961364418604769486195435604861663267741453125 out of 85651679353150321236814267844395152689354622364044189453125 combos
Line 1,608 ⟶ 1,615:
</pre>
===Enumeration method #2===
<langsyntaxhighlight lang="python"># ought to use a memoize class for all this
# factorial
def fact(n, cache={0:1}):
Line 1,654 ⟶ 1,661:
return
 
for x in range(2, 6): find_half(x)</langsyntaxhighlight>
{{out}}
<pre>
Line 1,662 ⟶ 1,669:
313 of 5 people: 498385488882289...2578125/99464149835930...2578125 combos
</pre>
 
=={{header|Racket}}==
{{trans|Python}}Based on the Python task. For three digits precision use 250000 repetitions. For four digits precision use 25000000 repetitions, but it’s very slow. See discussion page.
<langsyntaxhighlight Racketlang="racket">#lang racket
 
#;(define repetitions 25000000) ; for \sigma=1/10000
Line 1,713 ⟶ 1,719:
(search-from sharers (search-coarse-group-size sharers))])
(printf "~a independent people in a group of ~a share a common birthday. (~a%)\n"
sharers group-size (~r (* probability 100) #:precision '(= 2)))))</langsyntaxhighlight>
'''Output'''
<pre>2 independent people in a group of 23 share a common birthday. (50.80%)
Line 1,720 ⟶ 1,726:
5 independent people in a group of 313 share a common birthday. (50.17%)
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
Gives correct answers, but more of a proof-of-concept at this point, even with max-trials at 250K it is too slow to be practical.
<syntaxhighlight lang="raku" perl6line>sub simulation ($c) {
my $max-trials = 250_000;
my $min-trials = 5_000;
Line 1,738 ⟶ 1,743:
}
 
printf "$_ people in a group of %s share a common birthday. (%.3f)\n", simulation($_) for 2..5;</langsyntaxhighlight>
{{out}}
<pre>2 people in a group of 23 share a common birthday. (0.506)
Line 1,744 ⟶ 1,749:
4 people in a group of 187 share a common birthday. (0.500)
5 people in a group of 313 share a common birthday. (0.507)</pre>
 
=={{header|REXX}}==
===version 1===
Line 1,752 ⟶ 1,756:
 
This REXX version doesn't need a precalculated group size to find the percentage required to exceed 50%.
<langsyntaxhighlight lang="rexx">/*REXX pgm examines the birthday problem via random# simulation (with specifiable parms)*/
parse arg dups samp seed . /*get optional arguments from the CL. */
if dups=='' | dups=="," then dups= 10 /*Not specified? Then use the default.*/
Line 1,783 ⟶ 1,787:
end /*try=start.g*/ /* [↑] where the try─outs happen. */
say right(g, 15) right(try, 15) center( format( s / samp * 100, , 4)'%', 30)
end /*g*/ /*stick a fork in it, we're all done. */</langsyntaxhighlight>
{{out|output|text= &nbsp; when using the default inputs:}}
<pre>
Line 1,803 ⟶ 1,807:
 
===version 2===
<langsyntaxhighlight lang="rexx"> /*--------------------------------------------------------------------
* 04.11.2013 Walter Pachl translated from PL/I
* Take samp samples of groups with gs persons and check
Line 1,834 ⟶ 1,838:
Say format(gs,10) cnt.0 cnt.1 100*hits||'%'||arrow
End
End</langsyntaxhighlight>
Output:
<pre>
Line 1,876 ⟶ 1,880:
461 49316 50684 50.68400% <-
462 49121 50879 50.87900% <-</pre>
 
=={{header|Ruby}}==
{{trans|Java}}
<langsyntaxhighlight lang="ruby">def equalBirthdays(nSharers, groupSize, nRepetitions)
eq = 0
 
Line 1,924 ⟶ 1,927:
end
 
main()</langsyntaxhighlight>
{{out}}
<pre>2 independant people in a group of 23 share a common birthday. ( 50.5)
Line 1,930 ⟶ 1,933:
4 independant people in a group of 187 share a common birthday. ( 50.3)
5 independant people in a group of 313 share a common birthday. ( 50.3)</pre>
 
 
=={{header|Scala}}==
{{trans|Java}}
<syntaxhighlight lang="Scala">
import scala.util.Random
import scala.util.control.Breaks._
 
object Test {
 
def equalBirthdays(
nSharers: Int,
groupSize: Int,
nRepetitions: Int
): Double = {
val rand = new Random(1)
var eq = 0
 
for (_ <- 1 to nRepetitions) {
val group = new Array[Int](365)
for (_ <- 1 to groupSize) {
val birthday = rand.nextInt(group.length)
group(birthday) += 1
}
if (group.exists(_ >= nSharers)) eq += 1
}
 
(eq * 100.0) / nRepetitions
}
 
def main(args: Array[String]): Unit = {
var groupEst = 2
 
for (sharers <- 2 until 6) {
// Coarse.
var groupSize = groupEst + 1
while (equalBirthdays(sharers, groupSize, 100) < 50.0)
groupSize += 1
 
// Finer.
val inf = (groupSize - (groupSize - groupEst) / 4.0).toInt
breakable({
for (gs <- inf until groupSize + 999) {
val eq = equalBirthdays(sharers, groupSize, 250)
if (eq > 50.0) {
groupSize = gs
break
}
}
})
 
// Finest.
breakable({
for (gs <- (groupSize - 1) until groupSize + 999) {
val eq = equalBirthdays(sharers, gs, 50000)
if (eq > 50.0) {
groupEst = gs
println(
f"$sharers independent people in a group of $gs share a common birthday. ($eq%5.1f)"
)
break
}
}
})
}
}
}
</syntaxhighlight>
{{out}}
<pre>
2 independent people in a group of 23 share a common birthday. ( 50.6)
3 independent people in a group of 87 share a common birthday. ( 50.4)
4 independent people in a group of 187 share a common birthday. ( 50.1)
5 independent people in a group of 314 share a common birthday. ( 50.2)
 
</pre>
 
 
=={{header|SQL}}==
birthday.sql
<syntaxhighlight lang="sql">
<lang SQL>
with
c as
Line 1,996 ⟶ 2,076:
from sol where rownum = 1
;
</syntaxhighlight>
</lang>
 
SQL> @ birthday.sql
Line 2,004 ⟶ 2,084:
----------
23
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">proc birthdays {num {same 2}} {
for {set i 0} {$i < $num} {incr i} {
set b [expr {int(rand() * 365)}]
Line 2,039 ⟶ 2,118:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,070 ⟶ 2,149:
level found: 315 people
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-fmt}}
<langsyntaxhighlight ecmascriptlang="wren">import "random" for Random
import "./fmt" for Fmt
 
var equalBirthdays = Fn.new { |nSharers, groupSize, nRepetitions|
Line 2,117 ⟶ 2,195:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 2,128 ⟶ 2,206:
 
=={{header|XPL0}}==
<langsyntaxhighlight XPL0lang="xpl0">func Sim(N);
\Simulate birthdays and return number of people to have N same days
int N, I, People, R;
Line 2,148 ⟶ 2,226:
IntOut(0, N); Text(0, ": "); IntOut(0, Sum/10000); CrLf(0);
];
]</langsyntaxhighlight>
 
{{out}}
Line 2,157 ⟶ 2,235:
5: 311
</pre>
 
=={{header|zkl}}==
Pure simulation; adding a person to a population until there are the required number of collisions, then repeating that a bunch of times to get an average.
<langsyntaxhighlight lang="zkl">fcn bdays(N){ // N is shared birthdays in a population
year:=(0).pump(365,List.createLong(365).write,0); // 365 days == one year
shared:=people:=0; do{ // add a new person to population
Line 2,173 ⟶ 2,250:
println("Average of %d people in a populatation of %s share birthdays"
.fmt(n,simulate(n,0d10_000)));
}</langsyntaxhighlight>
{{out}}
<pre>
338

edits