Recommended way to initialize srand?
Asked Answered
A

15

81

I need a 'good' way to initialize the pseudo-random number generator in C++. I've found an article that states:

In order to generate random-like numbers, srand is usually initialized to some distinctive value, like those related with the execution time. For example, the value returned by the function time (declared in header ctime) is different each second, which is distinctive enough for most randoming needs.

Unixtime isn't distinctive enough for my application. What's a better way to initialize this? Bonus points if it's portable, but the code will primarily be running on Linux hosts.

I was thinking of doing some pid/unixtime math to get an int, or possibly reading data from /dev/urandom.

Thanks!

EDIT

Yes, I am actually starting my application multiple times a second and I've run into collisions.

Amadoamador answered 27/11, 2008 at 4:37 Comment(14)
Why is time() not enough? Are you starting the application multiple times a second? Note you should only call srand() ONCE in an application.Checkroom
Unless you start the application multiple times a second time() will return a unique value that does not repeat fro 60 years.Checkroom
If time() - or gettimeofday() - is not enough, then the chances are that rand() is not good enough for you. That PRNG need not be very good at all. Cryptographic randomness is hard - use a cryptographic library.Finnish
Actually at least MS CRT keeps the seed in TLS, so in that case you'd actually need to initialize srand() ONCE for each thread. Not sure how GCC stores the seed though.Hapte
Do NOT use tv_usec by itself. The seed repeats every second. Reread my post I have updated it.Checkroom
@Martin: Nonsense. The likelihood of tv_usec repeating is extremely low. But tv_nsec (with clock_gettime) would be even better.Mutate
@R.. Run the program once a second for sixty years. The chance of time() repeating is 0. If you use just the tv_used (not using the seconds) then you will hit every micro seconds 1000 times.Checkroom
I'd like to see the math for how you got that number 1000, but even if it's about right, it's inconsequential. Also unless you make sure you wait significantly more than a second each time, using tv_sec is going to repeat on two consecutive runs quite often, much more than 1000 times in 60 years, and if you wait any less, it's guaranteed to repeat a lot. It's also trivially predictable by an outside party, whereas predicting nanosecond-resolution clock values is essentially impossible.Mutate
@R.. I prefer time() much easier to predict, but less chance of repeating thus any two runs will never be the same. Now if you are starting more than once a second you need to look at how quickly you are spawning the processes the concept is to prevent any two runs being the same.Checkroom
60*365*24*60*60=2^9. Usecs in one sec=1^6 => 1000 times in sec yearsCheckroom
More info about initializing srand() with microseconds: guyrutenberg.com/2007/09/03/seeding-srandTownscape
Related: How to succinctly, portably, and thoroughly seed the mt19937 PRNG?Lye
Related: How I hacked Hacker News. HN used time in milliseconds as a seed, then used the RNG to generate login cookies. The attacker could recover the seed by logging in to their account, receiving a cookie, then enumerate possible seeds and check each against the cookie until a match was found. With the correct seed, they could then predict other users cookies, and carry out actions on the site as those users.Saintsimonianism
Related: srand (time (null)) causes compiler warning: implicit conversion loses integer precisionRuthie
C
67

The best answer is to use <random>. If you are using a pre C++11 version, you can look at the Boost random number stuff.

But if we are talking about rand() and srand()
The best simplest way is just to use time():

int main()
{
    srand(time(nullptr));

    ...
}

Be sure to do this at the beginning of your program, and not every time you call rand()!


Side Note:

NOTE: There is a discussion in the comments below about this being insecure (which is true, but ultimately not relevant (read on)). So an alternative is to seed from the random device /dev/random (or some other secure real(er) random number generator). BUT: Don't let this lull you into a false sense of security. This is rand() we are using. Even if you seed it with a brilliantly generated seed it is still predictable (if you have any value you can predict the full sequence of next values). This is only useful for generating "pseudo" random values.

If you want "secure" you should probably be using <random> (Though I would do some more reading on a security informed site). See the answer below as a starting point: https://mcmap.net/q/65908/-recommended-way-to-initialize-srand for a better answer.

Secondary note: Using the random device actually solves the issues with starting multiple copies per second better than my original suggestion below (just not the security issue).


Back to the original story:

Every time you start up, time() will return a unique value (unless you start the application multiple times a second). In 32 bit systems, it will only repeat every 60 years or so.

