Remarqué todas las cosas anteriores, otras 40 páginas con c ++ como esta y vi el video de Stephan T. Lavavej "STL"
y todavía no estaba seguro de cómo funcionan los números aleatorios en la praxis, así que me tomé un domingo completo para descubrir de qué se trata y cómo funciona y se puede utilizar.
En mi opinión, STL tiene razón sobre "no usar srand nunca más" y lo explicó bien en el video 2 . También recomienda usar:
a) void random_device_uniform()
- para la generación encriptada pero más lenta (de mi ejemplo)
b) los ejemplos con mt19937
- más rápido, capacidad de crear semillas, no encriptado
Saqué todos los libros de c ++ 11 reclamados a los que tengo acceso y encontré que los autores alemanes como Breymann (2015) todavía usan un clon de
srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or
solo con en <random>
lugar de <time> and <cstdlib>
#incluidos, así que tenga cuidado de aprender solo de un libro :).
Significado: eso no debería usarse desde c ++ 11 porque:
Los programas a menudo necesitan una fuente de números aleatorios. Antes del nuevo estándar, tanto C como C ++ dependían de una función de biblioteca C simple llamada rand. Esa función produce enteros pseudoaleatorios que se distribuyen uniformemente en el rango de 0 a un valor máximo dependiente del sistema que es al menos 32767. La función rand tiene varios problemas: muchos, si no la mayoría, los programas necesitan números aleatorios en un rango diferente del uno producido por rand. Algunas aplicaciones requieren números aleatorios de punto flotante. Algunos programas necesitan números que reflejen una distribución no uniforme. Los programadores a menudo introducen la no aleatoriedad cuando intentan transformar el rango, el tipo o la distribución de los números generados por rand. (cita de Lippmans C ++ primer quinta edición 2012)
Finalmente encontré la mejor explicación de 20 libros en los más nuevos de Bjarne Stroustrups, y él debería saber sus cosas, en "Un recorrido por C ++ 2019", "Principios y práctica de programación usando C ++ 2016" y "El lenguaje de programación C ++ 4ta edición 2014 "y también algunos ejemplos en" Lippmans C ++ primer quinta edición 2012 ":
Y es realmente simple porque un generador de números aleatorios consta de dos partes:
(1) un motor que produce una secuencia de valores aleatorios o pseudoaleatorios. (2) una distribución que mapea esos valores en una distribución matemática en un rango.
A pesar de la opinión del chico de Microsofts STL, Bjarne Stroustrups escribe:
En, la biblioteca estándar proporciona distribuciones y motores de números aleatorios (§24.7). Por defecto, use default_random_engine, que se elige por su amplia aplicabilidad y bajo costo.
El void die_roll()
ejemplo es de Bjarne Stroustrups: buena idea para generar motor y distribución con using
(más sobre eso aquí) .
Para poder hacer un uso práctico de los generadores de números aleatorios proporcionados por la biblioteca estándar <random>
aquí, algunos códigos ejecutables con diferentes ejemplos se reducen a los menos necesarios que con suerte ahorren tiempo y dinero para ustedes:
#include <random> //random engine, random distribution
#include <iostream> //cout
#include <functional> //to use bind
using namespace std;
void space() //for visibility reasons if you execute the stuff
{
cout << "\n" << endl;
for (int i = 0; i < 20; ++i)
cout << "###";
cout << "\n" << endl;
}
void uniform_default()
{
// uniformly distributed from 0 to 6 inclusive
uniform_int_distribution<size_t> u (0, 6);
default_random_engine e; // generates unsigned random integers
for (size_t i = 0; i < 10; ++i)
// u uses e as a source of numbers
// each call returns a uniformly distributed value in the specified range
cout << u(e) << " ";
}
void random_device_uniform()
{
space();
cout << "random device & uniform_int_distribution" << endl;
random_device engn;
uniform_int_distribution<size_t> dist(1, 6);
for (int i=0; i<10; ++i)
cout << dist(engn) << ' ';
}
void die_roll()
{
space();
cout << "default_random_engine and Uniform_int_distribution" << endl;
using my_engine = default_random_engine;
using my_distribution = uniform_int_distribution<size_t>;
my_engine rd {};
my_distribution one_to_six {1, 6};
auto die = bind(one_to_six,rd); // the default engine for (int i = 0; i<10; ++i)
for (int i = 0; i <10; ++i)
cout << die() << ' ';
}
void uniform_default_int()
{
space();
cout << "uniform default int" << endl;
default_random_engine engn;
uniform_int_distribution<size_t> dist(1, 6);
for (int i = 0; i<10; ++i)
cout << dist(engn) << ' ';
}
void mersenne_twister_engine_seed()
{
space();
cout << "mersenne twister engine with seed 1234" << endl;
//mt19937 dist (1234); //for 32 bit systems
mt19937_64 dist (1234); //for 64 bit systems
for (int i = 0; i<10; ++i)
cout << dist() << ' ';
}
void random_seed_mt19937_2()
{
space();
cout << "mersenne twister split up in two with seed 1234" << endl;
mt19937 dist(1234);
mt19937 engn(dist);
for (int i = 0; i < 10; ++i)
cout << dist() << ' ';
cout << endl;
for (int j = 0; j < 10; ++j)
cout << engn() << ' ';
}
int main()
{
uniform_default();
random_device_uniform();
die_roll();
random_device_uniform();
mersenne_twister_engine_seed();
random_seed_mt19937_2();
return 0;
}
Creo que eso lo suma todo y, como dije, me tomó un montón de lectura y tiempo para destilarlo a esos ejemplos; si tiene más información sobre la generación de números, me alegra escuchar eso a través de la tarde o en la sección de comentarios y lo agregará si es necesario o editará esta publicación. Bool