c++randomgaussiannormal-distribution

Is there a way to create a 'truer' random outcome using a Gaussian normal distribution in C++?


I've scoured stack overflow for some descriptions, explanations, and snippets of the std::normal_distribution<> variable(mean, stddev) function, and have found one instance in particular, listed below, that works quite effectively for my purpose, which is simply to be able to create and house a random number from a normal distribution given the mean and stddev.

#include <random>
...
std::mt19937 generator;
double mean = 100.0, stddev  = 15.0, example;
std::normal_distribution<double> normal(mean, stddev);
example = normal(generator);
cout << "Normal: " << example << endl;

credit - https://stackoverflow.com/a/11977979/14316685.

The one problem that I"ve run into, however, is that the results from this code become quite repetitive and predicatable over time. For example, I've repeatedly used a mean of 100 and a stddev of 15, which when run over 1000 instances almost assuredly, produces exactly one instance of both approximately 52.246 and 156.86 consistently, at least on my system.

Is there a way to manipulate this code snippet, or seed if I understand this correctly, so that it produces a variety of results that are different enough each time while still obeying the normal distribution?

As I'm still new to this function, I tried utilizing std::default_random_engine generator; in the place of std::mt19937 generator, and while it produced a different result, it had a similar problem of repetition over time.


Solution

  • You're default constructing the generator which means that it will be initialized with the same internal state every time you construct it.

    Running this program would print the same 10 numbers every time you run it:

    #include <iostream>
    #include <random>
    
    int main() {
        std::mt19937 generator;
        
        double mean = 100.0, stddev = 15.0, example;
        std::normal_distribution<double> normal(mean, stddev);
    
        for(int i = 0; i < 10; ++i) {
            example = normal(generator);
            std::cout << "Normal: " << example << '\n';
        }
    }
    

    If you put the instantiation of the generator in the loop, it'll print the same number every time.

    What you need to do is to seed the generator (once), and you can use an instance of std::random_device to get a good seed. It picks a number from an entropy pool (if it exists - which it usually does):

    int main() {
        std::mt19937 generator(std::random_device{}());
        //...
    

    Demo


    If you need access to the generator from multiple places in the program, you can make it global or pass it around by-reference. If threads are involved, you can make it thread_local if you have no other way of separating thread local data.