Me parece ver muchas respuestas en las que alguien sugiere usar <random>
para generar números aleatorios, generalmente junto con un código como este:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);
Por lo general, esto reemplaza algún tipo de "abominación impía" como:
srand(time(NULL));
rand()%6;
Podríamos criticar la forma antigua argumentando que time(NULL)
proporciona una entropía baja, time(NULL)
es predecible y el resultado final no es uniforme.
Pero todo eso es cierto en la nueva forma: simplemente tiene un barniz más brillante.
rd()
devuelve un singleunsigned int
. Esto tiene al menos 16 bits y probablemente 32. Eso no es suficiente para generar los 19937 bits de estado de MT.Usar
std::mt19937 gen(rd());gen()
(sembrar con 32 bits y mirar la primera salida) no da una buena distribución de salida. 7 y 13 nunca pueden ser la primera salida. Dos semillas producen 0. Doce semillas producen 1226181350. ( Enlace )std::random_device
puede implementarse, y a veces se implementa, como un PRNG simple con una semilla fija. Por lo tanto, podría producir la misma secuencia en cada ejecución. ( Enlace ) Esto es incluso peor quetime(NULL)
.
Peor aún, es muy fácil copiar y pegar los fragmentos de código anteriores, a pesar de los problemas que contienen. Algunas soluciones para esto requieren la adquisición de bibliotecas grandes que pueden no ser adecuadas para todos.
A la luz de esto, mi pregunta es ¿Cómo se puede sembrar de manera sucinta, portátil y completa el PRNG mt19937 en C ++?
Dados los problemas anteriores, una buena respuesta:
- Debe sembrar completamente el mt19937 / mt19937_64.
- No se puede confiar únicamente en
std::random_device
otime(NULL)
como fuente de entropía. - No debería confiar en Boost u otras bibliotecas.
- Debe caber en una pequeña cantidad de líneas para que se vea bien pegado en una respuesta.
Pensamientos
Mi pensamiento actual es que las salidas de
std::random_device
se pueden combinar (tal vez a través de XOR) contime(NULL)
valores derivados de la aleatorización del espacio de direcciones y una constante codificada (que podría establecerse durante la distribución) para obtener un mejor esfuerzo en la entropía.std::random_device::entropy()
no da una buena indicación de lo questd::random_device
podría o no hacer.
std::random_device
, time(NULL)
y direcciones de funciones, y luego XOR juntos para producir una especie de fuente de entropía de mejor esfuerzo.
std::random_device
correctamente en las plataformas en las que planea ejecutar su programa y proporcionar una función auxiliar que crea un generador inicial ( seed11::make_seeded<std::mt19937>()
)