Suponga que desea utilizar las <random>
instalaciones de C ++ en un programa práctico (para alguna definición de "práctico", las restricciones aquí son parte de esta pregunta). Tienes un código más o menos así:
int main(int argc, char **argv) {
int seed = get_user_provided_seed_value(argc, argv);
if (seed == 0) seed = std::random_device()();
ENGINE g(seed); // TODO: proper seeding?
go_on_and_use(g);
}
Mi pregunta es, ¿para qué tipo debes usar ENGINE
?
Solía decir siempre
std::mt19937
porque era rápido escribir y tenía reconocimiento de nombre. Pero en estos días parece que todos dicen que el Mersenne Twister es muy pesado y poco amigable con el caché y ni siquiera pasa todas las pruebas estadísticas que otros hacen.Me gustaría decirlo
std::default_random_engine
porque es el obvio "defecto". Pero no sé si varía de una plataforma a otra, y no sé si estadísticamente es bueno.Dado que todos están en una plataforma de 64 bits en estos días, ¿al menos deberíamos usar
std::mt19937_64
másstd::mt19937
?Me gustaría decir
pcg64
oxoroshiro128
porque parecen respetados y ligeros, pero no existen en<random>
absoluto.No sé nada acerca de
minstd_rand
,minstd_rand0
,ranlux24
,knuth_b
, etc - sin duda que debe ser bueno para algo?
Obviamente, hay algunas restricciones en competencia aquí.
Resistencia del motor. (
<random>
no tiene PRNG criptográficamente fuertes, pero aún así, algunos de los estandarizados son "más débiles" que otros, ¿verdad?)sizeof
el motor.Velocidad de su
operator()
.Facilidad de siembra.
mt19937
es notoriamente difícil de sembrar adecuadamente porque tiene mucho estado para inicializar.Portabilidad entre vendedores de bibliotecas. Si un proveedor
foo_engine
produce números diferentes de los de otro proveedorfoo_engine
, eso no es bueno para algunas aplicaciones. (Espero que esto no descarte nada excepto tal vezdefault_random_engine
).
Sopesando todas estas restricciones lo mejor que pueda, ¿cuál diría que es la respuesta definitiva de "mejor práctica para mantenerse dentro de la biblioteca estándar"? ¿Debo seguir usando std::mt19937
o qué?
Respuestas:
C ++ Reference enumera todos los motores aleatorios actualmente proporcionados por C ++. Sin embargo, la selección de motores deja mucho que desear (por ejemplo, vea mi lista de generadores aleatorios de alta calidad ). Por ejemplo:
default_random_engine
está definida por la implementación, por lo que se desconoce si el motor tiene fallas estadísticas que puedan interesarle a la aplicación.linear_congruential_engine
implementa generadores lineales congruentes. Sin embargo, tienden a tener mala calidad a menos que el módulo sea primo y muy grande (al menos 64 bits). Además, no pueden admitir más semillas que su módulo.minstd_rand0
yminstd_rand
admitir solo alrededor de 2 ^ 31 semillas.knuth_b
envuelve aminstd_rand0
y hace una mezcla de Bays-Durham.mt19937
ymt19937_64
podría admitir muchas más semillas si se inicializaran mejor (por ejemplo, inicializando astd::seed_seq
con múltiples salidas derandom_device
, no solo una), pero usan aproximadamente 2500 bytes de estado.ranlux24
yranlux48
usan aproximadamente 577 bits de estado, pero son lentos (funcionan manteniendo algunos y descartando otras salidas pseudoaleatorias).Sin embargo, C ++ también tiene dos motores que envuelven otro motor para mejorar potencialmente sus propiedades de aleatoriedad:
discard_block_engine
descarta algunas de las salidas de un motor aleatorio dado.shuffle_order_engine
implementa una mezcla aleatoria de Bays-Durham de un motor aleatorio dado.Por ejemplo, es posible, por ejemplo, tener un shuffle de Bays-Durham de
mt19937
,ranlux24
o una costumbrelinear_congruential_engine
conshuffle_order_engine
. Quizás el motor envuelto sea de mejor calidad que el original. Sin embargo, es difícil predecir la calidad estadística del nuevo motor sin probarlo .Por lo tanto, en espera de tales pruebas, parece que
mt19937
es el motor más práctico en el estándar C ++ por ahora. Sin embargo, soy consciente de al menos una propuesta para agregar otro motor de números aleatorios a futuras versiones de C ++ (consulte el documento C ++ P2075 ).fuente
Según C ++ de referencia ,
default_random_engine
:Entonces, para un uso liviano , no necesita preocuparse por nada, sembrar
default_random_engine
conEpoch Time (time(0))
y eso sería lo suficientemente bueno;)fuente