I know you don't think time is unique enough but I find that hard to believe. But I have been known to be wrong.

If you are starting a lot of copies of your application simultaneously you could use a timer with a finer resolution. But then you run the risk of a shorter time period before the value repeats.

OK, so if you really think you are starting multiple applications a second.
Then use a finer grain on the timer.

 int main()
 {
     struct timeval time; 
     gettimeofday(&time,NULL);

     // microsecond has 1 000 000
     // Assuming you did not need quite that accuracy
     // Also do not assume the system clock has that accuracy.
     srand((time.tv_sec * 1000) + (time.tv_usec / 1000));

     // The trouble here is that the seed will repeat every
     // 24 days or so.

     // If you use 100 (rather than 1000) the seed repeats every 248 days.

     // Do not make the MISTAKE of using just the tv_usec
     // This will mean your seed repeats every second.
 }
Checkroom answered 27/11, 2008 at 5:30 Comment(26)
Actually, I am starting multiple instances of my app a second :)Amadoamador
I saw somewhere solution that works with timeval/gettimeofday.... ah, yes, my own!! You criticised that its VERY BAD, although chances are 1/1000000 that it will repeat (with the same assumptions you made). And yours is 1/60000. So, it's my solution, only worse, and it is presented as yours.Nichrome
1) Don't assume the clock resolution is 1/1000000. 2) My probability is 1/2147483648 (note the tv_sec). 3) seed repeats is 24 days apart (interaction between apps is also important).Checkroom
Your solution is a well known anti-pattern. My solution is not mine, it is a well known better solution to the one you presented (time to read some books ;-)Checkroom
"seed repeats is 24 days apart" You have 1000 collisions in a second.Nichrome
I have a 1/1000 probability of a collision in any 1 sec. Where the seed overlaps every 24 days. Which is why I prefer to use time() where seed only overlaps every 60 years.Checkroom
Dividing tv_usec by 1000 throws away all of the entropy. Milliseconds are easily predictable, and in fact it's easy to run a program twice within less than a millisecond...Mutate
Side note: gettimeofday is obsolete in POSIX 2008. Instead, it introduces clock_gettime which may require linking with -lrt. It may not yet be available on many platforms, though. In Linux this is alright. On Mac I think it's not yet available. In Windows it will probably never be available.Gravity
tv_sec and tv_usec are long, whereas srand() takes unsigned int. truncate?Leighton
@LokiAstari I know this is late but where is it guaranteed that an unsigned int is 32 bits. the only thing I have seen in the standard about a minimum for unsigned int is that it must have a range of [0, 65,535]. see this: en.wikipedia.org/wiki/C_data_typesWillardwillcox
@NathanOliver: It is only guaranteed to be at least 16 bits. https://mcmap.net/q/16584/-what-is-the-difference-between-an-int-and-a-long-in-c But I don't say it is 32 bits I just say on 32 bits systems. What I am implying is that on systems where sizeof(int) * CHAR_BITS >= 32 this is what will happen. I deleted my mistaken comment.Checkroom
Why are C++ <random> or Boost better options? Does either implementation act as a front-end for /dev/random?Anastigmat
@CiroSantilli烏坎事件2016六四事件法轮功 No these are higher level library than what is produced by /dev/random. It allows you to use different random number generators both pseudo generators and rand devices (like /dev/random). But also provides distributors on top of the random generators to allow you to have different random distributions (like uniform/binomial/poisson etc).Checkroom
Read answers further down today, random_device interfaces to /dev/urandom, making it the best answer to seeding: https://mcmap.net/q/65908/-recommended-way-to-initialize-srandAnastigmat
@CiroSantilli烏坎事件2016六四事件法轮功 If you are going to use the new random libraries then just use them. There is no point using a good random number library to seed a bad random number library. If you have initialized a good random number generator just use it. Which is the first line of this answer.Checkroom
This is a really bad answer. It is trivially easy to predict values returned by a rand() seeded with time with only a few values leaked.Endotoxin
Yes but a PRNG is only as good as its seed. if I can predict the seed, your PRNG might as well just return a constant value every time. The problem is not that you suggest rand as an alternative to random, it's that you recommends seeding with a value based on time. /dev/urandom would be much better for seeding.Endotoxin
@Endotoxin Also it solved the OP question. So your point is invalid (there is no requirement here for non predictability).Checkroom
If you need predictability then just seed it with a constant? I fail to see any scenario where seeding with time could be beneficial. Seeding with time offers literally no value over /dev/urandom. OP (or other readers) might not be aware of how easy predicting time-based seeds is, there should at least be a disclaimer...Endotoxin
return 4; is also portable everywhere.Endotoxin
Portability was, as per OP request, only a bonus (non essential). My point about return 4 is that going for the "bonus" option should not go to the detriment of the answer. We don't know how OP (nor the people who are gonna read your post) are gonna use their PRNG. To claim "non-predictability" is not a real requirement is short sighted and foolish.Endotoxin
If you use time(), EVERYONE can predict the next value. If you use /dev/urandom, only the one running the application can. You can't predict the next value if you don't know the seed, at least not until you complete a full rand() cycle. A game (your example) is a great example of scenario where you might not want predictability while still not requiring the same level of randomness that encryption requires. Say I make a game of poker. What happens if I can predict the next card being drawn? I can now win against every other players very easily (and unfairly).Endotoxin
Not everyone aspire to make an insignificant game that nobody cares about. For any competitive game online involving some kind of PRNG (so, almost every single one of them), your answer is downright dangerous and it doesn't even offer a single WARNING about the exploitability of such code. All because you'd rather people know how to make portable code rather than secure code? This is beyond ridiculous. People like you are the reasons why security flaws are so easy to find in literally every commercial applications.Endotoxin
Your first line doesn't even answer the question, which is how to initialize srand. As for the rest of your answer, you literally claimed that The best way [to init srand] is just to use time(). You offer no trade offs, no warning. Just "this is the best way" without even explaining what about it is better over other solutions. So why are you talking to me about context when your answers completely ignore all the scenarios where it is wrong (and dangerous)?Endotoxin
std::srand(std::time(nullptr)); gives a warning about truncation from 64 to 32 bitRuthie
@ThomasWeller You should be using std::random at this point.Checkroom
C
77

