repetir rango randomize rand numeros libreria generar funcion arreglo aleatorios c++ random get seed

rango - libreria random c++



¿Cómo obtener la semilla actual de C++ rand()? (8)

Genero unos pocos miles de objetos en mi programa basados ​​en la función C ++ rand () . Mantenerlos en la memoria sería exhaustivo. ¿Hay alguna forma de copiar la semilla CURRENT de rand () en un momento dado? Esto me daría la oportunidad de almacenar SÓLO las semillas actuales y no los objetos completos. (así podría regenerar esos objetos, regenerando exactamente las mismas subsecuencias de números aleatorios)

Una solución exhaustiva es almacenar la secuencia completa de números aleatorios dados por rand () : no vale la pena. Otra solución sería implementar mi propia clase para números aleatorios.

Google no me dio pistas positivas. Hay cientos de artículos que enseñan los conceptos básicos de rand y srand, y no pude encontrar los específicos.

¿Alguien conoce otros generadores de números aleatorios con robo de semillas implementado?

¡Gracias por tus respuestas rápidas! Hay más respuestas / soluciones posibles a esta pregunta, así que hice una lista de sus respuestas aquí.

SOLUCIONES:

  1. La respuesta corta es: no hay una forma estándar de obtener la semilla

  2. La solución más cercana posible es guardar la semilla INICIAL al principio, y contar cuántas veces llama a la función rand (). Marqué esto como una solución porque funciona en la función actual std :: rand () de cada compilador (y esta fue la pregunta principal). Hice una evaluación comparativa de mi CPU de 2.0 GHz, y descubrí que puedo llamar y contar rand () 1,000,000,000 de veces en 35 segundos. Esto puede sonar bien, pero tengo 80,000 llamadas para generar un objeto. Esto restringe la cantidad de generaciones a 50,000 porque el tamaño de la longitud sin firmar. De todos modos, aquí está mi código:

    class rand2 { unsigned long n; public: rand2 () : n(0) {} unsigned long rnd() { n++; return rand(); } // get number of rand() calls inside this object unsigned long getno () { return n; } // fast forward to a saved position called rec void fast_forward (unsigned long rec) { while (n < rec) rnd(); } };

  3. Otra forma es implementar su propio generador de números pseudoaleatorios, como el sugerido por Matteo Italia. Esta es la solución más rápida y posiblemente la MEJOR. No está restringido a 4,294,967,295 llamadas rand () , y tampoco necesita usar otras bibliotecas. Vale la pena mencionar que los diferentes compiladores tienen diferentes generadores. He comparado el LCG de Matteo con rand () en Mingw / GCC 3.4.2 y G ++ 4.3.2. Los 3 de ellos fueron diferentes (con semilla = 0 ).

  4. Use generadores de C ++ 11 u otras bibliotecas como lo sugirieron Cubbi, Jerry Coffin y Mike Seymour. Esta es la mejor idea, si ya está trabajando con ellos. Enlace para generadores C ++ 11: http://en.cppreference.com/w/cpp/numeric/random (aquí también hay algunas descripciones de algoritmos)


¿Alguien conoce otros generadores de números aleatorios con robo de semillas implementado?

Todos los generadores de números aleatorios C ++ 11 estándar (también disponibles en TR1 y en Boost) ofrecen esta funcionalidad. Simplemente puede copiar los objetos del generador o serializarlos / deserializarlos.


Las clases de generación de números aleatorios en C ++ 11 soportan el operator<< para almacenar su estado (principalmente la semilla) y el operator>> para volver a leerlo. Entonces, básicamente, antes de crear sus objetos, guarde el estado, entonces cuando necesita volver a generar la misma secuencia, leer el estado de nuevo y listo.


No hay una forma estándar de obtener la semilla actual (solo puede establecerla a través de srand ), pero puede volver a implementar rand() (que generalmente es un generador congruente lineal ) usted mismo en unas pocas líneas de código:

class LCG { private: unsigned long next = 1; public: LCG(unsigned long seed) : next(seed) {} const unsigned long rand_max = 32767 int rand() { next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768; } void reseed(unsigned long seed) { next = seed; } unsigned long getseed() { return next; } };


Podría intentar guardar el valor que utilizó para sembrar justo antes (o después) del srand.

Así por ejemplo:

int seed = time(NULL); srand(time(NULL)); cout << seed << endl; cout << time(NULL);

Los dos valores deben ser iguales.



rand() no ofrece ninguna forma de extraer o duplicar la semilla. Lo mejor que puede hacer es almacenar el valor inicial de la semilla cuando la establece con srand() , y luego reconstruir toda la secuencia a partir de eso.

La función de Posix rand_r() le da el control de la semilla.

La biblioteca C ++ 11 incluye una biblioteca de números aleatorios basada en "motores" de generación de secuencias; estos motores se pueden copiar y permiten que su estado se extraiga y restaure con los operadores << y >> , de modo que pueda capturar el estado de una secuencia en cualquier momento. Bibliotecas muy similares están disponibles en TR1 y Boost, si aún no puede usar C ++ 11.


Te recomendaría usar el generador de números pseudoaleatorios de Mersenne Twister . Es rápido y ofrece números aleatorios muy buenos. Puedes sembrar el generador en el constructor de la clase muy simplemente

unsigned long rSeed = 10; MTRand myRandGen(rSeed);

Entonces solo necesitas almacenar en alguna parte las semillas que usaste para generar las secuencias ...


¿Hay alguna forma de copiar la semilla CURRENT de rand () en un momento dado?

Lo que sigue es una forma específica de implementación para guardar y restaurar el estado del generador de números pseudoaleatorios (PRNG) que funciona con la biblioteca C en Ubuntu Linux (probado en 14.04 y 16.04).

#include <array> #include <cstdlib> #include <iostream> using namespace std; constexpr size_t StateSize = 128; using RandState = array<char, StateSize>; void save(RandState& state) { RandState tmpState; char* oldState = initstate(1, tmpState.data(), StateSize); copy(oldState, oldState + StateSize, state.data()); setstate(oldState); } void restore(RandState& state) { setstate(state.data()); } int main() { cout << "srand(1)/n"; srand(1); cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << "srand(1)/n"; srand(1); cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << "save()/n"; RandState state; save(state); cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << "restore()/n"; restore(state); cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; cout << " rand(): " << rand() << ''/n''; }

Esto se basa en:

  1. el mismo PRNG utilizado por la biblioteca C para exponer las interfaces rand() y al random() , y
  2. algún conocimiento sobre la inicialización predeterminada de este PRNG en la biblioteca C (estado de 128 bytes).

Si se ejecuta, esto debería dar como resultado:

srand(1) rand(): 1804289383 rand(): 846930886 rand(): 1681692777 rand(): 1714636915 rand(): 1957747793 rand(): 424238335 rand(): 719885386 rand(): 1649760492 srand(1) rand(): 1804289383 rand(): 846930886 rand(): 1681692777 rand(): 1714636915 save() rand(): 1957747793 rand(): 424238335 rand(): 719885386 rand(): 1649760492 restore() rand(): 1957747793 rand(): 424238335 rand(): 719885386 rand(): 1649760492

Esta solución puede ayudar en algunos casos (código que no se puede cambiar, reproducir la ejecución para fines de depuración, etc.), pero obviamente no se recomienda como una general (por ejemplo, usar C ++ 11 PRNG que respalde adecuadamente esto )