Random number from normal distribution in C++

南楼画角 提交于 2020-12-26 07:26:27

问题


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 do so:

#include <iostream>   
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>

using namespace std;

int main()
{
    boost::mt19937 rng(std::time(0)+getpid());
    boost::normal_distribution<> nd(0.0, 1.0);
    boost::variate_generator<boost::mt19937&,
                             boost::normal_distribution<> > rnorm(rng, nd);

    cout<< rnorm();
  return 0;
}

Since the code is quite elaborate (in my view), I thought that there might be a more straightforward solution:

#include <iostream>
#include <random>

using namespace std;

int main()
{   
    default_random_engine generator;
    normal_distribution<double> distribution(0.0,1.0);

    cout << distribution(generator);
    return 0;
}

While I can generate a random number, it is continuously the same number. That leads to two questions:

(1) Why is that happing and how do I fix this?

(2) Is there another easier way to generate random numbers?


回答1:


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;
}



回答2:


(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:

  • Using a time based seed based on a one-shot sample of the clock is considered bad since you risk seeding two PRNG:s with the same value.
  • You only need one PRNG (per thread that needs to generate random numbers) in you program - and seeding a PRNG is considered costly (in terms of speed). You could therefore make the generator global so it can be used everywhere in the program. The below is a thread safe version, initialized with what is supposed to be a True (but slow) RNG, generating numbers from an entropy pool, std::random_device.
    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;
    }
    


来源:https://stackoverflow.com/questions/60721093/random-number-from-normal-distribution-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!