This is what I've used for small command line programs that can be run frequently (multiple times a second):

unsigned long seed = mix(clock(), time(NULL), getpid());

Where mix is:

// Robert Jenkins' 96 bit Mix Function
unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
{
    a=a-b;  a=a-c;  a=a^(c >> 13);
    b=b-c;  b=b-a;  b=b^(a << 8);
    c=c-a;  c=c-b;  c=c^(b >> 13);
    a=a-b;  a=a-c;  a=a^(c >> 12);
    b=b-c;  b=b-a;  b=b^(a << 16);
    c=c-a;  c=c-b;  c=c^(b >> 5);
    a=a-b;  a=a-c;  a=a^(c >> 3);
    b=b-c;  b=b-a;  b=b^(a << 10);
    c=c-a;  c=c-b;  c=c^(b >> 15);
    return c;
}
Cadenza answered 27/11, 2008 at 9:20 Comment(2)
Good idea involving the pid. The code source link has gone stale, it's still on archive - the source of that specific code named "Robert Jenkins' 96 bit Mix Function" in that text is actually linked as well: burtleburtle.net/bob/hash/doobs.htmlMylander
Another nice mix, though less portable without a bit of preprocessor conditional inclusion is mix (clock(), time(NULL), ts.tv_nsec) where the struct timespec is filled by clock_gettime (CLOCK_MONOTONIC_RAW, &ts); on Linux (_GNU_SOURCE) Or for windows microseconds can be used from QueryPerformanceCounter()Bipolar
C
67

The best answer is to use <random>. If you are using a pre C++11 version, you can look at the Boost random number stuff.

But if we are talking about rand() and srand()
The best simplest way is just to use time():

int main()
{
    srand(time(nullptr));

    ...
}

Be sure to do this at the beginning of your program, and not every time you call rand()!


Side Note:

NOTE: There is a discussion in the comments below about this being insecure (which is true, but ultimately not relevant (read on)). So an alternative is to seed from the random device /dev/random (or some other secure real(er) random number generator). BUT: Don't let this lull you into a false sense of security. This is rand() we are using. Even if you seed it with a brilliantly generated seed it is still predictable (if you have any value you can predict the full sequence of next values). This is only useful for generating "pseudo" random values.

