This question already has an answer here:
- Pseudo-random number generator 10 answers
I'm trying to generate a random number 0 - 59, and am not satisfied with the rand() function in C. Here is the code I'm playing around with:
#include <stdlib.h>
#include <time.h>
main()
{
int num;
srand(time(NULL));
num = rand();
num = num % 59;
printf("%d\n", num);
}
I've repeated the run on this code and noticed that the random numbers being generated don't really seem that random. The generated numbers produced are definitely following a pattern, as each time I run the program the number gets progressively larger until it wraps back around to the beginning (i.e. 2, 17, 21, 29, 38, 47, 54, 59, 4, 11....etc).
Is there a way I can seed the function so that every time I re-run the function I get a true random number with a 1/60 chance of being generated? Or are there any alternative methods I can implement myself rather than using the rand() function in C?
No, the C standard library uses a PRNG (pseudorandom number generator). You will never get true random numbers.
You can, however, seed it with something that changes more frequently than
time()
, for example, on POSIX:Also, using the modulo operator for generating a random number is not a good solution (it severely decreases entropy). If you have a BSD-style libc implementation, use
Or, if you don't have this function:
Note the use of
random()
- it is superior torand()
(which had and has a number of low-quality implementations). This function can be seeded usingsrandom()
.You can (of course, else how would the writers of the C library implementation do it?), but you better not - it's a separate science to write a good PRNG, so to say.
The way your program is written, you must re-run it each time to get a new random number, which also means it gets re-seeded each time. Re-seeding a PRNG is bad.
You want to seed once, then generate a bunch of random numbers.
Do it this way:
Now you should get much better results.
Each time you re-run the program, you re-seed with
time()
, and that function only advances once a second (if you re-run the program quickly enough you'll get the same result).The fact that it seems to increment until it rolls over suggests that the first call to
rand()
is returning the un-modified seed -- that number which increments once per second. In that case you're getting the same results (or very similar results) as if you'd run:I'm sure you can see what's wrong with that.
In this case, if you used the 'more correct'
rand() * 59 / RAND_MAX
, which is meant to prefer a value from the 'more random' bits, you would have an even worse situation -- the results wouldn't change at all for maybe 500 seconds, or more.Fundamentally you need to find a less predictable seed, but you may also want to see that it's properly mixed before you use it.
Reading from
/dev/urandom
should provide a good seed, in which case you won't need to worry about mixing, but otherwise callingrand()
a couple of times should help to do away with the especially glaring artefacts of the low-quality seed you started with (except, of course, the problem that it only changes once a second).