2010-04-14 33 views
6

Estoy tratando de generar una buena semilla aleatoria para un generador de números psicoaleatorios. Pensé que obtendría las opiniones de los expertos. avíseme si esta es una mala manera de hacerlo o si hay formas mucho mejores.C++ generar una buena semilla aleatoria para generadores de números aleatorios psudo

#include <iostream> 
#include <cstdlib> 
#include <fstream> 
#include <ctime> 

unsigned int good_seed() 
{ 
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/random", std::ios::binary); 
    if (file.is_open()) 
    { 
     char * memblock; 
     int size = sizeof(int); 
     memblock = new char [size]; 
     file.read (memblock, size); 
     file.close(); 
     random_seed_a = int(memblock); 
     delete[] memblock; 
    }// end if 
    else 
    { 
     random_seed_a = 0; 
    } 
    random_seed_b = std::time(0); 
    random_seed = random_seed_a xor random_seed_b; 
    return random_seed; 
} // end good_seed() 
+0

no se olvide de tirar los dados y XOR con ella;) – Andrey

+2

¿Qué pasaría si el proceso se queda sin identificadores de archivo y no se puede abrir '/ dev/random'? –

Respuesta

0

Definir bien. :-)

¿Es importante encontrar una semilla rápidamente, o que la semilla sea lo más aleatoria posible sin importar cuánto tiempo tarde en juntarse?

Para un equilibrio - sin duda no es el más aleatoria, definitivamente no es el más rápido ...

  • Cuando se llamó por primera vez, se toman el tiempo del sistema, en milisegundos.
  • Ejecutar eso a través de una función hash, como SHA-1.
  • Usa el resultado como semilla.

Eso debería darle una mayoría aleatoria de 160 bits, que es 10^50o más o menos de variabilidad. El hash tardará una fracción de segundo en ejecutarse, por lo que no es muy rápido, pero ha sido un buen equilibrio en el pasado para mí.

+0

Me gustaría tener lo más aleatorio posible para mi aplicación, pero también me interesaría una solución rápida. – posop

+3

@DeanJ El hash es superfluo. Simplemente siembre con la hora del sistema directamente. Lo que estás tratando de lograr con el hash es qué (un buen) generador de números pseudo aleatorio ya * * (mejor). –

+0

Jon-Eric es 100% correcto; por otro lado, estoy acostumbrado a trabajar con generadores de números aleatorios malos, no puedo distinguir uno bueno de uno malo, y tiendo a limitarme demasiado (rápido). –

1

Tradicionalmente, hemos utilizado la primera o la segunda entrada de usuario para sembrar nuestros valores, ya que el intervalo de tiempo (de tics a milisegundos) que les lleva responder es bastante variable.

5

El código que lee de/dev/random parece incorrecto: usted está transfiriendo C-style la dirección de su búfer de caracteres a random_seed_a (plug para C++ arroja aquí) e ignorando todo lo que realmente lee de/dev/random (intente *reinterpret_cast<int*>(memblock).

/dev/random ya debería ser una buena fuente de entropía, por lo tanto, si está disponible, posiblemente no manche el valor con ningún otro dato y simplemente utilícelo directamente. Si no hay suficientes datos en/dev/random Me limitaría a recurrir al tiempo y usarlo solo en lugar de xor'ing con algo.

+1

según mis estudios una variable aleatoria no determinista "dev/urandom" xor-ed con un tiempo variable no tan aleatorio (0) seguirá siendo una variable aleatoria no determinista. – posop

2

Los buenos generadores de números pseudoaleatorios no necesitan una semilla "buena", ninguna semilla (eso es diferente de correr para correr) funciona igual de bien.

Usando la hora del sistema es directamente bien (y común). Usar /dev/random también está bien.

Si su generador de números pseudoaleatorios no es bueno, incluso elegir una semilla "buena" no ayudará. Reemplaza si puedes.

Sugerencias: Mersenne twister es una muy bien considerada. Here's un precursor que se ejecutará incluso en los sistemas más limitados.

+3

Según el propósito, un generador de números pseudoaleatorios puede necesitar una semilla impredecible. Hubo un juego de póker en línea que alimentó el tiempo en lo que pudo haber sido un PRNG decente, lo que significaba que era posible, al observar algunas cartas, averiguar dónde comenzaba el PRNG y, por lo tanto, conocer todo el mazo. –

+1

Si es * en absoluto * importante para los usuarios no ser capaces de predecir la secuencia de números aleatorios, entonces usted quiere un generador criptográficamente seguro, no un generador pseudoaleatorio. (Estás loco si haces apuestas con dinero real en un generador pseudoaleatorio.) –

+0

Solo para tu información, con Mersenne twister, tienes que observar 624 cartas consecutivas (12 barajas) antes de conocer todas las cartas futuras. –

0

Quizás prefiera /dev/urandom/ sobre /dev/random. Este último bloquea en Linux si no hay suficiente entropía disponible, lo que puede suceder fácilmente si el programa se ejecuta en una máquina sin interacción del usuario. En caso de que no pueda abrir /dev/urandom, podría lanzar una excepción en lugar de usar un respaldo.

1

generadores "buenos", "Bad generadores" eso no quiere decir nada. "Cualquiera que considere métodos aritméticos para producir dígitos aleatorios está, por supuesto, en estado de pecado". - John von Neumann. Cada generador de este tipo es solo un algoritmo determinista. Es muy importante tener estados iniciales (semilla) que traen suficiente entropía. Dependiendo de lo que necesite, debe probar la calidad de su generador. El método de Monte Carlo es un muy buen estimador de un generador de números pseudoaleatorios.

2

Ok aquí están los cambios que hice después de considerar su entrada. Gracias por todo por cierto!

unsigned int good_seed() 
{ 
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/urandom", std::ios::binary); 
    if (file.is_open()) 
    { 
     char * memblock; 
     int size = sizeof(int); 
     memblock = new char [size]; 
     file.read (memblock, size); 
     file.close(); 
     random_seed_a = *reinterpret_cast<int*>(memblock); 
     delete[] memblock; 
    }// end if 
    else 
    { 
     random_seed_a = 0; 
    } 
    random_seed_b = std::time(0); 
    random_seed = random_seed_a xor random_seed_b; 
    std::cout << "random_seed_a = " << random_seed_a << std::endl; 
    std::cout << "random_seed_b = " << random_seed_b << std::endl; 
    std::cout << " random_seed = " << random_seed << std::endl; 
    return random_seed; 
} // end good_seed() 
Cuestiones relacionadas