zebra
zebra

Reputation: 6531

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)

Upvotes: 4

Views: 3970

Answers (3)

YvesgereY
YvesgereY

Reputation: 3888

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 ;

Upvotes: 0

jerry
jerry

Reputation: 2611

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.

Upvotes: 8

Shafik Yaghmour
Shafik Yaghmour

Reputation: 158469

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

Upvotes: 1

Related Questions