If you want "secure" you should probably be using <random> (Though I would do some more reading on a security informed site). See the answer below as a starting point: https://mcmap.net/q/65908/-recommended-way-to-initialize-srand for a better answer.

Secondary note: Using the random device actually solves the issues with starting multiple copies per second better than my original suggestion below (just not the security issue).


Back to the original story:

Every time you start up, time() will return a unique value (unless you start the application multiple times a second). In 32 bit systems, it will only repeat every 60 years or so.

I know you don't think time is unique enough but I find that hard to believe. But I have been known to be wrong.

If you are starting a lot of copies of your application simultaneously you could use a timer with a finer resolution. But then you run the risk of a shorter time period before the value repeats.

OK, so if you really think you are starting multiple applications a second.
Then use a finer grain on the timer.

 int main()
 {
     struct timeval time; 
     gettimeofday(&time,NULL);

     // microsecond has 1 000 000
     // Assuming you did not need quite that accuracy
     // Also do not assume the system clock has that accuracy.
     srand((time.tv_sec * 1000) + (time.tv_usec / 1000));

     // The trouble here is that the seed will repeat every
     // 24 days or so.

     // If you use 100 (rather than 1000) the seed repeats every 248 days.

     // Do not make the MISTAKE of using just the tv_usec
     // This will mean your seed repeats every second.
 }
Checkroom answered 27/11, 2008 at 5:30 Comment(26)
Actually, I am starting multiple instances of my app a second :)Amadoamador
I saw somewhere solution that works with timeval/gettimeofday.... ah, yes, my own!! You criticised that its VERY BAD, although chances are 1/1000000 that it will repeat (with the same assumptions you made). And yours is 1/60000. So, it's my solution, only worse, and it is presented as yours.Nichrome
1) Don't assume the clock resolution is 1/1000000. 2) My probability is 1/2147483648 (note the tv_sec). 3) seed repeats is 24 days apart (interaction between apps is also important).Checkroom
Your solution is a well known anti-pattern. My solution is not mine, it is a well known better solution to the one you presented (time to read some books ;-)Checkroom
"seed repeats is 24 days apart" You have 1000 collisions in a second.Nichrome
I have a 1/1000 probability of a collision in any 1 sec. Where the seed overlaps every 24 days. Which is why I prefer to use time() where seed only overlaps every 60 years.Checkroom
Dividing tv_usec by 1000 throws away all of the entropy. Milliseconds are easily predictable, and in fact it's easy to run a program twice within less than a millisecond...Mutate
Side note: gettimeofday is obsolete in POSIX 2008. Instead, it introduces clock_gettime which may require linking with -lrt. It may not yet be available on many platforms, though. In Linux this is alright. On Mac I think it's not yet available. In Windows it will probably never be available.Gravity
tv_sec and tv_usec are long, whereas srand() takes unsigned int. truncate?Leighton
@LokiAstari I know this is late but where is it guaranteed that an unsigned int is 32 bits. the only thing I have seen in the standard about a minimum for unsigned int is that it must have a range of [0, 65,535]. see this: en.wikipedia.org/wiki/C_data_typesWillardwillcox
@NathanOliver: It is only guaranteed to be at least 16 bits. https://mcmap.net/q/16584/-what-is-the-difference-between-an-int-and-a-long-in-c But I don't say it is 32 bits I just say on 32 bits systems. What I am implying is that on systems where sizeof(int) * CHAR_BITS >= 32 this is what will happen. I deleted my mistaken comment.Checkroom
Why are C++ <random> or Boost better options? Does either implementation act as a front-end for /dev/random?Anastigmat
@CiroSantilli烏坎事件2016六四事件法轮功 No these are higher level library than what is produced by /dev/random. It allows you to use different random number generators both pseudo generators and rand devices (like /dev/random). But also provides distributors on top of the random generators to allow you to have different random distributions (like uniform/binomial/poisson etc).Checkroom
Read answers further down today, random_device interfaces to /dev/urandom, making it the best answer to seeding: https://mcmap.net/q/65908/-recommended-way-to-initialize-srandAnastigmat
@CiroSantilli烏坎事件2016六四事件法轮功 If you are going to use the new random libraries then just use them. There is no point using a good random number library to seed a bad random number library. If you have initialized a good random number generator just use it. Which is the first line of this answer.Checkroom
This is a really bad answer. It is trivially easy to predict values returned by a rand() seeded with time with only a few values leaked.Endotoxin
Yes but a PRNG is only as good as its seed. if I can predict the seed, your PRNG might as well just return a constant value every time. The problem is not that you suggest rand as an alternative to random, it's that you recommends seeding with a value based on time. /dev/urandom would be much better for seeding.Endotoxin
@Endotoxin Also it solved the OP question. So your point is invalid (there is no requirement here for non predictability).Checkroom
If you need predictability then just seed it with a constant? I fail to see any scenario where seeding with time could be beneficial. Seeding with time offers literally no value over /dev/urandom. OP (or other readers) might not be aware of how easy predicting time-based seeds is, there should at least be a disclaimer...Endotoxin
return 4; is also portable everywhere.Endotoxin
Portability was, as per OP request, only a bonus (non essential). My point about return 4 is that going for the "bonus" option should not go to the detriment of the answer. We don't know how OP (nor the people who are gonna read your post) are gonna use their PRNG. To claim "non-predictability" is not a real requirement is short sighted and foolish.Endotoxin
If you use time(), EVERYONE can predict the next value. If you use /dev/urandom, only the one running the application can. You can't predict the next value if you don't know the seed, at least not until you complete a full rand() cycle. A game (your example) is a great example of scenario where you might not want predictability while still not requiring the same level of randomness that encryption requires. Say I make a game of poker. What happens if I can predict the next card being drawn? I can now win against every other players very easily (and unfairly).Endotoxin
Not everyone aspire to make an insignificant game that nobody cares about. For any competitive game online involving some kind of PRNG (so, almost every single one of them), your answer is downright dangerous and it doesn't even offer a single WARNING about the exploitability of such code. All because you'd rather people know how to make portable code rather than secure code? This is beyond ridiculous. People like you are the reasons why security flaws are so easy to find in literally every commercial applications.Endotoxin
Your first line doesn't even answer the question, which is how to initialize srand. As for the rest of your answer, you literally claimed that The best way [to init srand] is just to use time(). You offer no trade offs, no warning. Just "this is the best way" without even explaining what about it is better over other solutions. So why are you talking to me about context when your answers completely ignore all the scenarios where it is wrong (and dangerous)?Endotoxin
std::srand(std::time(nullptr)); gives a warning about truncation from 64 to 32 bitRuthie
@ThomasWeller You should be using std::random at this point.Checkroom
B
17

