rand
From Cppwiki
rand and srand are standard library functions that provide a primitive implementation of a pseudorandom number generator (PRNG).
Contents |
API
- void srand(unsigned int seed)
- resets the PRNG to generate a sequence of pseudorandom integers based on the given seed value. C++ uses an initial seed value of 1.
- int rand()
- returns the next value in the sequence. Each value n falls in the range 0 <= n <= RAND_MAX.
- RAND_MAX
- a number in the range 32767 <= RAND_MAX <= INT_MAX (2147483647 for 32-bit integers).
Common uses
Range surjection
...or, in English, how to get a random number within a particular range:
inline double random(double lo, double hi, bool inclusive = false) { const double range = (inclusive ? RAND_MAX : 1.0 + RAND_MAX); return lo + rand() * (hi - lo) / range; } inline int random(int lo, int hi, bool inclusive = false) { // note: floor() really only needed if hi < 0 return int(floor(random(double(lo), double(hi), inclusive))); }
Math.random()
Java class java.lang.Math has a method random() that returns a floating-point number n in the range 0 <= n < 1, which you can then multiply in order to get your desired range. To accomplish the same in C++:
namespace Math { inline double random() { return rand() / (1.0 + RAND_MAX); } } double n; n = Math::random() * 42; // 0.0 <= n < 42.0 n = Math::random() * 43; // 0.0 <= n < 43.0 n = Math::random() * 42 + 1; // 1.0 <= n < 43.0 n = int(Math::random() * 42); // 0 <= n <= 41 n = int(Math::random() * 43); // 0 <= n <= 42 n = int(Math::random() * 42) + 1; // 1 <= n <= 42
Common problems
Same/similar sequence of values for each run
Each call to srand(seed) starts a new sequence of pseudorandom numbers based on the given seed value. With that in mind:
- Call it at least once per program, usually in your main() function.
- Don't call it each time you call rand() or else you may get the same "random" number each time.
- Use a unique seed value for each sequence. The entropy (randomness) of the sequence depends on the entropy of the seed.
- Beware of using time(NULL) as your seed value. If you call time(NULL) several times in a short period, you may get the same value (or similar values), which will generate the same sequence (or similar sequences). To increase entropy, you may wish to use a seed whose value changes more frequently, such as the current process ID (Unix getpid, Windows GetCurrentProcessId) or the current time in milliseconds or nanoseconds (e.g. Unix gettimeofday, Windows GetTickCount). You can even XOR these together (e.g. time(NULL) ^ getpid()).
- As a special case, if the values can be close but never identical, you can use srand((time(0) << 16) | (time(0) >> 16)) as a workaround.
Sequences don't seem to be uniformly distributed
rand() may be biased in some C++ implementations. Some numbers are more likely than others to be returned.
rand() % N performs poorly if rand() is biased! Here's a good example:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int main() { srand(time(NULL)); const int range = 1400000000; int lo = 0, hi = 0; for (int i = 0, j = 1 << 20; i < j; ++i) { if ((rand() % range) < (range / 2)) { ++lo; } else { ++hi; } } cout << "lo=" << lo << "/hi=" << hi << '\n'; }
It usually prints something like lo=684268/hi=364308, i.e. numbers are twice as likely to be in the low half of the range!
You can compensate by converting to a floating-point number and then translating it into your desired range:
int n; n = int(double(rand()) * N / RAND_MAX); // 0 <= n <= N n = int(double(rand()) * N / (RAND_MAX + 1)); // 0 <= n < N
If, in the above example, we use this if-statement...
if (rand() * double(range) / RAND_MAX < (range / 2)) {
...we get a more reasonable result like lo=523957/hi=524619, closer to 50/50.
Ranges approaching RAND_MAX are more susceptible to bias; and integer ranges larger than RAND_MAX cannot be completely mapped to the range of rand(). If these become problems for you, you may have to look into other PRNGs, such as Boost.Random.
See also
- Boost.Random provides a collection of far better PRNG implementations; apparently now part of C++ TR1
- How can I get random integers in a certain range? (comp.lang.c FAQ)
- HotBits: Genuine random numbers, generated by radioactive decay
- a PRNG that exploits "randomness in the drift between the processor clock and the rate at which interval timer interrupts occur"