简体   繁体   中英

Why is boost's random number generation (on a normal distribution) always giving the same values?

I am doing some random number generation and getting fishy behaviour. Here is my code:

    // initialized earlier... in the constructor of a class
    boost::mt19937 *rng = new boost::mt19937();
    rng->seed(time(NULL));

    // actual use here.
    for (int i = 0; i < 10; ++i)
    {
        test();
    }


    void test()
    {
       boost::normal_distribution<> distribution(10, 10);
       boost::variate_generator< boost::mt19937, boost::normal_distribution<> > resampler(*rng, distribution);

       const double sample = (resampler)(); // always the same value.
    }

Am I misusing the random sampling in boost? What have I done wrong to make that always be the same value. I initialize the random number generator in the constructor so it should always spit out a different value (not getting reinitialized)

The problem is with the line boost::variate_generator< boost::mt19937, boost::normal_distribution<> > resampler(*rng, distribution); . This constructor take its parameters by value (see the documentation ). So each resampler starts off with an identical copy of the generator and calls it once.


Edit: Shafik noticed the same thing just a little after I did. If you really can't hoist the initialization out of the loop, you can also re-seed the generator. There are many ways to accomplish this depending on your application. Below is just one example:

void test()
{
   static unsigned int seed = 0
   rng->seed((++seed) + time(NULL));

   boost::normal_distribution<> distribution(10, 10);
   boost::variate_generator< boost::mt19937, boost::normal_distribution<> > resampler(*rng, distribution);

   const double sample = (resampler)(); // always the same value.
}

Note: do not re-seed rng with just time(NULL) , as that may return the same value several times if you call test() in a tight loop.

It is because you are instantiating the class in the function test if you move them outside then it works as expected. You are starting off each instance with the same generator. see this minimal case:

int main()
{
    boost::mt19937 *rng2 = new boost::mt19937();
    rng2->seed(time(NULL));

    boost::normal_distribution<> distribution(0, 1);
    boost::variate_generator< boost::mt19937, boost::normal_distribution<> >        resampler(*rng2, distribution);

    for (int i = 0; i < 10; ++i)
    {
        std::cout << resampler() << std::endl ;
    }
}

If you change the loop to work like your posted code then you see the same problem:

    for (int i = 0; i < 10; ++i)
    {
        boost::normal_distribution<> distribution(0, 1);
        boost::variate_generator< boost::mt19937, boost::normal_distribution<> >        resampler(*rng2, distribution);

        std::cout << resampler() << std::endl ;
    }

The 'why' has been addressed in other answers. Here is how to fix it without re-seeding (which defeat the point of using a generator) : initialize normal_distribution and variate_generator once, together with mt19937 .

In your class, take care of defining theses members in the proper order.

As a side note, 'new' is useless, you could simply write :

boost::mt19937 rng ;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM