¡No uses rand()
!
Si buscas precisión en las distribuciones de la aleatoriedad, abandona rand()
. Utilizar rand()
no sólo es inadecuado por ser una utilidad del lenguaje C (siendo tu pregunta sobre C++) si no que también lo es porque el uso que le estás dando falsea la distribución.
Distribución de rand()
.
La función rand()
devuelve un número entero, pseudoaleatorio entre 0
y RAND_MAX
(ambos incluídos). La distribución de los valores resultantes de llamar a rand()
es uniforme, es decir: todos los números entre 0
y RAND_MAX
tienen la misma probabilidad de obtenerse.
Rompes la distribución de rand()
.
Suponiendo que el intervalo de rand()
sea [0, 32767], si el resultado lo operas con módulo (%
) sobre un número que no es divisor del valor máximo del intervalo (en tu caso 100
) estarás falseando la distribución: dado que el residuo de dividir 32767 entre 100 es 67, los números de 0 a 67 tienen más probabilidades de aparecer que los números 68 a 99.
¿Qué debes hacer?
Como ya he comentado, debes dejar de usar rand()
, que además de no ser una utilidad de C++ ¡lo estabas usando mal!. La manera adecuada de aproximar tu problema es usar <random>
la librería de números pseudoaleatorios de C++ que permite escoger la distribución de probabilidad (uniforme, Bernoulli, Poisson, normal, discreta, constante, lineal...), el tipo subyacente del valor generado e incluso el algoritmo a usar (minstd, mt19937, ranlux, knuth...).
En tu caso, dado que tus probabilidades se dividen en dos:
- ¿He sacado pelota? se cumplirá 1 de cada 20 veces (5%).
- Si he sacado pelota ¿de qué color es? (15% dorada, 15% roja, 30% azul y 40% verde).
Para la primera probabilidad, podrías usar una distribución de Bernoulli, que permite configurar la probabilidad de que un suceso (sacar pelota) suceda:
std::random_device device;
std::mt19937 generador(device());
std::bernoulli_distribution distribucion(0.05);
if (distribucion(generador));
{
// Entramos en este if un 5% de las veces.
}
Para la segunda probabilidad, podrías usar una distribución discreta, que permite distribuir el peso de cada probabilidad (las probabilidades de aparición de cada pelota):
std::random_device device;
std::mt19937 generador(device());
std::discrete_distribution<> distribucion({15, 15, 30, 40});
switch(distribucion(generador))
{
case 0: std::cout << "Pelota dorada\n"; break;
case 1: std::cout << "Pelota roja\n"; break;
case 2: std::cout << "Pelota azul\n"; break;
case 3: std::cout << "Pelota verde\n"; break;
}
Puedes ver un ejemplo de esto funcionando en Wandbox 三へ( へ՞ਊ ՞)へ ハッハッ.