if you need a better random number generator, don't use the libc rand. Instead just use something like /dev/random or /dev/urandom directly (read in an int directly from it or something like that).

The only real benefit of the libc rand is that given a seed, it is predictable which helps with debugging.

Blasien answered 27/11, 2008 at 4:54 Comment(6)
On Windows you can use rand_s.Billposter
You should not read repeatedly from /dev/urandom for random numbers, just for the seed. It's much slower, and depletes the system entropy pool.Mutate
Just to nitpick here: every PRNG is predictable, given the same seed. That's what the Pseudo means in PRNG.Goosy
@vanneto, When you figure out how to seed /dev/random to make it fully predictable, let me know :-P. It too is a PRNG.Blasien
std::random_device is a portable wrapper over /dev/urandom in glibc: https://mcmap.net/q/65908/-recommended-way-to-initialize-srandAnastigmat
It is recommended to use getrandom() rather than reading /dev/urandom directly. Reading a device is vulnerable to file descriptor exhaustion attacks. Another difference versus urandom is that getrandom() will block until at least 128 bits of entropy have been gathered by the kernel.Saintsimonianism
C
13

On windows:

srand(GetTickCount());

provides a better seed than time() since its in milliseconds.

Cumming answered 27/11, 2008 at 8:34 Comment(5)
You need to be careful though: "the time will wrap around to zero if the system is run continuously for 49.7 days. To avoid this problem, use the GetTickCount64 function". If it gets to the point where it's always zero this will generate bad results.Gallant
@Gallant Wrapping around zero means that it starts counting from zero again in every 49.7 days, not that it is unusable after 49.7 days of uptime.Emmalynn
@Gallant why would wrapping matter? you should only be calling srand() once when the app starts anyways.Chrystal
@DanBechard Uh...when looking at my 9 year old comment I think I misunderstood the sentence I quoted, as pointed out by Csq before. Wrapping around would indeed not be an issue, but I assumed it would be 0 indefinitely.Gallant
@Gallant Ah, that's a reasonable misinterpretation, never thought of it like that heh. I did notice your comment was from eons ago, but still wanted to leave an updated comment for people landing here from google in the modern era. Hope your last 9 years have gone well. :)Chrystal
B
9

