Estoy haciendo ejercicio al azar de la biblioteca, nuevo para C++11. Escribí el siguiente programa mínimo:

#include <iostream>
#include <random>
using namespace std;
int main() {
    default_random_engine eng;
    uniform_real_distribution<double> urd(0, 1);
    cout << "Uniform [0, 1): " << urd(eng);
}

Cuando ejecuto esto en repetidas ocasiones se le da el mismo resultado cada vez:

>a
Uniform [0, 1): 0.131538
>a
Uniform [0, 1): 0.131538
>a
Uniform [0, 1): 0.131538

Me gustaría tener el programa conjunto de la semilla de manera diferente cada vez que es llamada, por lo que un número aleatorio diferente se genera cada vez. Soy consciente de que al azar proporciona una utilidad llamada seed_seq, pero me parece que la explicación de la misma (en cplusplus.com totalmente oscuro:

http://www.cplusplus.com/reference/random/seed_seq/

Agradecería consejos sobre cómo tener un programa de generar una semilla nueva, cada vez que se llama: La más simple es la mejor.

Mi plataforma(s):

InformationsquelleAutor Argent | 2015-12-28

2 Comentarios

  1. 10

    El punto de tener un seed_seq es aumentar la entropía de la secuencia generada. Si usted tiene un random_device en su sistema, inicializar con varios números desde que dispositivo aleatorio podría hacer eso. En un sistema que tiene un generador de números pseudoaleatorios no creo que hay un aumento de la aleatoriedad, es decir, genera la secuencia de la entropía.

    Edificio en que su enfoque:

    Si su sistema no proporciona un dispositivo aleatorio, a continuación, se puede utilizar como esto:

      std::random_device r;
      //std::seed_seq ssq{r()};
      //and then passing it to the engine does the same
      default_random_engine eng{r()};
      uniform_real_distribution<double> urd(0, 1);
      cout << "Uniform [0, 1): " << urd(eng);

    Si su sistema no dispone de un dispositivo aleatorio, a continuación, puede utilizar time(0) como semilla para la random_engine

      default_random_engine eng{static_cast<long unsigned int>(time(0))};
      uniform_real_distribution<double> urd(0, 1);
      cout << "Uniform [0, 1): " << urd(eng);

    Si usted tiene múltiples fuentes de aleatoriedad en realidad se puede hacer esto (por ejemplo, 2)

    std::seed_seq seed{ r1(), r2() };
      default_random_engine eng{seed};
      uniform_real_distribution<double> urd(0, 1);
      cout << "Uniform [0, 1): " << urd(eng);

    donde r1 , r2 son aleatorios diferentes dispositivos , por ejemplo, un el ruido térmico o fuente cuántica .

    Por supuesto, usted puede mezclar y combinar

    std::seed_seq seed{ r1(), static_cast<long unsigned int>(time(0)) };
      default_random_engine eng{seed};
      uniform_real_distribution<double> urd(0, 1);
      cout << "Uniform [0, 1): " << urd(eng);

    Por último, me gustaría inicializar con un uno forro:

      auto rand = std::bind(std::uniform_real_distribution<double>{0,1},
                  std::default_random_engine{std::random_device()()});
      std::cout << "Uniform [0,1): " << rand();

    Si usted se preocupa por el time(0) tener segunda precisión se puede superar esta jugando con el high_resolution_clock o que pida que el tiempo desde la época como designado en primer lugar por bames23 a continuación:

    static_cast<long unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()) 

    o tal vez sólo jugar con la CPU aleatoriedad

    long unsigned int getseed(int const K)
    {
    
        typedef std::chrono::high_resolution_clock hiclock;
    
        auto gett= [](std::chrono::time_point<hiclock> t0)
        {
            auto tn = hiclock::now();
            return static_cast<long unsigned int>(std::chrono::duration_cast<std::chrono::microseconds>(tn-t0).count());
        };
    
        long unsigned int diffs[10];
        diffs[0] = gett(hiclock::now());
        for(int i=1; i!=10; i++)
        {
            auto last = hiclock::now();
            for(int k=K; k!=0; k--)
            {
                diffs[i]= gett(last);
            }
        }
    
        return *std::max_element(&diffs[1],&diffs[9]);
    }
    • Gracias, g241. Después de modificar la inicialización de default_random_engine para incluir una llamada a la vez(0) la salida del programa es no determinista.
    • AFAIK en Windows no hay azar motor , el tiempo(0) inicializa la semilla a la actual con la segunda precisión, por lo que las siguientes son las pistas sembradas de manera diferente y lograr su objetivo . Un segundo es su granularidad. si la respuesta resuelve tu problema por favor acepte.
    • Windows absolutamente tiene un azar del motor; de forma predeterminada, utiliza rand_s (), que usa RtlGenRandom, lo que pone en advapi32.dll para generar bastante buenos números aleatorios (sin el costo de ir todo el camino a crypto.)
    • Sospecho g24l es el pensamiento de un problema con MinGW, que, al menos en Windows, es la producción de un 100% repetible, determinista número de secuencia (a partir de 2017, ni idea de si/cuando se fija). MSVC proporciona una útil al azar motor, y tales características están disponibles en Windows en general, pero la libstdc++ MinGW utiliza ni siquiera de intentar utilizarlo.
    • Los amigos no dejan que sus amigos el uso de MinGW. Visual Studio es una descarga gratuita. La fijación de las advertencias VS considera que g++ no, es bueno para tu código!
  2. 6
    #include <iostream>
    #include <random>
    
    using namespace std;
    
    int main() {
        std::random_device r;                                       //1
        std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()}; //2
        std::mt19937 eng(seed);                                     //3
    
        uniform_real_distribution<double> urd(0, 1);
    
        cout << "Uniform [0, 1): " << urd(eng);
    }

    Con el fin de obtener resultados impredecibles a partir de un generador de números pseudoaleatorios
    necesitamos una fuente de impredecible de la semilla de datos. En 1 creamos un
    std::random_device para este propósito. En
    2 utilizamos un std::seed_seq para combinar
    varios valores producidos por random_device en una forma conveniente para la siembra de una
    generador de números pseudoaleatorios. El más impredecible de los datos que se introducen en
    el seed_seq, el menos predecible de los resultados de los cabezas de serie de motor
    ser. En 3 podemos crear un número aleatorio motor usando la seed_seq a la semilla de la
    el motor inicial del estado.

    Un seed_seq puede ser utilizado para inicializar varias aleatorio de los motores;
    seed_seq producirá la misma semilla de datos cada vez que se utiliza.

    Nota: No todos los implemenations proporcionar una fuente de no-determinista de datos.
    Verificación de la implementación de la documentación para std::random_device.


    Si la plataforma no proporcionar un no-determinista random_device, a continuación, algunas otras fuentes puede ser utilizado para la siembra. El artículo Simple Portátil de C++ de la Semilla de la Entropía sugiere un número de fuentes alternativas:

    • Una alta resolución reloj tales como std::chrono::high_resolution_clock ( time() , normalmente, tiene una resolución de un segundo que por lo general, demasiado baja)
    • La configuración de la memoria que en la moderna OSs varía debido a la selección aleatoria del diseño del espacio de direcciones (ASLR)
    • CPU contadores o generadores de números aleatorios. C++ no proporciona estandarizar el acceso a estos así que no voy a usar ellos.
    • identificador de subproceso
    • Un simple contador (que sólo importa si se siembra más de una vez)

    Por ejemplo:

    #include <chrono>
    #include <iostream>
    #include <random>
    #include <thread>
    #include <utility>
    
    using namespace std;
    
    //we only use the address of this function
    static void seed_function() {}
    
    int main() {
        //Variables used in seeding
        static long long seed_counter = 0;
        int var;
        void *x = std::malloc(sizeof(int));
        free(x);
    
        std::seed_seq seed{
            //Time
            static_cast<long long>(std::chrono::high_resolution_clock::now()
                                       .time_since_epoch()
                                       .count()),
            //ASLR
            static_cast<long long>(reinterpret_cast<intptr_t>(&seed_counter)),
            static_cast<long long>(reinterpret_cast<intptr_t>(&var)),
            static_cast<long long>(reinterpret_cast<intptr_t>(x)),
            static_cast<long long>(reinterpret_cast<intptr_t>(&seed_function)),
            static_cast<long long>(reinterpret_cast<intptr_t>(&_Exit)),
            //Thread id
            static_cast<long long>(
                std::hash<std::thread::id>()(std::this_thread::get_id())),
            //counter
            ++seed_counter};
    
        std::mt19937 eng(seed);
    
        uniform_real_distribution<double> urd(0, 1);
    
        cout << "Uniform [0, 1): " << urd(eng);
    }
    • Puede agregar más comentarios en el código para ampliar un poco más ? 🙂
    • bames53: he compilado y ejecutar su código. Debo seguir para obtener una salida determinista, es decir, el mismo cada vez. Puede ser que mi plataforma es un problema. Es de Windows 7, y estoy runninging el TDM-compilador GCC.
    • El problema es que libstdc++ en Windows vuelve a caer en el determinismo de la aplicación. Aún no lo han intentado enlazar con el Windows’ OS instalaciones para no-determinismo (y, por supuesto, Windows no dar las facilidades que libstdc++ utiliza en *nix plataformas). Si se construye el programa con VS2015 o con gcc en Linux, usted obtendrá la no-repitió resultados. Si desea continuar con el uso de gcc en Windows, entonces usted tendrá que reemplazar random_device con algo como el uso de CryptoAPI de Windows.

Dejar respuesta

Please enter your comment!
Please enter your name here