#include<iostream>
#include <ctime>
#include <cstdlib>
int main()
{
// seed the random number generator with the current system time
srand(time(NULL));
// obtain and display 20 random numbers
for (int i = 0; i < 20; i++)
{
// stores the random number
int numPicked = rand() % 100 + 1; / range 1 - 100
std::cout << numPicked << "\t";
}
std::cout << std::endl;
return 0;
}
#include<iostream>
#include <chrono>
#include <random>
int main()
{
// obtain a seed from the system clock:
unsigned seed = static_cast<int> (std::chrono::system_clock::now().time_since_epoch().count());
// seeds the random number engine, the mersenne_twister_engine
std::mt19937 generator(seed);
// set a distribution range (1 - 100)
std::uniform_int_distribution<int> distribution(1, 100);
// obtain and display 20 random numbers
for (int i = 0; i < 20; i++)
{
// stores the random number
int numPicked = distribution(generator);
std::cout << numPicked << "\t";
}
std::cout << std::endl;
return 0;
}
Did I miss anything that would improve the code? Would the linear_congruential_engine be a better engine choice?
I seem to recall a while back someone explaining (or linking to a discussion) why using the C++ <random> library gave better distribution on random number distribution versus using the C library srand()/rand() functions.
I did more than a few searches, here and the full internet, for such and I can't seem to find anything.
Do you know of any online resource that explains simply why using the C++ library is the best method for new code?
I am soon to write the FAQ on <random>, but the simple answer is that rand() stinks.
The main problem for distribution is that people don't know how to properly get a random number from rand() -- there is no magic library code to do it for you -- and most people get it Wrong.
The next is that rand's range is often significantly smaller than you want it to be.
If you want to get technical, rand() implementations tend to favor lower bits, which leads to biased numbers.
The C++ <random> library gives you much more powerful PRNGs with a lot of built-in ways to draw numbers from them without bias.
The most difficult thing to do is seed it properly. Unfortunately, people still depend on the clock -- which is a mistake, but acceptable for video games and the like -- anything that doesn't require statistical correctness (like Monte Carlo simulations and the like).
You need to warm up your Mersenne Twister. generator.discard(10000) or so.
Unfortunately, random_device is specified to possibly throw just about anytime you look at it. You must use it carefully.
If your STL is broken, use Boost's. Most modern OSs provide a TRNG that is appropriate for generating a proper seed sequence. (That is, don't just seed with a single integer. Pull from the TRNG. Or, as has been written elsewhere, "use /dev/urandom, use /dev/urandom, use /dev/urandom!" [if I remember the quote correctly].)
Seed your PRNGs with a full state pulled from the TRNG -- which random_device will use. Only if you cannot get the TRNG/CSPRNG to work should you fall back on the system's high-resolution time or quit, depending on the security requirements of your application.
#include <iostream>
#include <random>
#include <chrono>
#include <algorithm>
std::mt19937 initialize_twister(std::size_t seed = std::chrono::system_clock::now().time_since_epoch().count())
{
staticconstexpr std::size_t NUM_DISCARD = 10240;
std::minstd_rand lcg(seed);
lcg.discard(NUM_DISCARD);
std::size_t seeds[std::mt19937::state_size];
std::generate_n(seeds, std::mt19937::state_size, lcg);
try
{
// check if there is a random_device available
seeds[0] = std::random_device {}();
}
catch (const std::exception&)
{
/* ignore */
}
std::seed_seq seed_sequence(std::begin(seeds), std::end(seeds));
return std::mt19937 {seed_sequence}; // warm-up with seed seed_sequence.generate()
// return seed_sequence;
}
int main()
{
std::mt19937 generator = initialize_twister();
// set a distribution range (1 - 100)
std::uniform_int_distribution<int> distribution(1, 100);
// obtain and display 50 random numbers
for (int i = 0; i < 50; i++)
{
// stores the random number
int numPicked = distribution(generator);
std::cout << numPicked << "\t";
}
std::cout << std::endl;
return 0;
}
Little bit by little bit I'm hopefully getting a grasp on what C++ brings to the toolbox with random number generation. My brain is stuffed to overflow at the moment. ;)