3
votes

We have been using boost::random for sometime now in our projects. Recently, a failing test unit got me intrigued about one of its properties: the sequence of numbers generated across different versions of Boost may be different, depending on the used distribution.

This behavior does not seem to be consistent across all distributions. Most of the time, uniform distributions using a RNG with the same seed yield the same results. Other distributions such as normal, lognormal, binomial and discrete may show these differences.

I have put together a simple C++ program that shows the issue:

#include <iostream>
#include <boost/random.hpp>
#include <stdint.h>

void uniform() {
  uint32_t seed = 42;
  boost::mt19937 rng(seed);
  boost::random::uniform_real_distribution<double> distro(0., 1.);
  std::cout << "uniform" << std::endl;
  for (int i=0; i<10; ++i) {
    std::cout << distro(rng) << std::endl;
  }
}

void normal() {
  uint32_t seed = 42;
  boost::mt19937 rng(seed);
  boost::random::normal_distribution<double> distro(0., 1.);
  std::cout << "normal" << std::endl;
  for (int i=0; i<10; ++i) {
    std::cout << distro(rng) << std::endl;
  }
}

void discrete() {
  uint32_t seed = 42;
  boost::mt19937 rng(seed);
  std::vector<double> P;
  P.push_back(0.3);
  P.push_back(0.4);
  P.push_back(0.3);
  boost::random::discrete_distribution<uint64_t> distro(P.begin(), P.end());
  std::cout << "discrete" << std::endl;
  for (int i=0; i<10; ++i) {
    std::cout << distro(rng) << std::endl;
  }
}

int main() {
  uniform();
  normal();
  discrete();
}

This simple program will show different sequences of numbers for Boost 1.56 (running on OSX):

uniform
0.37454
0.796543
0.950714
0.183435
0.731994
0.779691
0.598658
0.59685
0.156019
0.445833
normal
-0.638714
-0.836808
-0.400566
-0.869232
-0.972045
-0.758932
-1.30435
1.22996
0.249399
0.286848
discrete
1
2
2
1
0
0
0
2
1
2

Or with Boost 1.50 (running on Ubuntu 12.10):

uniform
0.37454
0.796543
0.950714
0.183435
0.731994
0.779691
0.598658
0.59685
0.156019
0.445833
normal
-1.25821
1.2655
0.606347
-0.19401
-0.196366
-1.72826
-1.09713
-0.783069
0.604964
0.90255
discrete
2
1
2
1
1
0
1
1
0
1

Notice that the uniform distribution works as expected: i.e., the same seed generates a consistent sequence of numbers on both versions. The normal and discrete distribution do not behave the same.

Is there a way to "fix" this? I.e. have different platforms generate the exact same sequence independently of the boost version?

1
The obvious google query here is "boost bug normal distribution". Tada.Hans Passant
I tried your code on Mac OS X, Boost 1.55, and got the same results as your Ubuntu with Boost 1.50. I was sort of expecting to match your other results! But now we can see from @HansPassant's hint at svn.boost.org/trac/boost/ticket/9513 that this is a bug present up to 1.55 and fixed afterward.John Zwinck
Thanks for both comments and the link. Please note this is not the only problem. I have extended the example so that it shows as well problems with the discrete distribution.André Anjos
Another note: between Boost 1.48 and Boost 1.50, the binomial distribution also presents this issue.André Anjos

1 Answers

2
votes

it seems boost::random does not guarantee that you get the same sequence of numbers for certain seeds with different versions boost.

E.g. in version 1.56 they have changed the algorithm to generate normal distributed random numbers from the Box-Muller method to the Ziggurat method:

https://github.com/boostorg/random/commit/f0ec97ba36c05ef00f2d29dcf66094e3f4abdcde

This method is faster but also produces different number sequences.

Similar changes have probably been done to the other distributions. The uniform distribution still produces the same result as that is typically the output of the base rng which is a mersenne twister 19937 by default.