Separate rand () sequences giving the same results in an expression

OK, this is really weird.

I have an MPI program where each process must generate random numbers in a fixed range (the range is read from a file). It happens that even if I sow each process with a different value, and the numbers generated by rand() differ in each process, the expression for generating random numbers still gives the same sequence between them.

Here are all the relevant codes:

 // 'rank' will be unique for each process int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); // seed the RNG with a different value for each process srand(time(NULL) + rank); // print some random numbers to see if we get a unique sequence in each process // 'log' is a uniquely named file, each process has its own log << rand() << " " << rand() << " " << rand() << std::endl; // do boring deterministic stuff while (true) { // waitTimeMin and waitTimeMax are integers, Max is always greater than Min waitSecs = waitTimeMin + rand() % (waitTimeMax - waitTimeMin); log << "waiting " << waitSecs << " seconds" << std::endl; sleep(waitSecs); // do more boring deterministic stuff } 

Here is the output of each process with three processes generating numbers in the range [1.9].

process 1:

 15190 28284 3149 waiting 6 seconds waiting 8 seconds waiting 9 seconds waiting 4 seconds 

process 2:

 286 6264 3153 waiting 6 seconds waiting 8 seconds waiting 9 seconds waiting 4 seconds 

process 3:

 18151 17013 3156 waiting 6 seconds waiting 8 seconds waiting 9 seconds waiting 4 seconds 

Thus, while rand() explicitly generates different numbers, the expression for computing waitSecs still evaluates the same sequence for all processes. What's even weirder: if I run the program again with the same parameters, only the first 3 random numbers change, the rest of the "random" sequence will be the same in every run! Changing the range of numbers will obviously lead to a different result from this, but the same parameters always give the same sequence between processes and between execution: with the exception of the first three numbers.

What the hell is going on here?


EDIT: To just make sure this is simplified random generation and / or low range, I replaced the random generation with this line:

 waitSecs = waitTimeMin + (int)((double)rand() / ((double)RAND_MAX + 1) * (waitTimeMax - waitTimeMin)); 

And he began to generate numbers in the range of [1.99]. Here is the result:

process 1:

 7833 3798 10977 waiting 1 seconds waiting 20 seconds waiting 58 seconds waiting 35 seconds waiting 82 seconds waiting 18 seconds 

process 2:

 25697 14547 10980 waiting 1 seconds waiting 20 seconds waiting 58 seconds waiting 35 seconds waiting 82 seconds waiting 18 seconds 

process 3:

 10794 25295 10984 waiting 1 seconds waiting 20 seconds waiting 58 seconds waiting 35 seconds waiting 82 seconds waiting 18 seconds 

Same. Could this just be rand() really bad?

EDIT2: The same when creating numbers from 1 to 10000.

+4
source share
4 answers

Well, apparently, I'm set aside. After initializing the RNG, I spawned a new thread and generated random numbers there, without initialization. Calling srand() on a new thread fixed the problem. So the lesson here is that srand() and rand() work for the thread, not for the process. I also need to start posting more information about my program in my questions.

Uch.

Sorry to spend all the time.

+1
source

In your code, you only use the 3 least significant bits if a random number is generated (remainder of division by 8). What your experiment shows is that the sequence of the smallest 3 bits of the generated sequence of numbers is the same every time. It is quite possible. This is essentially a known issue with the simplified pseudo random number generator commonly used to implement rand() .

If you want to use rand() (instead of a more complex custom generator), it is better to use higher order bits rather than lower ones. That is, do not use the % operator to reduce the range of rand() . Take a look at the best method here: http://c-faq.com/lib/randrange.html

+4
source

Try using a random number generator from tr1, for example std::tr1::mt19937 . The rand() function is usually implemented using a low-quality random number generator.

EDIT: Poor quality may mean, for example, that even creating 2D points (x,y) in [0,100]^2 will lead to points that are not uniformly scattered across the square. You might think that it should not behave so badly, but you will be surprised at how rand() actually behaves (and this, unfortunately, is true in most languages).

EDIT2: range*(rand()/RAND_MAX) methods range*(rand()/RAND_MAX) not very good. He has problems with double precision, which will not even give results.

Try the following and see if your program produces results that will surprise you:

 std::tr1::mt19937 engine(thread_seed); std::tr1::uniform_int<> unigen(waitTimeMin, waitTimeMax); std::tr1::variate_generator<std::tr1::mt19937, std::tr1::uniform_int<> >gen(engine, unigen); waitSec = gen(); 

EDIT3:
(source: dilbert.com )

+1
source

Computing (rand() % n) is usually a bad idea - you get results that are less random. Instead, if RAND_MAX is the output range of rand() , try dividing rand() by (RAND_MAX/(waitTimeMax - waitTimeMin)) .

The rand() is most likely a linear congruent generator . If you follow the last link, you will find more information on how it works, as well as an explanation of why the lower digits are “less random” than the higher ones.

+1
source

Source: https://habr.com/ru/post/1305977/


All Articles