Why is boost's random number generation (on a

2019-02-24 08:54发布

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)

标签: c++ boost random
3条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-02-24 09:32

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 ;
    }
查看更多
叛逆
3楼-- · 2019-02-24 09:37

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 ;
查看更多
戒情不戒烟
4楼-- · 2019-02-24 09:46

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.

查看更多
登录 后发表回答