tags:

views:

1461

answers:

7

How do you generate a random double uniformly distributed between 0 and 1 from C++?

Of course I can think of some answers, but I'd like to know what the standard practice is, to have:

  • Good standards compliance
  • Good randomness
  • Good speed

(speed is more important than randomness for my application).

Thanks a lot!

PS: In case that matters, my target platforms are Linux and Windows.

+5  A: 

An old school solution like:

double X=((double)rand()/(double)RAND_MAX);

Should meet all your criteria (portable, standard and fast). obviously the random number generated has to be seeded the standard procedure is something like:

srand((unsigned)time(NULL));
Elemental
Be wary of RAND_MAX though if you're looking for identical range and behaviour on different systems. Some have a RAND_MAX of 32k, others 2048k. Always best to check.
Dave
@Dave: just to be nitpicky: in this case, the output will always be a double in the range [0,1], so the only thing that the value of RAND_MAX can change is the amount of distinct values that the expression can return.
suszterpatt
Thanks, that's what I was looking for.
static_rtti
@suszterpatt: Yup, that's what I was referring to. Given he's asking for double precision, thought it might be relevant! I should have phrased it better.
Dave
It's of course not a real uniform distribution, but even _defining_ that precisely for floating point numbers is a bit of a challenge. (The very least you should expect is that p(x) > 0 if 0<x<1)
MSalters
+4  A: 

The random_real class from the Boost random library is what you need.

Vijay Mathew
The documentation for that library is pretty scarce. Do you have a code sample?
Bill
Please have a look at this sample: http://www.boost.org/doc/libs/1_39_0/libs/random/random_demo.cpp
Vijay Mathew
A: 

You could try the Mersenne Twister algorithm.

http://en.wikipedia.org/wiki/Mersenne%5Ftwister

It has a good blend of speed and randomness, and a GPL implementation.

Ryan
A: 

If speed is your primary concern, then I'd simply go with

double r = (double)rand() / (double)RAND_MAX;
suszterpatt
-1: I just checked this, rand() and RAND_MAX are both declared int, so this will always give 0.
Chris Burt-Brown
Fair enough, edited.
suszterpatt
A: 

Well considering simplicity and speed as your primary criteria, you can add a small generic helper like this :-

  // C++ rand generates random numbers between 0 and RAND_MAX. This is quite a big range
  // Normally one would want the generated random number within a range to be really
  // useful. So the arguments have default values which can be overridden by the caller
  int nextRandomNum(int low = 0, int high = 100) const {
    int range = (high - low) + 1;
    // this modulo operation does not generate a truly uniformly distributed random number
    // in the span (since in most cases lower numbers are slightly more likely), 
    // but it is generally a good approximation for short spans. Use it if essential
    //int res = ( std::rand() % high + low );
    int res = low + static_cast<int>( ( range * std::rand() / ( RAND_MAX + 1.0) ) );
    return res;
  }

Random number generation is a well studied, complex and advanced topic. You can find some simple but useful algorithms here apart from the ones mentioned in other answers:-

Eternally Confuzzled

Abhay
A: 

Here's how you'd do it if you were using C++ TR1.

John D. Cook
This seems to me to be the only implementation that actually claims to give you a UNIFORM real distribution - my solution above gives MAX_RAND possible values evenly distributed in the range 0 to 1 which is not quite the same thing.
Elemental
+1  A: 
double randDouble()
{
  double out;
  out = (double)rand()/(RAND_MAX + 1); //each iteration produces a number in [0, 1)
  out = (rand() + output)/RAND_MAX;
  out = (rand() + output)/RAND_MAX;
  out = (rand() + output)/RAND_MAX;
  out = (rand() + output)/RAND_MAX;
  out = (rand() + output)/RAND_MAX;

  return out;
}

Not quite as fast as double X=((double)rand()/(double)RAND_MAX);, but with better distribution. That algorithm gives only RAND_MAX evenly spaced choice of return values; this one gives RANDMAX^6, so its distribution is limited only by the precision of double.

If you want a long double just add a few iterations. If you want a number in [0, 1] rather than [0, 1) just make line 4 read out = (double)rand()/(RAND_MAX);.

foo'pitier