Leí acerca de los RNG en Wikipedia y $RANDOM
funcionó en TLDP, pero en realidad no explica este resultado:
$ max=$((6*3600))
$ for f in {1..100000}; do echo $(($RANDOM%max/3600)); done | sort | uniq -c
21787 0
22114 1
21933 2
12157 3
10938 4
11071 5
¿Por qué los valores anteriores son aproximadamente 2 veces más propensos a ser 0, 1, 2 que 3, 4, 5, pero cuando cambio el módulo máximo, se distribuyen casi por igual en los 10 valores?
$ max=$((9*3600))
$ for f in {1..100000}; do echo $(($RANDOM%max/3600)); done | sort | uniq -c
11940 0
11199 1
10898 2
10945 3
11239 4
10928 5
10875 6
10759 7
11217 8
$RANDOM
variable no utiliza un buen PRNG internamente.Respuestas:
Para ampliar el tema del sesgo de módulo, su fórmula es:
Y en esta fórmula,
$RANDOM
es un valor aleatorio en el rango 0-32767.Ayuda a visualizar cómo esto se asigna a los posibles valores:
Entonces, en su fórmula, la probabilidad de 0, 1, 2 es dos veces mayor que 4, 5. Y la probabilidad de 3 también es ligeramente mayor que 4, 5. De ahí su resultado con 0, 1, 2 como ganadores y 4, 5 como perdedores.
Al cambiar a
9*3600
, resulta que:1-8 tienen la misma probabilidad, pero todavía hay un ligero sesgo para 0 y, por lo tanto, 0 seguía siendo el ganador en su prueba con 100'000 iteraciones.
Para corregir el sesgo del módulo, primero debe simplificar la fórmula (si solo desea 0-5, entonces el módulo es 6, no 3600 o incluso un número más loco, no tiene sentido). Esta simplificación por sí sola reducirá su sesgo en gran medida (32766 se asigna a 0, 32767 a 1 dando un pequeño sesgo a esos dos números).
Para deshacerse del sesgo por completo, debe volver a tirar, (por ejemplo) cuando
$RANDOM
es inferior a32768 % 6
(eliminar los estados que no se asignan perfectamente al rango aleatorio disponible).Resultado de la prueba:
La alternativa sería usar una fuente aleatoria diferente que no tenga un sesgo notable (órdenes de magnitud mayores que solo 32768 valores posibles). Pero implementar una lógica de repetición de todos modos no hace daño (incluso si es probable que nunca se cumpla).
fuente
Esto es sesgo de módulo. Si
RANDOM
está bien construido, cada valor entre 0 y 32767 se produce con igual probabilidad. Cuando usa el módulo, cambia las probabilidades: las probabilidades de todos los valores por encima del módulo se agregan a los valores a los que se asignan.En su ejemplo, 6 × 3600 es aproximadamente dos tercios del rango de valores. Por lo tanto, las probabilidades del tercio superior se suman a las del tercio inferior, lo que significa que los valores de 0 a 2 (aproximadamente) tienen el doble de probabilidades de producirse que los valores de 3 a 5. 9 × 3600 es casi 32767, por lo que el sesgo de módulo es mucho más pequeño y solo afecta valores de 32400 a 32767.
Para responder a su pregunta principal, al menos en Bash la secuencia aleatoria es completamente predecible si conoce la semilla. Ver
intrand32
envariables.c
.fuente