I need a function which would generate a random integer in given range (including border values). I don't unreasonable quality/randomness requirements, I have four requirements:
- I need it to be fast. My project needs to generate millions (or sometimes even tens of millions) of random numbers and my current generator function has proven to be a bottleneck.
- I need it to be reasonably uniform (use of rand() is perfectly fine).
- the min-max ranges can be anything from <0, 1> to <-32727, 32727>.
- it has to be seedable.
I currently have following C++ code:
output = min + (rand() * (int)(max - min) / RAND_MAX)
The problem is, that it is not really uniform - max is returned only when rand() = RAND_MAX (for Visual C++ it is 1/32727). This is major issue for small ranges like <-1, 1>, where the last value is almost never returned.
So I grabbed pen and paper and came up with following formula (which builds on the (int)(n + 0.5) integer rounding trick):
But it still doesn't give me uniform distribution. Repeated runs with 10000 samples give me ratio of 37:50:13 for values values -1, 0. 1.
Could you please suggest better formula? (or even whole pseudo-random number generator function)
How about the Mersenne Twister? The boost implementation is rather easy to use and is well tested in many real-world applications. I've used it myself in several academic projects such as artificial intelligence and evolutionary algorithms.
Here's their example where they make a simple function to roll a six-sided die:
Oh, and here's some more pimping of this generator just in case you aren't convinced you should use it over the vastly inferior
rand()
:This is a mapping of 32768 integers to (nMax-nMin+1) integers. The mapping will be quite good if (nMax-nMin+1) is small (as in your requirement). Note however that if (nMax-nMin+1) is large, the mapping won't work (For example - you can't map 32768 values to 30000 values with equal probability). If such ranges are needed - you should use a 32-bit or 64-bit random source, instead of the 15-bit rand(), or ignore rand() results which are out-of-range.
The simplest (and hence best) C++ (using the 2011 standard) answer is
No need to re-invent the wheel. No need to worry about bias. No need to worry about using time as random seed.
If your compiler supports C++0x and using it is an option for you, then the new standard
<random>
header is likely to meet your needs. It has a high qualityuniform_int_distribution
which will accept minimum and maximum bounds (inclusive as you need), and you can choose among various random number generators to plug into that distribution.Here is code that generates a million random
int
s uniformly distributed in [-57, 365]. I've used the new std<chrono>
facilities to time it as you mentioned performance is a major concern for you.For me (2.8 GHz Intel Core i5) this prints out:
2.10268e+07 random numbers per second.
You can seed the generator by passing in an int to its constructor:
If you later find that
int
doesn't cover the range you need for your distribution, this can be remedied by changing theuniform_int_distribution
like so (e.g. tolong long
):If you later find that the
minstd_rand
isn't a high enough quality generator, that can also easily be swapped out. E.g.:Having separate control over the random number generator, and the random distribution can be quite liberating.
I've also computed (not shown) the first 4 "moments" of this distribution (using
minstd_rand
) and compared them to the theoretical values in an attempt to quantify the quality of the distribution:(The
x_
prefix refers to "expected")I recommend the Boost.Random library, it's super detailed and well-documented, lets you explicitly specify what distribution you want, and in non-cryptographic scenarios can actually outperform a typical C library rand implementation.
The following expression should be unbiased if I am not mistaken:
I am assuming here that rand() gives you a random value in the range between 0.0 and 1.0 NOT including 1.0 and that max and min are integers with the condition that min < max.