Init random numbers with time?

M

Markus Dehmann

According to several C++ tutorials, calling srand like this to
initialize the random number generator seems to be standard:

srand((unsigned)time(0));

But it leads to the same random number sequence on every program call
if the program is called several times in a second! Isn't there a
better method to seed the random numbers? Probably based on
milliseconds instead of seconds? And integrating the process ID or
current amount of free memory or whatever? Is there a C++ library that
does it right?

Here is the program that outputs 3 different random numbers on a
../a.out call, but two identical sequences if called in a row like:
../a.out; ./a.out

#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

int main(){
srand((unsigned)time(0));
for(unsigned i=0; i<3; ++i){
cout << rand() << endl;
}
cout << endl;
return EXIT_SUCCESS;
}

Thanks!
Markus
 
J

Jeff Dege

According to several C++ tutorials, calling srand like this to
initialize the random number generator seems to be standard:

srand((unsigned)time(0));

But it leads to the same random number sequence on every program call
if the program is called several times in a second! Isn't there a
better method to seed the random numbers?

Yes, if you want different behavior on every run. Though you may prefer
identical behavior on every run for certain phases of testing.
Probably based on
milliseconds instead of seconds?

There isn't a standard function that's guaranteed to return milliseconds.
There's nothing in the standard that time_t can't be in milliseconds, or
that it must be. You're dealing with inherently OS-specific functionality.
And integrating the process ID or
current amount of free memory or whatever?

Is your idea that by adding PID you would get distinct sequences when the
program is run more than once in the same second? That'd probably work,
except that getting the PID is also a non-portable construct. You might
as well just used the fine-grained OS-specific time function. I know of
at least one OS in which the time function is guaranteed to return unique
values on every call. And there are OSes that don't have PIDs. So your
proposal would be unnecessary on some, and impossible on others.
Is there a C++ library that
does it right?

"Right" is a matter of opinion. IMO, a pseudo-random generator that can't
be configured to produce repeatable sequences when desired is broken. In
other words, if you want to initialize the seed from the system clock, do
so.
Here is the program that outputs 3 different random numbers on a
./a.out call, but two identical sequences if called in a row like:
./a.out; ./a.out

[...]

--
"The national budget must be balanced. The public debt must be
reduced; the arrogance of the authorities must be moderated and
controlled. Payments to foreign governments must be reduced,
if the nation doesn't want to go bankrupt. People must again
learn to work, instead of living on public assistance."
- Marcus Tullius Cicero
 
S

Steve Pope

Markus Dehmann said:
According to several C++ tutorials, calling srand like this to
initialize the random number generator seems to be standard:

srand((unsigned)time(0));

But it leads to the same random number sequence on every program call
if the program is called several times in a second! Isn't there a
better method to seed the random numbers? Probably based on
milliseconds instead of seconds?

One approach is to use the process id as part of the seed. One
standard/portable way to do this is to use an integer hash function
of the string returned by tmpnam().

Steve
 
D

David Harmon

On 4 Dec 2006 21:43:37 -0800 in comp.lang.c++, "Markus Dehmann"
According to several C++ tutorials, calling srand like this to
initialize the random number generator seems to be standard:

srand((unsigned)time(0));

But it leads to the same random number sequence on every program call
if the program is called several times in a second!

Indeed, that method is unsuitable for a program that's going to be
called several times in a second. It may also be unsuitable for a
program that's going to be launched by "chron" or the windows task
scheduler etc. at repeated predictable times. The whole rand()
scheme is suitable for only casual undemanding applications.

For a somewhat better grade of random numbers I think I'd start by
adapting the random number generator class from Stroustrup ch. 22.
For your concern, I'd make it a class that loaded the seed from a file
in the constructor and saved it back to disk in the destructor.

For the best grade of random numbers, consult a cryptologist.

In June 1998 the Arizona Lottery had to suspended its Pick 3 game when
they discovered that their random number generator selecting the winning
numbers never picked the digit 9. (RISKS Digest 19.3)
 
D

David Harmon

On Tue, 05 Dec 2006 06:03:37 GMT in comp.lang.c++, David Harmon
In June 1998 the Arizona Lottery had to suspended its Pick 3 game when
they discovered that their random number generator selecting the winning
numbers never picked the digit 9. (RISKS Digest 19.3)

Sorry, that's RISKS Digest 19.83
 
S

Steve Pope

I said:
One approach is to use the process id as part of the seed. One
standard/portable way to do this is to use an integer hash function
of the string returned by tmpnam().

I notice the gcc documentation for tmpnam() says: "Never use this
function. Use mkstemp(3) instead".

However, mkstemp() is not part of standard C++, whereas tmpnam()
is, so pick your poison.

Steve
 
E

eriwik

According to several C++ tutorials, calling srand like this to
initialize the random number generator seems to be standard:

srand((unsigned)time(0));

