usar - ¿Cómo puedo generar un número aleatorio usando la biblioteca estándar C++ 11?
randomize en c (7)
El nuevo estándar C ++ 11 tiene un capítulo completo dedicado a generadores de números aleatorios. Pero, ¿cómo realizo la tarea más simple y común que solía codificarse así, pero sin recurrir a la biblioteca C estándar?
srand((unsigned int)time(0)); int i = rand();
¿Existen valores predeterminados razonables para motores, distribuciones y semillas de números aleatorios que se podrían usar de manera predeterminada?
Aqui tienes. Doble aleatorio en un rango:
// For ints
// replace _real_ with _int_,
// <double> with <int> and use integer constants
#include <random>
#include <iostream>
#include <ctime>
#include <algorithm>
#include <iterator>
int main()
{
std::default_random_engine rng(std::random_device{}());
std::uniform_real_distribution<double> dist(-100, 100); //(min, max)
//get one
const double random_num = dist(rng);
//or..
//print 10 of them, for fun.
std::generate_n(
std::ostream_iterator<double>(std::cout, "/n"),
10,
[&]{ return dist(rng);} );
return 0;
}
Debería poder hacer algo como:
std::default_random_engine e((unsigned int)time(0));
int i = e();
La calidad de default_random_engine
depende de la implementación. También puede usar std::min_rand0
o std::min_rand
.
Probablemente, una mejor forma de generar un motor aleatorio sea con un número aleatorio tan real como esté disponible a partir de la implementación en lugar del time
uso.
P.ej
std::random_device rd;
std::default_random_engine e( rd() );
La generación de números aleatorios es un problema difícil. No hay una manera verdaderamente aleatoria de hacerlo. Si solo estás generando aleatoriedad para sembrar un entorno de juego, entonces tu enfoque debería estar bien. rand () tiene varias deficiencias.
Si necesita aleatoriedad para generar claves de cifrado, entonces es SOL. La mejor manera en ese caso es ir al sistema operativo, que generalmente tiene un mecanismo. En POSIX eso es aleatorio () (o lea desde / dev / random si está dispuesto). En Windows puede usar CryptoAPI:
Puede usar RC4 para generar bytes aleatorios. Esto probablemente tiene las propiedades que desea. Es rápido y bastante simple de implementar. La secuencia es repetible en todas las implementaciones cuando se conoce la semilla, y es completamente impredecible cuando se desconoce la semilla. http://en.wikipedia.org/wiki/RC4
Si su código actual era apropiado antes del nuevo estándar, entonces seguirá siéndolo. Los nuevos generadores de números aleatorios se agregaron para aplicaciones que requieren una mayor calidad de pseudoaleatoriedad, por ejemplo, simulación estocástica.
Unificando y simplificando algunas de las muestras ya provistas resumiré a:
// Good random seed, good engine
auto rnd1 = std::mt19937(std::random_device{}());
// Good random seed, default engine
auto rnd2 = std::default_random_engine(std::random_device{}());
// like rnd1, but force distribution to int32_t range
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));
// like rnd3, but force distribution across negative numbers as well
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));
Luego realicé algunas pruebas para ver cómo son los valores predeterminados:
#include <random>
#include <functional>
#include <limits>
#include <iostream>
template<class Func>
void print_min_mean_max(Func f) {
typedef decltype(f()) ret_t;
ret_t min = std::numeric_limits<ret_t>::max(), max = std::numeric_limits<ret_t>::min();
uint64_t total = 0, count = 10000000;
for (uint64_t i = 0; i < count; ++i) {
auto res = f();
min = std::min(min,res);
max = std::max(max,res);
total += res;
}
std::cout << "min: " << min << " mean: " << (total/count) << " max: " << max << std::endl;
}
int main() {
auto rnd1 = std::mt19937(std::random_device{}());
auto rnd2 = std::default_random_engine(std::random_device{}());
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));
print_min_mean_max(rnd1);
print_min_mean_max(rnd2);
print_min_mean_max(rnd3);
print_min_mean_max(rnd4);
}
Produce el resultado:
min: 234 mean: 2147328297 max: 4294966759
min: 349 mean: 1073305503 max: 2147483423
min: 601 mean: 1073779123 max: 2147483022
min: -2147481965 mean: 178496 max: 2147482978
Como podemos ver, mt19937 y default_random_engine tienen un rango predeterminado diferente, por lo que se recomienda usar uniform_int_distribution.
Además, el valor predeterminado uniform_int_distribution es [0, max_int] (no negativo), incluso cuando se usa un tipo de entero con signo. Debe proporcionar el rango explícitamente si desea un rango completo.
Finalmente, es importante recordar esto en momentos como estos.
Uso el siguiente código en mi proyecto. ''motor'' y ''distribución'' pueden ser uno de los proporcionados por la biblioteca.
#include <random>
#include <functional>
#include <iostream>
...
std::uniform_int_distribution<unsigned int> unif;
std::random_device rd;
std::mt19937 engine(rd());
std::function<unsigned int()> rnd = std::bind(unif, engine);
std::cout << rnd() << ''/n'';