2012-09-07 7 views
5

Actualmente, tengo una aplicación principal en Fortran que necesita una semilla para generar números pseudoaleatorios. Me gustaría ejecutar muchas (muchas) veces esta aplicación con semillas completamente no correlacionadas (y además cadenas de números pseudoaleatorias completamente independientes).Semillas aleatorias paralelas no correlacionadas con C++ 2011?

Mi pregunta es: ¿cómo generar las semillas con C++ 2011?

+0

supongo que los números sobre la arquitectura con alma única serían pseudo-aleatorio, sería generar números 1,2,3,4,5,6,7,8 como los métodos y procesos de forma secuencial a través de la CPU haría acaba de tomar lo que está siguiente y actuaría como 'rand(); rand(); return rand(); ' – Vyktor

Respuesta

6

En su hilo principal, extraiga una única semilla (o secuencia inicial) de una buena fuente aleatoria (por ejemplo, de /dev/urandom en Linux). Use esa información para sembrar un solo PRNG raíz. Luego use que PRNG para generar valores de inicialización para sus PRNG locales de subprocesos.

#include <random> 
#include <vector> 

typedef std::mt19937 rng_type; 
std::uniform_int_distribution<rng_type::result_type> udist; 

int main() 
{ 
    rng_type rng; 

    // seed rng first, and store the result in a log file: 
    rng_type::result_type const root_seed = get_seed(); 
    rng.seed(root_seed); 

    // make thread seeds: 
    std::vector<rng_type::result_type> seeds(NUMBER_OF_THREADS); 
    for (auto & n : seeds) { n = udist(rng); } 

    // make threads... 
} 

El interfaz del motor de número aleatorio en <random> le permite siembras tanto desde un solo número entero y de una secuencia de números enteros. Si desea aleatoriedad adicional, puede sembrar el mt19937 a partir de una secuencia de varios cientos de enteros.

0

No se puede generar semillas al azar. Tíralos de algún lado. El sistema operativo probablemente tenga una forma de recuperar valores pseudoaleatorios (/dev/urandom en Linux, por ejemplo) que se pueden usar para inicializar.

Obtener una marca de tiempo que represente la hora actual también es una opción común; luego, para asegurarse de obtener diferentes semillas para cada hilo, solo asegúrese de que pidan la marca de tiempo en tiempos ligeramente diferentes y use un temporizador de alta resolución para asegúrese de que realmente obtengan diferentes valores como semillas.

No hay función de "obtener una buena semilla" integrada en C++ 11, porque tal función es esencialmente insignificante. La computadora no puede generar datos aleatorios. Tiene que elegir algo que parece lo suficientemente aleatorio para sus propósitos, y usarlo para generar el generador aleatorio

6

C++ 11 proporciona std::random_device para proporcionar números aleatorios no deterministas si hay una fuente disponible. Sin embargo, deberá verificar su implementación para asegurarse de que sea buena. libC++ usa/dev/urandom de forma predeterminada. libstdC++ también lo hace si se define la macro _GLIBCXX_USE_RANDOM_TR1. La implementación de Visual Studio lamentablemente no es no determinista. editar: a partir de VS2012, su implementación usa los servicios de criptografía de Windows.

Si std::random_device proporciona acceso a una fuente de aleatoriedad no determinista (normalmente/dev/urandom usa un PRNG criptográfico), esto debería ser suficiente para generar semillas independientes.

#include <random> 

int main() { 
    std::random_device r; 
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()}; 
    std::mt19937 engine(seed); 

} 

En lugar de utilizar un único valor como semilla, algunos motores pueden funcionar mejor con más datos de inicialización. Una secuencia de semilla es la alternativa proporcionada por el estándar. Los motores pueden ser sembrados con secuencias semilla, que son objetos que se cargan con cualquier cantidad de datos y que producen datos semilla basados ​​en eso.

valores
std::random_device r; 
std::vector<std::mt19937> engines; 

int engines = 50; 
for (int i = 0; i < engines; ++i) { 
    std::seed_seq s{r(), r(), r(), r(), r(), r(), r(), r()}; 
    engines.emplace_back(s); 
} 

Ocho de 32 bits, 256 bits, es suficiente, pero si realmente desea puede usar más. Cada uno de los motores estándar documenta la cantidad de datos que utiliza de una secuencia de semilla.

Por ejemplo, cada motor mt19937 recuperará mt19937::state_size (624) valores de 32 bits de la secuencia inicial.Las semillas recuperadas de la secuencia de semilla no son las mismas que las de entrada, pero están basadas en esa información, por lo que podemos usar esa cantidad de datos aleatorios en la secuencia.

std::random_device r; 
std::vector<std::uint_least32_t> data; 
std::generate_n(back_inserter(data), 624, std::ref(r)); 

std::seed_seq seed(begin(data), end(data)); 

std::mt19937 engine(seed); // 'fully' seeded mt19937 
+2

+1 por mencionar' std :: random_device'. – ildjarn

Cuestiones relacionadas