11

I'm working on implementing R code into C++ so that it runs faster, but I am having difficulties implementing mersenne twister. I only wish to generate values between (0,1). Here is what I have that pertains to this question.

#include <random>

std::mt19937 generator (123);

std::cout << "Random value: " << generator() << std:: endl;

I tried dividing by RAND_MAX, but that did not produce the values that I was looking for.

Thanks in advance.

yizzlez
  • 8,757
  • 4
  • 29
  • 44
user3508622
  • 113
  • 1
  • 1
  • 4

3 Answers3

21

In C++11 the concepts of "(pseudo) random generator" and "probability distribution" are separated, and for good reasons.

What you want can be achieved with the following lines:

  std::mt19937 generator (123);
  std::uniform_real_distribution<double> dis(0.0, 1.0);

  double randomRealBetweenZeroAndOne = dis(generator);

If you want to understand why this separation is necessary, and why using a standard division /range manipulation on the output of the generator is a bad idea, watch this video.

sbabbi
  • 11,070
  • 2
  • 29
  • 57
  • using a standard division /range manipulation on the output of the generator is not a bad idea per se, this is how we create specific distributions or stochastic processes for random variables – 4pie0 Apr 07 '14 at 21:58
  • and actually, the standard implementations (at least I checked boost) do a simple substraction / division range manipulation. Is this bad? – galinette Apr 07 '14 at 22:03
  • 1
    one day, the stl will provide a class for calculating a percentage. Because dividing by the reference and multiplying by 100 may be harmful. – galinette Apr 07 '14 at 22:05
  • @galinette, Why do you say that it "may be harmful?" – kmiklas Jul 20 '16 at 16:21
  • Will this generate random numbers excluding 0 and 1 or does it include the boundaries 0 and 1?? I want to exclude the values 0 and 1 – Shashank Shekhar Oct 05 '18 at 01:53
  • This will include 0, as explained here : http://www.cplusplus.com/reference/random/uniform_real_distribution/. A quick fix to exclude 0 is to add an if control for whether the number generated is 0, and re-generate when that is the case (which will almost never happen). – GabCaz Jul 11 '20 at 01:14
8

You may want to consider code like this:

// For pseudo-random number generators and distributions
#include <random> 

...
    
// Use random_device to generate a seed for Mersenne twister engine.
std::random_device rd{};    

// Use Mersenne twister engine to generate pseudo-random numbers.
std::mt19937 engine{rd()};

// "Filter" MT engine's output to generate pseudo-random double values,
// **uniformly distributed** on the closed interval [0, 1].
// (Note that the range is [inclusive, inclusive].)
std::uniform_real_distribution<double> dist{0.0, 1.0};

// Generate pseudo-random number.
double x = dist(engine);

For more details on generating pseudo-random numbers in C++ (including reasons why rand() is not good), see this video by Stephan T. Lavavej (from Going Native 2013):

rand() Considered Harmful

Community
  • 1
  • 1
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • I wish there was a oneliner in C++ standard library that one could use for simple cases. just like there is `arc4random_uniform` on BSD machines. – A. K. May 20 '23 at 00:03
2

std::mt19937 does not generate between 0 and RAND_MAX like rand(), but between 0 and 2^32-1

And by the way, the class provides min() and max() values!

You need to convert the value to a double, substract min() and divide by max()-min()

uint32_t val;
val << generator;
double doubleval = ((double)val - generator::min())/(generator::max()-generator::min());

or (less generic)

uint32_t val;
val << generator;
double doubleval = (double)val * (1.0 / std::numeric_limits<std::uint32_t>::max());
galinette
  • 8,896
  • 2
  • 36
  • 87
  • You might want to explain that long double value.. Or replace it with `1.0 / std::numeric_limits::max()` – Brandon Apr 07 '14 at 22:04