But it leads to the same random number sequence on every program call
if the program is called several times in a second! Isn't there a
better method to seed the random numbers? Probably based on
milliseconds instead of seconds? And integrating the process ID or
current amount of free memory or whatever? Is there a C++ library that
does it right?

As many have pointed out, if you want to do this well, you'll have to
use some platform-specific code (or wait to the next version of the
standard, looks like it will have random number generators). If you are
running Linux/Unix you can read in a value to use as seed from
/dev/random (or dev/urandom or something such). This will give you
high-entropy random numbers.
 
L

lwz

You could put a random number generated by rand() into your srand
function, maybe even added to the number of processor clock ticks after
the process started (clock())... so
srand(rand()+clock()+time(NULL));
 
J

Jeff Dege

You could put a random number generated by rand() into your srand
function, maybe even added to the number of processor clock ticks after
the process started (clock())... so
srand(rand()+clock()+time(NULL));

That's not going to give you a unique seed, if you start the program
multiple times in the same second. Calling rand() without having set a
distinct seed will always return the same value. On many platforms,
calling clock() at the same point in program execution will always return
the same value.
 
M

Markus Moll

Hi

Steve said:
I notice the gcc documentation for tmpnam() says: "Never use this
function. Use mkstemp(3) instead".

It's completely safe if you just want to use the string for whatever
purpose. The only problem with the function is that getting the filename
from tmpnam and actually opening the file is not atomic, which leaves you
vulnerable to some attacks:
http://www.owasp.org/index.php/Insecure_Temporary_File

Markus
 
J

Jeff Dege

One approach is to use the process id as part of the seed.

There's no guarantee that your platform has process ids.
One
standard/portable way to do this is to use an integer hash function
of the string returned by tmpnam().

There's no guarantee that tmpnam will create distinct values in different
processes.

--
The most dangerous man, to any government, is the man who is able to think
things out for himself without regard to the prevailing superstitions
and taboos. Almost inevitably he comes to the conclusion that the
government he lives under is dishonest, insane and intolerable, and so,
if he is romantic, he tries to change it. And even if he is not romantic
personally he is apt to spread discontent among those who are.
- H.L. Mencken
 
J

Jeff Dege

I notice the gcc documentation for tmpnam() says: "Never use this
function. Use mkstemp(3) instead".

However, mkstemp() is not part of standard C++, whereas tmpnam()
is, so pick your poison.

mkstemp() actually opens the file. Which means it generates a filename
that doesn't correspond to an existing file, tries to open it, and then
repeats if the open fails because the file already exists. (We don't have
transaction guarantees, so there's a chance that another process can
create the file between the time we generate the name and create the file.)

--
The most dangerous man, to any government, is the man who is able to think
things out for himself without regard to the prevailing superstitions
and taboos. Almost inevitably he comes to the conclusion that the
government he lives under is dishonest, insane and intolerable, and so,
if he is romantic, he tries to change it. And even if he is not romantic
personally he is apt to spread discontent among those who are.
- H.L. Mencken
 
S

Steve Pope

There's no guarantee that your platform has process ids.
There's no guarantee that tmpnam will create distinct values in different
processes.

No guarantee, true, but that is what it is supposed to do.
It's a bug if it doesn't.

And... do you have a better suggestion?

Steve
 
J

Jeff Dege

No guarantee, true, but that is what it is supposed to do.
It's a bug if it doesn't.

It's a bug if it generates a name that matches a file that already
exists. It's a bug if it generates the same name twice within the same
process.
And... do you have a better suggestion?

Use uuid_create().
 
J

Jeff Dege

[ tmpnam() ]
Use uuid_create().

That's not part of the language. tmpnam() is.

But tmpnam() isn't guaranteed to give you the behavior you need.

Yes, the way tmpnam() is implemented on many systems gives you what you
need, but it's not guaranteed to. And in my mind, relying on
implementation details that aren't guaranteed by the spec is dangerous.

--
To my mind it is wholly irresponsible to go into the world incapable of
preventing violence, injury, crime, and death. How feeble is the mindset
to accept defenselessness. How unnatural. How cheap. How cowardly. How
pathetic.
- Ted Nugent
 
R

rossum

According to several C++ tutorials, calling srand like this to
initialize the random number generator seems to be standard:

srand((unsigned)time(0));

But it leads to the same random number sequence on every program call
if the program is called several times in a second! Isn't there a
better method to seed the random numbers?
If the program is being called several times a second, it is a fair
bet that the calls are being generated automatically. Just make the
calling program keep a count of the number of calls it makes and pass
the call number to the program as a parameter. The call number will
be unique to each copy of the program, unless you are making 2**32 or
more calls in a very short time. Use a combination of time(0) and the
call number to seed the RNG.

Alternatively have a separate process continually running to generate
random numbers. Each copy of the program can get its own random
number and use that to seed its own internal generator. Linux users
have dev/random or dev/urandom for this purpose, it should be possible
to set up something similar for other operating systems.

rossum
 

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

Similar Threads


Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top