2006-04-11

Simulação do problema de Monty Hall

O programa seguinte, escrito em linguagem C, permite simular um grande número de jogos do problema de Monty Hall. Este problema consiste no seguinte: No inicio do jogo temos 3 portas contendo duas delas uma cabra e a terceira um automóvel de luxo.
O jogador escolhe uma das portas, após a escolha o apresentador abre uma das duas outras portas e mostra uma cabra (eliminando uma má resposta). A pergunta do problema de Monty-Hall consiste em saber se o jogador tem algum interesse em mudar de escolha após a eliminação da má resposta.

O programa seguinte supõe que o jogador muda sempre de opinião e conta o número de vezes que este ganha. Para mostrar que a boa estratégia consiste em mudar de opinião um pequeno cálculo elementar mostra que nesse caso se ganha com probabilidade 2/3. O programa ilustra experimentalmente este resultado e serve de bom exemplo para o chamado Método de Monte-Carlo que consiste em simular a realidade mediante a utilização de um gerador de números aleatórios.

Neste caso concreto o programa usa a função uniform01 que tira á sorte un número entre 0 e 1 segundo a lei de distribuição uniforme. Depois distribui o carro e as cabras usando um vector de dimensão 3, se o número for < 1/3 a cabra estará na primeira porta, se estiver entre 1/3 e 2/3 estará na segunda porta e se for > 2/3 estará na última porta. Supomos que o jogador escolhe sempre a primeira porta depois eliminamos uma cabra (escolhida também á sorte) e devolvemos o conteúdo da porta que não foi eliminada.

Finalmente a função main lê o número de experiências a realizar e conta o número de carros.

Este programa compila em qualquer bom compilador de linguagem C, em gcc a linha de comando é:

gcc -o monty_hall monty_hall.c


e para executar 100 000 simulações:

./monty_hall 100000


O código seguinte deve ser copiado para um ficheiro chamado monty_hall.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef unsigned char boolean;
#define FERRARI 1
#define CABRA 0

double uniform01()
{
return ( (double)rand() / ((double)(RAND_MAX)+1.) );
}

boolean simulacao(double rnd1, double rnd2)
{
/* Supomos que se escolhe sempre a primeira porta */
boolean portas[3];
int i;

if ( 3.*rnd1 < 1. )
{
portas[0]=FERRARI;
portas[1]=CABRA;
portas[2]=CABRA;
}
else if ( 3.*rnd1 < 2. )
{
portas[0]=CABRA;
portas[1]=FERRARI;
portas[2]=CABRA;
}
else
{
portas[0]=CABRA;
portas[1]=CABRA;
portas[2]=FERRARI;
}

/* Se ha duas cabras eliminar uma delas */
if (portas[1] == portas[2])
{
/*
Escolher a porta a eliminar aleatoriamente e devolver o
valor da outra.
*/
i=1;
if ( rnd2 < 0.5 )
{
i=2;
}
}
/* Eliminar a porta com a cabra */
else if ( portas[1] == CABRA )
{
i=2;
}
/* Eliminar a porta com a cabra */
else
{
i=1;
}

return portas[i];
}

int main(int argc, char *argv[])
{
int num_simul=1000;
int num_ferrari=0;
int i=0;

srand((unsigned int)time(NULL));

if ( argc > 1 )
{
num_simul=atoi(argv[1]);
}

for ( i=0; i<num_simul; i++)
{
num_ferrari += simulacao(uniform01(),uniform01());
}

printf("Numero de simulacoes: %15d\n", num_simul);
printf("Numero de Ferraris: %15d\n", num_ferrari);
printf("Fraccao de Ferraris: %15.13lf\n",
(double)num_ferrari/(double)num_simul);

return 0;
}