oddly behaving rand( ) in microsoft compiler

S

Siam

Hi all,

I'm writing a shell language in c++ that supports the generation of
random numbers, and by its nature, each command must be executed in a
new thread. The call to the random function from my language simply
propogates up to the rand( ) function from c++. For some reason, C++
will give each thread independent use of their own rand( ) function, so
that a rand( ) call from one thread won't affect another thread's call
to rand( ). This meant that every call to random( ) from my language
ended up returning the same number (41, as it happens). To get round
this, I made each thread's constructor call srand on consecutive seeds,
so that the first thread calls srand(1), the next thread srand(2) and
so on. However, the microsoft compiler (but not g++) has more odd
behaviour when generating random numbers from consecutive seeds. In
short, I noticed my calls to random( ) still didn't produce random
numbers. Essentially, I narrowed it down to the following problem:

int main()
{
for(int index=0; index<20; index++){
srand(index);
cout << rand() << endl;
}
return 0;

}

The code above returns the sequence 41, 45, 48, 51, 54, 58, 61, 64,
68....
For some reason, consecutive seeds return closely related numbers on
the first call to rand(). I've tried popping the first rand( ), then
returning the 2nd rand( ) from each seed, but these are still related
(though not quite as strongly as the first calls).

Three questions:
1) Why has it been chosen that each thread gets independent use of
rand( )
2) Why does the microsoft compiler behave like this? Whats the point in
different seeds if they're all related?
3) Any work-arounds anyone can think of?

Thanks a lot :)
 
B

Bernd Strieder

Hello,

problems with rand() on particular platforms are mildly off-topic here.
The FAQ should say something on the problems of rand(), but seems not
to do so. Absolutely none rand() implementation is a perfect source of
randomness. All I can give are simple quick fixes and keywords for
further reading.
Three questions:
1) Why has it been chosen that each thread gets independent use of
rand( )

I can only guess on this question. It is, because it produces less
enough randomness among multiple threads that the program starts
getting deterministic again. In many cases during development and
testing this behaviour is quite useful. Anyway, you cannot take rand()
as something more than just that, the simplest possible source of some
pseudo randomness.

2) Why does the microsoft compiler behave like this? Whats the point
in different seeds if they're all related?

Different seeds producing similar values usually is a sign of a very
poor algorithm for those pseudo random values. If you take poor seeds,
it won't become better. A frequently used strategy involves a strong,
but slow source of randomness to seed a weaker, and faster one.
3) Any work-arounds anyone can think of?

A first try might be better seeds, something involving time() (seconds
since January, 1st 1970) might produce a little bit better results in
your case. At least there is less repetition.

Look at Boost (www.boost.org), they have a set of PRNG (pseudo random
number generator) which are better sources of randomness than most of
the rand() implementations. You have to take resonable seeds to get
good results. However, if you want to know how good your generator has
to be to make an educated choice, then you have to analyze your problem
quite thoroughly. Search with pseudo random number generator or PRNG as
keyword.

Bernd Strieder
 
H

Heinz Ozwirk

....
Essentially, I narrowed it down to the following problem:

int main()
{
for(int index=0; index<20; index++){
srand(index);
cout << rand() << endl;
}
return 0;
}

The code above returns the sequence 41, 45, 48, 51, 54, 58, 61, 64,
68....

Don't call srand() for each call to rand() you make. Call srand() only once
per thread (and don't pass 0 to it). Often srand() is called with the result
of time(), i.e. srand(time(0)). Yo will still get similiar sequences in all
threads if they call srand() within a short time, but that's how rand()
works.
Three questions:
1) Why has it been chosen that each thread gets independent use of
rand( )
2) Why does the microsoft compiler behave like this? Whats the point in
different seeds if they're all related?

I can only guess, but since neither C nor C++ know anything about threads,
microsoft is probably free to do so. One reason might be that rand() has to
save some data from one call to another and it is at least faster to save
those data separately for each thread than using some kind of thread
synchronisation. Also, rand() is supposed to produce exactly the same
sequence of pseudo-random numbers when srand() has been called with 0 as its
argument. For a single thread, that would not be possible, if all threads
would share the initial state of rand().#
3) Any work-arounds anyone can think of?

Take a look at the implementation of srand() and rand(). You can easily copy
that code and write your own implementation, where threads share the
internal state of srand() and rand(). ut then you have to synchronize access
to that state.

HTH
Heinz
 
S

Siam

Heinz said:
Don't call srand() for each call to rand() you make. Call srand() only once
per thread (and don't pass 0 to it). Often srand() is called with the result
of time(), i.e. srand(time(0)). Yo will still get similiar sequences in all
threads if they call srand() within a short time, but that's how rand()
works.

Just to clarify, the code I put there isn't from my actual program, it
was to demonstrate my problem with the seeds' random number generation.
In my program, each thread would only call srand() once upon
construction with a unique seed.

I've fixed this problem now, but only by forcing all calls to random
execute on a single thread. Will probably at some stage take a look at
Boost's rand implementations.

Cheers :)
 
P

Pete Becker

Siam said:
int main()
{
for(int index=0; index<20; index++){
srand(index);
cout << rand() << endl;
}
return 0;

}

The code above returns the sequence 41, 45, 48, 51, 54, 58, 61, 64,
68....

That's not particularly surprising. Most implementations of rand use a
linear congruential generator, which produces similar values whenever
the previous value was a small integer. Try seeding with 10000*i.
Three questions:
1) Why has it been chosen that each thread gets independent use of
rand( )

Most likely, speed. Locking and unlocking a mutex on every call to rand
makes it very slow.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top