Home > Back-end >  Why do I get nearly the same number out of the rand() function in the first iteration?
Why do I get nearly the same number out of the rand() function in the first iteration?

Time:12-04

in my C99-programme I want to use pseudo-random numbers between 0 an 1. Unfortunatly, my programme always generates a first number that is almost identical. It just steps up ever so slightly every time I rerun my programme.

This is the relevant part of my programme:

srand(time(NULL));  
for(int i = 0; i < 10; i  ){
    float a = (float)rand()/RAND_MAX;
    printf("%f\n",a);

And here are the results of two Iterations with a time difference of below 10 seconds:

0.717103
0.357464
0.903628
0.271930
0.327478
0.917489
0.231215
0.026307
0.135259
0.290941

0.717221
0.330531
0.237708
0.151682
0.318986
0.201876
0.936884
0.209277
0.324705
0.311334

I tried to generate completely different numbers no matter how many I computed before, but the first is alway close to the same.

CodePudding user response:

Patterns like this are typically caused by low-quality linear congruential pseudorandom number generators. Each random number is computed as Xnew = (aXold c) mod m. When you seed this with a number of seconds, the change between the first value generated after seeding at one time and the first value generated after seeding one second later is a modulo m.

If you are using a Unix system (such as macOS or Linux), you can use srandom and random instead.

CodePudding user response:

The problem appears to be that your system's rand() implementation is sensitive to the fact that successive return values from time() don't differ by much -- that is, aren't supplying much entropy.

I tried your code on my machine and got remarkably similar results.

You need to provide a bit more entropy, to "mix things up".

One technique I like to use (at least, on Unix-like systems) is to add the process ID into the seed, since the pid will be different each time. Usually I do it like this:

srand(time(NULL)   getpid());

This is a good way to make sure your program generates different results even if you invoke it twice in the same second.

Unfortunately, this wasn't enough to make a difference with your code on my machine, and I suspect it won't help on yours, either. The problem is that (especially on a non-loaded system) the process ID typically just increments by 1 or 2 each time also, and it's adding in to the same low-order bits of time's return value which also aren't changing my much. (And the high order bits of the pid don't change at all, and are being added to the high-order bits of the time of day, which also aren't changing.)

On my system, I got decent results with

srand(time(NULL) ^ (getpid() << 16));

and I suggest you try this.

If that doesn't help, you'll want to use either a significantly better entropy source, or a significantly better pseudorandom number generator.

These days, virtually all Unix-like systems have a good source of entropy accessible via the special file /dev/random. So a superior way of seeding a pseudorandom number generator is with code like this:

FILE *fp = fopen("/dev/random", "rb");
if(fp != NULL) {
    int seed;
    fread(&seed, sizeof(seed), 1, fp);
    srand(seed);
}

(For a production program, obviously you'd have to decide what to do if the fopen call failed.)

Eric Postpischil's answer mentions random, a significantly better PRNG available on most systems.

  • Related