I am trying to write a code for the birthday problem. For example, given a group of 23 people, 2 people having the same birthday should be greater than 50%. But for some reason, my code is returning 69.32% which doesn't make sense.
function doProbability() {
const cntPeople = document.getElementById( 'setSize' ).valueAsNumber;
const cntSubset = document.getElementById( 'subsetSize' ).valueAsNumber;
const prob = getProbability( cntPeople, cntSubset );
const probAsPercentage = prob.toLocaleString( undefined, { style: 'percent', minimumFractionDigits: 2 } );
document.getElementById( 'result' ).textContent = "Probability: " + probAsPercentage;
}
function getProbability( cntPeople, cntSubset ) {
// Count of number of ways of choosing these pairs (cntPeople choose cntSubset)
const selectingCnt = binomial( cntPeople, cntSubset );
// Probability of one k subset of people having the same birthday
const birthdayP = 1.0 / Math.pow( 365, cntSubset - 1 );
// Probability of any k subset of people having the same birthday
return Math.min( selectingCnt * birthdayP, 1 );
}
function binomial(n, k) {
// Preconditions:
if( typeof n !== 'number' || isNaN( n ) || n < 0 ) throw new Error( 'n is invalid' );
if( typeof k !== 'number' || isNaN( k ) || k < 0 ) throw new Error( 'k is invalid' );
if( k > n ) throw new Error( 'k cannot be greater than n' );
//
let b = 1;
for ( var t = 0, _pj_a = Math.min(k, n - k); t < _pj_a; t += 1 ) {
b *= n;
b /= t + 1;
n -= 1;
}
return b;
}
label { display: block; }
<label>
Size of entire set of people
<input type="number" min="1" max="999" value="23" id="setSize" />
</label>
<label>
Size of small subset of people
<input type="number" min="1" max="999" value="2" id="subsetSize" />
</label>
<button onclick="doProbability()">Click me</button>
<br />
<output id="result"></output>
Updated your getProbability function based on this working example (https://jsfiddle.net/aM3z/36z0f4pu/).
Also updated the binomial function by simplifying it.
function doProbability() {
const cntPeople = document.getElementById( 'setSize' ).valueAsNumber;
const cntSubset = document.getElementById( 'subsetSize' ).valueAsNumber;
const prob = getProbability( cntPeople, cntSubset );
const probAsPercentage = prob.toLocaleString( undefined, { style: 'percent', minimumFractionDigits: 2 } );
document.getElementById( 'result' ).textContent = "Probability: " + probAsPercentage;
}
function getProbability( cntPeople, cntSubset ) {
let days = 365
// Count of number of ways of choosing these pairs (cntPeople choose cntSubset)
const selectingCnt = binomial( cntPeople, cntSubset );
const birthdayP = (days - 1) / days
return ((1 - Math.pow(birthdayP, selectingCnt)) * 100).toFixed(2);
}
function binomial(n, k) {
// Preconditions:
if( typeof n !== 'number' || isNaN( n ) || n < 0 ) throw new Error( 'n is invalid' );
if( typeof k !== 'number' || isNaN( k ) || k < 0 ) throw new Error( 'k is invalid' );
if( k > n ) throw new Error( 'k cannot be greater than n' );
return (n * (n - 1)) / k;
}
label { display: block; }
<label>
Size of entire set of people
<input type="number" min="1" max="999" value="23" id="setSize" />
</label>
<label>
Size of small subset of people
<input type="number" min="1" max="999" value="2" id="subsetSize" />
</label>
<button onclick="doProbability()">Click me</button>
<br />
<output id="result"></output>