As a complete beginner to C++, I would like to generate a random number from a normal distribution.
With the following code (derived from this post), I am able to d
(1) Why is that happing and how do I fix this?
It's happening because you default construct your PRNG (pseudo random number generator) and don't seed it. A PRNG generates a deterministic sequence of numbers. The sequence is typically very long and then it starts all over again. The seed is used to set the internal state of the PRNG - its starting point so to speak. Given no seed, it'll start with the same state every time.
(2) Is there another easier way to generate random numbers?
No, not using modern standard C++ (C++11 and later).
Some notes:
std::mt19937& prng() { // extern declared in a header file
static thread_local std::mt19937 gen(std::random_device{}());
return gen;
}
If your random_device
lacks entropy or is buggy (older versions of MinGW had a buggy implementation) you can combine random_device
output with a few time based numbers (sampled some time apart) to create a std::seed_seq that you use to initialize your PRNG. The below should work with both buggy and conformant implementations to create a seed that is hard to predict:
#include <chrono>
#include <thread>
// Create a seed_seq with 2 time based numbers and 2 random_device numbers.
// The two sleeps are done to ensure some diff in the clock counts.
static std::seed_seq get_seed() {
static constexpr auto min = std::chrono::steady_clock::duration::min();
std::random_device rd;
std::uint_least32_t si[4];
for(size_t s = 0; s < std::size(si);) {
si[s++] = rd();
std::this_thread::sleep_for(min);
si[s++] = static_cast<std::uint_least32_t>(
std::chrono::steady_clock::now().time_since_epoch().count());
std::this_thread::sleep_for(min);
}
return {si[0], si[1], si[2], si[3]};
}
std::mt19937& prng() { // extern declared in a header file
static thread_local std::seed_seq seed = get_seed();
static thread_local std::mt19937 gen(seed);
return gen;
}
Use a seed to initialize your generator
. Here I am using a time-based seed.
#include <iostream>
#include <random>
#include <chrono>
using namespace std;
int main()
{
unsigned seed = chrono::system_clock::now().time_since_epoch().count();
default_random_engine generator(seed);
normal_distribution<double> distribution(0.0, 1.0);
cout << distribution(generator);
return 0;
}