C++11 random_device

If you need reasonable quality then you should not be using rand() in the first place; you should use the <random> library. It provides lots of great functionality like a variety of engines for different quality/size/performance trade-offs, re-entrancy, and pre-defined distributions so you don't end up getting them wrong. It may even provide easy access to non-deterministic random data, (e.g., /dev/random), depending on your implementation.

#include <random>
#include <iostream>

int main() {
    std::random_device r;
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
    std::mt19937 eng(seed);

    std::uniform_int_distribution<> dist{1,100};

    for (int i=0; i<50; ++i)
        std::cout << dist(eng) << '\n';
}

eng is a source of randomness, here a built-in implementation of mersenne twister. We seed it using random_device, which in any decent implementation will be a non-determanistic RNG, and seed_seq to combine more than 32-bits of random data. For example in libc++ random_device accesses /dev/urandom by default (though you can give it another file to access instead).

Next we create a distribution such that, given a source of randomness, repeated calls to the distribution will produce a uniform distribution of ints from 1 to 100. Then we proceed to using the distribution repeatedly and printing the results.

Bugeye answered 22/10, 2012 at 3:12 Comment(0)
N
8

Best way is to use another pseudorandom number generator. Mersenne twister (and Wichmann-Hill) is my recommendation.

http://en.wikipedia.org/wiki/Mersenne_twister

Nichrome answered 27/11, 2008 at 4:55 Comment(8)
I was just about to suggest this generator. I've used it for many scientific modelling problems, and it produces much better results than alternatives I have seen. math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.htmlUltimate
If you have access to a better RNG, why use it to seed the standard one? Just use the better one!Olympias
that was essentially my suggestion :-PBlasien
@Pax: USE another PRNG, not use PRNG as seed! Seeding PRNG with better PRNG, who would do something like that?? :DNichrome
Sorry, @sharpsy, just naturally combined question with your answer to get "use another RNG to seed standard one". My bad.Olympias
It seems odd to me that in order to come up with a good pseudo-random number, you need to first come up with a good pseudo-random number. :-)Massacre
Mersenne twister is good pseudo-random number generator. It's meant to be used instead of rand() (if 'randomness' is important), not for srand().Nichrome
this does not solve the question at all, how do you seed the MT PRNG?Honkytonk
A
7

i suggest you see unix_random.c file in mozilla code. ( guess it is mozilla/security/freebl/ ...) it should be in freebl library.

there it uses system call info ( like pwd, netstat ....) to generate noise for the random number;it is written to support most of the platforms (which can gain me bonus point :D ).

Alfy answered 27/11, 2008 at 6:7 Comment(0)
F
6

The real question you must ask yourself is what randomness quality you need.

libc random is a LCG

The quality of randomness will be low whatever input you provide srand with.

If you simply need to make sure that different instances will have different initializations, you can mix process id (getpid), thread id and a timer. Mix the results with xor. Entropy should be sufficient for most applications.

Example :

struct timeb tp;
ftime(&tp);   
srand(static_cast<unsigned int>(getpid()) ^ 
static_cast<unsigned int>(pthread_self()) ^ 
static_cast<unsigned int >(tp.millitm));

For better random quality, use /dev/urandom. You can make the above code portable in using boost::thread and boost::date_time.

Fatherland answered 27/11, 2008 at 13:24 Comment(0)
B
4

The c++11 version of the top voted post by Jonathan Wright:

#include <ctime>
#include <random>
#include <thread>

...

const auto time_seed = static_cast<size_t>(std::time(0));
const auto clock_seed = static_cast<size_t>(std::clock());
const size_t pid_seed =
      std::hash<std::thread::id>()(std::this_thread::get_id());

std::seed_seq seed_value { time_seed, clock_seed, pid_seed };

