I read a very interesting article on the NY Times today, linked from this /. article, about the Monty Hall Problem. The problem has apparently caused much embarrassment among mathematicians, and now psychologists, and it’s a very interesting read.
I couldn’t quite agree with the argument put forth, and I’m no mathematician, so I wrote a simple program to calculate some numbers for me… first, lets review the problem at hand:
- I present you with three closed doors. Behind one is a new car, the other two, a goat.
- You choose one of the three doors, hoping it has a car.
- I open one door exposing a goat.
- You may keep your original door, or change your mind choosing the other closed door.
- Open your door, if it’s the car, you can keep it.
So as impulsive humans, it’s easy to see, and think, that since I open one door, your final choice gives you a 50/50 shot at winning a car. The argument in the paper those posits that you should change your mind, since your original decision only had a 33% chance of being correct, and a 66% chance of being wrong.
The source for this simulation is included below. It very closely follows the steps I laid out above, resetting the doors at the start of the loop, randomly choosing which one contains a “car” (true value). The simulates a user’s choice (rand mod three), opens a door containing a goat, and then simulates the user randomly choosing to change their mind (rand mod 2). It totals how many times the user kept their original door and won a car, as well as how many times the user changed their minds and won a car.
I present the results here for you to mull over – I ran 75,000,000 iterations of the loop and got the following:
How many iterations: 75000000
In 75000000 runs, we won a car 44.4418% of the time.
Used original choice and won a car 12499628 out of 37505245 times... 33.3277%
Chose the other door and won a car 20831722 out of 37494755 times... 55.559%
Suggesting that your original choice is only correct 33% of the time – which makes perfect sense. However, after I open a door and narrow your choices down, you have about a 50% chance of winning the car when you change your mind.
Since your original choice was made out of three closed doors, you’ll win with that choice 33% of the time. However, when you change your mind you’re only choosing out of two closed doors, so you’ll win about 50% of the time.
Doesn’t add up, I know – but makes a certain bit of sense.
/** Monty Hall's game simulator… Calculates win percentages when you keep your original door or change your mind in a monty hall problem - http://en.wikipedia.org/wiki/Monty_Hall_problem * Author: Timothy C. Fanelli Date: April 10, 2008 **/ include <cstdlib> include <cassert> include <ctime> include <iostream> using namespace std; int main() { int iterations; bool contents[] = { false, false, false }; cout << "How many iterations: "; cin >> iterations; int changedDoorCount = 0; int correct[] = {0, 0}; srand( time( 0 ) ); for ( int i = 0; i < iterations; ++i ) { int goatOne, goatTwo; int carIdx = rand() % 3;// Setup the monty hall's doors:
contents[0] = false;
contents[1] = false;
contents[2] = false;
contents[carIdx] = true;
if ( carIdx == 0 ) {
goatOne = 1;
goatTwo = 2;
}
else if ( carIdx == 1 ) {
goatOne = 0;
goatTwo = 2;
}
else {
goatOne = 0;
goatTwo = 1;
}
// So:
// contents[carIdx] == true
// contents[goatOne] == false
// contents[goatTwo] == false
assert( contents[carIdx] );
assert( ! contents[goatOne] );
assert( ! contents[goatTwo] );
// Simulate an initial choice, then expose a goat:
int userChoice = rand() % 3;
int doorExposed = (goatOne==userChoice)?goatTwo:goatOne;
// Do we change doors?
bool changedDoors = rand() % 2;
if ( changedDoors ) {
changedDoorCount++;
// Pick the door that isn't the user's choice
// and isn't the exposedDoor... note:
//
// userChoice != doorExposed by design.
if ( userChoice == 0 )
{
if ( doorExposed == 1 )
userChoice = 2;
else
userChoice == 1;
}
else if ( userChoice == 1 )
{
if ( doorExposed == 0 )
userChoice = 2;
else
userChoice = 0;
}
else
{
if ( doorExposed == 0 )
userChoice = 1;
else
userChoice = 0;
}
assert( userChoice != doorExposed ); }
// Track how many times we chose correctly -
// Increment correct[0] if we kept our original choice
// Increment correct[1] if we chose the other door.
if ( contents[userChoice] ) {
correct[ changedDoors ]++; } }
double changedWinPercent =
100(correct[1]/static_cast(changedDoorCount));
double originalWinPercent =
100(correct[0]/static_cast(iterations-changedDoorCount)); double totalWinPercent = (correct[0]+correct[1]) / static_cast( iterations ) * 100; cout << "In " << iterations << " runs, we won a car " << totalWinPercent << "% of the time." << endl; cout << "\tUsed original choice and won a car " << correct[0] << " out of " << iterations - changedDoorCount << " times… " << originalWinPercent << "%" << endl; cout << "\tChose the other door and won a car " << correct[1] << " out of " << changedDoorCount << " times… " << changedWinPercent << "%" << endl; }