>A much clearer method would be rand()%x , where x is the number you want.
Clearer, but not necessarily better. rand has subtleties that need to be considered. In particular, there are two distinct problems with rand: one historical and one that is still common.
The historical problem is that older implementations of rand (and extremely poor modern implementations) show a pattern where the low order bits of the random number are decidedly nonrandom. Because the remainder trick (
rand() % N ) uses the low order bits, it fails miserably for smaller values of N.
The solution for the historical problem is to use the high order bits instead with some variation of division by RAND_MAX (
rand() / ( RAND_MAX / N + 1 ) ). If you have a small value of N and a weak implementation of rand, this method is vastly more effective.
The second problem is one of distribution. Both of the above methods (remainder and division by RAND_MAX) have the same problem with distribution, regardless of the quality of rand. Because implementations of rand have pretty much been fixed, the historical problem isn't much of a problem anymore, but the problem of distribution is still present. Except in very specific exceptions, some numbers will be produced with a higher frequency than others because rand is designed to return values in a certain range, and if you close that range then the
pigeonhole principle is in effect and the hole with more pigeons will show up more often.
What the two methods above do is merge ranges into a single value. For example if the full range of rand is [0, 10) and you want a value in the range of [0,1], you need to pretend that any value in the range of [0, 5) represents 0 and any value in the range of [5, 10) represents 1:
0 1
--------- ---------
0 1 2 3 4 5 6 7 8 9
That's all well and good because 10 is evenly divisible by 2, but what if you want numbers in a range of [0, 2]? 10 isn't evenly divisible by 2, so you have to make one group larger than the other two:
0 1 2
----- ----- -------
0 1 2 3 4 5 6 7 8 9
Now 2 will be more common than 0 and 1 because the range that's assumed to be 2 is larger than the range that's assumed to be 0 or 1. This is the distribution problem. To fix the distribution, I prefer to use a uniform deviate:
#include <cstdlib>
#include <iostream>
int main()
{
for ( int i = 0; i < 20; i++ )
std::cout<< ( std::rand() * ( 1.0 / ( RAND_MAX + 1.0 ) ) ) * 7 + 1 <<'\n';
}
The difference is that instead of trying to shrink the range of the random number (which breaks the distribution except when the RAND_MAX is evenly divisible by N, a uniform deviate produces a random value in the range of [0, 1) in floating-point, which can then be multiplied to get a suitable range without affecting the distribution. It's tedious to type, so a function would be better suited:
#include <cstdlib>
#include <iostream>
double udrand ( int lo, int hi )
{
static const double base = 1.0 / ( RAND_MAX + 1.0 );
double deviate = std::rand() * base;
return lo + deviate * ( hi - lo );
}
int main()
{
for ( int i = 0; i < 20; i++ )
std::cout<< udrand ( 1, 7 ) <<'\n';
}
I'd also rant about using time to seed the random number generator, but people have a tendency to ignore my advice on that matter.