...
// E.g seeding an engine with the above seed.
std::mt19937 gen;
gen.seed(seed_value);
Brigade answered 22/3, 2015 at 4:20 Comment(0)
N
2
#include <stdio.h>
#include <sys/time.h>
main()
{
     struct timeval tv;
     gettimeofday(&tv,NULL);
     printf("%d\n",  tv.tv_usec);
     return 0;
}

tv.tv_usec is in microseconds. This should be acceptable seed.

Nichrome answered 27/11, 2008 at 9:13 Comment(7)
This is a VERY BAD idea. The seed repeats every second. If you start the application multiple times you get a high probability you will get the same seed.Checkroom
VERY BAD? 1/1000000 (yes, that's a one in a milion) chances of repeating? If you feel that lucky, go buy a lottery ticket! 9.5367431640625e-07 (less than a usecond) measured with python: from time import time abs(time()-time()) #on windows use clock()-clock()Nichrome
That's great if you only buy one lottery ticket. But if you are buying 1 lottery ticket a second how often do you get a hit. probability says 36 hits a year. My method 1/2147483648 chance repeated every 24 days, in 1 year that's 1/143165576 hits a year!Checkroom
"chance repeated every 24 days" :D How did you come up with that? Sec=X+1, USec<1000... You have collision 1000 times in a second.Nichrome
I use tv_sec: based on the epoch. It repeats every 60 years. Module this by 1000 (I knock of the top bits by multiplying by 1000). This gives you a value that repeats every 24 days. I then insert uSec in the bottom bits. I thus have a time with mili second precision that repeats every 24 days.Checkroom
You are using a micro precision timer that repeats every second.Checkroom
This very discussion is an example of why rand (like cryptography) is difficult to get correct and why people should be using boost::rand and not trying to roll their own. Unless you are an expert on the subject, then there are many pitfalls where the pseudo random numbers become less than random.Checkroom
C
2

As long as your program is only running on Linux (and your program is an ELF executable), you are guaranteed that the kernel provides your process with a unique random seed in the ELF aux vector. The kernel gives you 16 random bytes, different for each process, which you can get with getauxval(AT_RANDOM). To use these for srand, use just an int of them, as such:

#include <sys/auxv.h>

void initrand(void)
{
    unsigned int *seed;

    seed = (unsigned int *)getauxval(AT_RANDOM);
    srand(*seed);
}

It may be possible that this also translates to other ELF-based systems. I'm not sure what aux values are implemented on systems other than Linux.

Camboose answered 6/12, 2017 at 15:0 Comment(0)
M
0

Suppose you have a function with a signature like:

int foo(char *p);

An excellent source of entropy for a random seed is a hash of the following:

  • Full result of clock_gettime (seconds and nanoseconds) without throwing away the low bits - they're the most valuable.
  • The value of p, cast to uintptr_t.
  • The address of p, cast to uintptr_t.

At least the third, and possibly also the second, derive entropy from the system's ASLR, if available (the initial stack address, and thus current stack address, is somewhat random).

I would also avoid using rand/srand entirely, both for the sake of not touching global state, and so you can have more control over the PRNG that's used. But the above procedure is a good (and fairly portable) way to get some decent entropy without a lot of work, regardless of what PRNG you use.

Mutate answered 10/5, 2011 at 5:19 Comment(0)
O
0

For those using Visual Studio here's yet another way:

#include "stdafx.h"
#include <time.h>
#include <windows.h> 

const __int64 DELTA_EPOCH_IN_MICROSECS= 11644473600000000;

struct timezone2 
{
  __int32  tz_minuteswest; /* minutes W of Greenwich */
  bool  tz_dsttime;     /* type of dst correction */
};

struct timeval2 {
__int32    tv_sec;         /* seconds */
__int32    tv_usec;        /* microseconds */
};

int gettimeofday(struct timeval2 *tv/*in*/, struct timezone2 *tz/*in*/)
{
  FILETIME ft;
  __int64 tmpres = 0;
  TIME_ZONE_INFORMATION tz_winapi;
  int rez = 0;

  ZeroMemory(&ft, sizeof(ft));
  ZeroMemory(&tz_winapi, sizeof(tz_winapi));

  GetSystemTimeAsFileTime(&ft);

  tmpres = ft.dwHighDateTime;
  tmpres <<= 32;
  tmpres |= ft.dwLowDateTime;

  /*converting file time to unix epoch*/
  tmpres /= 10;  /*convert into microseconds*/
  tmpres -= DELTA_EPOCH_IN_MICROSECS; 
  tv->tv_sec = (__int32)(tmpres * 0.000001);
  tv->tv_usec = (tmpres % 1000000);


  //_tzset(),don't work properly, so we use GetTimeZoneInformation
  rez = GetTimeZoneInformation(&tz_winapi);
  tz->tz_dsttime = (rez == 2) ? true : false;
  tz->tz_minuteswest = tz_winapi.Bias + ((rez == 2) ? tz_winapi.DaylightBias : 0);

  return 0;
}


int main(int argc, char** argv) {

  struct timeval2 tv;
  struct timezone2 tz;

  ZeroMemory(&tv, sizeof(tv));
  ZeroMemory(&tz, sizeof(tz));

  gettimeofday(&tv, &tz);

  unsigned long seed = tv.tv_sec ^ (tv.tv_usec << 12);

  srand(seed);

}

Maybe a bit overkill but works well for quick intervals. gettimeofday function found here.

Edit: upon further investigation rand_s might be a good alternative for Visual Studio, it's not just a safe rand(), it's totally different and doesn't use the seed from srand. I had presumed it was almost identical to rand just "safer".

To use rand_s just don't forget to #define _CRT_RAND_S before stdlib.h is included.

Oosperm answered 16/1, 2013 at 4:57 Comment(3)
In your linked post it uses / 1000000UL for gettimeofday. As far as I can see, your * 0.000001 produces weird (negative) results. Should this be fixed in your code?Gallant
it was copied from https://mcmap.net/q/66681/-how-to-use-gettimeofday-or-something-equivalent-with-visual-studio-c-2008 don't see how you get negatives, typo, missing line?Oosperm
Don't know (though I'm pretty sure it's not a typo), I didn't look into it further and used rand_s in the end anyway. But this post social.msdn.microsoft.com/Forums/vstudio/en-US/… also uses the / 1000000UL method, seems safer to me. So if someone is using this code it should be verified that it's working properly at this line.Gallant
I
0

Assuming that the randomness of srand() + rand() is enough for your purposes, the trick is in selecting the best seed for srand. time(NULL) is a good starting point, but you'll run into problems if you start more than one instance of the program within the same second. Adding the pid (process id) is an improvement as different instances will get different pids. I would multiply the pid by a factor to spread them more.

But let's say you are using this for some embedded device and you have several in the same network. If they are all powered at once and you are launching the several instances of your program automatically at boot time, they may still get the same time and pid and all the devices will generate the same sequence of "random" numbers. In that case, you may want to add some unique identifier of each device (like the CPU serial number).

The proposed initialization would then be:

srand(time(NULL) + 1000 * getpid() + (uint) getCpuSerialNumber()); 

In a Linux machine (at least in the Raspberry Pi where I tested this), you can implement the following function to get the CPU Serial Number:

// Gets the CPU Serial Number as a 64 bit unsigned int. Returns 0 if not found.
uint64_t getCpuSerialNumber() {

    FILE *f = fopen("/proc/cpuinfo", "r");
    if (!f) {
        return 0;
    }

    char line[256];
    uint64_t serial = 0;
    while (fgets(line, 256, f)) {
        if (strncmp(line, "Serial", 6) == 0) {
            serial = strtoull(strchr(line, ':') + 2, NULL, 16);
        }
    }
    fclose(f);

    return serial;
}
Inaccuracy answered 11/10, 2019 at 20:2 Comment(1)
1000 * getpid() loses 3 bits of the pid when converting to unsigned. Consider 997.Pearle
L
-2

Include the header at the top of your program, and write:

srand(time(NULL));

In your program before you declare your random number. Here is an example of a program that prints a random number between one and ten:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
   //Initialize srand
   srand(time(NULL));

   //Create random number
   int n = rand() % 10 + 1;

   //Print the number
   cout << n << endl; //End the line

   //The main function is an int, so it must return a value
   return 0;
}
Lobation answered 21/12, 2014 at 21:33 Comment(1)
Despite time(NULL) being acceptable in some contexts, you shouldn't recommend such strategy for initialization srand() without exposing the cons. For instance, in a scenario with many processes being init in the same second, your example would generate the same result in each process. This behavior may not be what the user expect.Illegalize

© 2022 - 2024 — McMap. All rights reserved.