I need to generate random numbers within a specified interval, [max;min].
Also, the random numbers should be uniformly distributed over the interval, not located to
@Solution ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
Warning: Don't forget due to stretching and possible precision errors (even if RAND_MAX were large enough), you'll only be able to generate evenly distributed "bins" and not all numbers in [min,max].
@Solution: Bigrand
Warning: Note that this doubles the bits, but still won't be able to generate all numbers in your range in general, i.e., it is not necessarily true that BigRand() will generate all numbers between in its range.
Info: Your approach (modulo) is "fine" as long as the range of rand() exceeds your interval range and rand() is "uniform". The error for at most the first max - min numbers is 1/(RAND_MAX +1).
Also, I suggest to switch to the new random packagee in C++11 too, which offers better and more varieties of implementations than rand().
rand
is a bad ideaMost of the answers you got here make use of the rand
function and the modulus operator. That method may not generate numbers uniformly (it depends on the range and the value of RAND_MAX
), and is therefore discouraged.
With C++11 multiple other options have risen. One of which fits your requirements, for generating a random number in a range, pretty nicely: std::uniform_int_distribution. Here's an example:
const int range_from = 0;
const int range_to = 10;
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(range_from, range_to);
std::cout << distr(generator) << '\n';
And here's the running example.
Template function may help some:
template<typename T>
T random(T range_from, T range_to) {
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<T> distr(range_from, range_to);
return distr(generator);
}
The <random> header offers innumerable other random number generators with different kind of distributions including Bernoulli, Poisson and normal.
The standard provides std::shuffle, which can be used as follows:
std::vector<int> vec = {4, 8, 15, 16, 23, 42};
std::random_device random_dev;
std::mt19937 generator(random_dev());
std::shuffle(vec.begin(), vec.end(), generator);
The algorithm will reorder the elements randomly, with a linear complexity.
Another alternative, in case you don't have access to a C++11+ compiler, is to use Boost.Random. Its interface is very similar to the C++11 one.
[edit] Warning: Do not use rand()
for statistics, simulation, cryptography or anything serious.
It's good enough to make numbers look random for a typical human in a hurry, no more.
See @Jefffrey's reply for better options, or this answer for crypto-secure random numbers.
Generally, the high bits show a better distribution than the low bits, so the recommended way to generate random numbers of a range for simple purposes is:
((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
Note: make sure RAND_MAX+1 does not overflow (thanks Demi)!
The division generates a random number in the interval [0, 1); "stretch" this to the required range. Only when max-min+1 gets close to RAND_MAX you need a "BigRand()" function like posted by Mark Ransom.
This also avoids some slicing problems due to the modulo, which can worsen your numbers even more.
The built-in random number generator isn't guaranteed to have a the quality required for statistical simulations. It is OK for numbers to "look random" to a human, but for a serious application, you should take something better - or at least check its properties (uniform distribution is usually good, but values tend to correlate, and the sequence is deterministic). Knuth has an excellent (if hard-to-read) treatise on random number generators, and I recently found LFSR to be excellent and darn simple to implement, given its properties are OK for you.
The solution given by man 3 rand for a number between 1 and 10 inclusive is:
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
In your case, it would be:
j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));
Of course, this is not perfect randomness or uniformity as some other messages are pointing out, but this is enough for most cases.
If you are concerned about randomness and not about speed, you should use a secure random number generation method. There are several ways to do this... The easiest one being to use OpenSSL's Random Number Generator.
You can also write your own using an encryption algorithm (like AES). By picking a seed and an IV and then continuously re-encrypting the output of the encryption function. Using OpenSSL is easier, but less manly.