Generate random numbers uniformly over an entire range
I'd like to complement Shoe's and peterchen's excellent answers with a short overview of the state of the art in 2015:
Some good choices
randutils
The randutils
library (presentation) is an interesting novelty, offering a simple interface and (declared) robust random capabilities. It has the disadvantages that it adds a dependence on your project and, being new, it has not been extensively tested. Anyway, being free (MIT License) and header-only, I think it's worth a try.
Minimal sample: a die roll
#include <iostream>
#include "randutils.hpp"
int main() {
randutils::mt19937_rng rng;
std::cout << rng.uniform(1,6) << "\n";
}
Even if one is not interested in the library, the website provides many interesting articles about the theme of random number generation in general and the C++ library in particular.
Boost.Random
Boost.Random
(documentation) is the library which inspired C++11's <random>
, with whom it shares much of the interface. While theoretically also being an external dependency, Boost has by now a status of "quasi-standard" library, and its Random
module could be regarded as the classical choice for good-quality random number generation. It features two advantages with respect to the C++11 solution:
- it is more portable, just needing compiler support for C++03
- its
random_device
uses system-specific methods to offer seeding of good quality
The only small flaw is that the module offering random_device
is not header-only, one has to compile and link boost_random
.
Minimal sample: a die roll
#include <iostream>
#include <boost/random.hpp>
#include <boost/nondet_random.hpp>
int main() {
boost::random::random_device rand_dev;
boost::random::mt19937 generator(rand_dev());
boost::random::uniform_int_distribution<> distr(1, 6);
std::cout << distr(generator) << '\n';
}
While the minimal sample does its work well, real programs should use a pair of improvements:
- make
mt19937
athread_local
: the generator is quite plump (more than 2 KB) and is better not allocated on the stack - seed
mt19937
with more than one integer: the Mersenne Twister has a big state and can take benefit of more entropy during initialization
Some not-so-good choices
The C++11 library
While being the most idiomatic solution, the <random>
library does not offer much in exchange for the complexity of its interface even for the basic needs. The flaw is in std::random_device
: the Standard does not mandate any minimal quality for its output (as long as entropy()
returns 0
) and, as of 2015, MinGW (not the most used compiler, but hardly an esoteric choice) will always print 4
on the minimal sample.
Minimal sample: a die roll
#include <iostream>
#include <random>
int main() {
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(1, 6);
std::cout << distr(generator) << '\n';
}
If the implementation is not rotten, this solution should be equivalent to the Boost one, and the same suggestions apply.
Godot's solution
Minimal sample: a die roll
#include <iostream>
#include <random>
int main() {
std::cout << std::randint(1,6);
}
This is a simple, effective and neat solution. The only defect is it will take a while to compile – about two years, providing C++17 is released on time and the experimental randint
function is approved into the new Standard. Maybe by that time also the guarantees on the seeding quality will improve.
The worse-is-better solution
Minimal sample: a die roll
#include <cstdlib>
#include <ctime>
#include <iostream>
int main() {
std::srand(std::time(nullptr));
std::cout << (std::rand() % 6 + 1);
}
The old C solution is considered harmful, and for good reasons (see the other answers here or this detailed analysis). Still, it has its advantages: is is simple, portable, fast and honest, in the sense it is known that the random numbers one gets are hardly decent, and therefore one is not tempted to use them for serious purposes.
The accounting troll solution
Minimal sample: a die roll
#include <iostream>
int main() {
std::cout << 9; // http://dilbert.com/strip/2001-10-25
}
While 9 is a somewhat unusual outcome for a regular die roll, one has to admire the excellent combination of good qualities in this solution, which manages to be the fastest, simplest, most cache-friendly and most portable one. By substituting 9 with 4, one gets a perfect generator for any kind of Dungeons & Dragons die, while still avoiding the symbol-laden values 1, 2 and 3. The only small flaw is that, because of the bad temper of Dilbert's accounting trolls, this program actually engenders undefined behavior.
Why rand
is a bad idea
Most 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.
C++11 and generation over a range
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);
}
Other random generators
The <random>
header offers innumerable other random number generators with different kind of distributions including Bernoulli, Poisson and normal.
How can I shuffle a container?
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.
Boost.Random
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.
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.