How does calling srand affect the quality of randomness more than once?

This comment , which reads:

srand(time(0)); I would put this line as the first line in main () instead if you call it several times ( which will actually result in less random numbers ).

... and I highlighted the line with which I had a problem ... repeats the general advice for calling srand once in the program. Questions like srand () - why call only once? repeat the iteration because time(0) returns the current time in seconds, so that several calls to srand in the same second one will produce the same seed. A common solution is to use milliseconds or nanoseconds instead.

However, I do not understand why this means that srand needed or can only be called once, or how it leads to less random numbers.

cppreference :

Generally speaking, a pseudo-random number generator should be only once, before any calls to rand () and the start of the program. It should not be repeatedly sown or repeated every time you want to create a new batch of pseudo-random numbers.

phoxis answer srand () - why call only once? :

Initialization, when enough random numbers are generated with the initial state with the initial value, since you do not set the internal state with srand , which makes the number more likely random.

Maybe they just use an inaccurate language, none of the explanations seem to explain why calling srand bad several times (besides creating the same sequence of random numbers) or how it affects the "randomness" of numbers. Can someone clarify this is for me?

+6
source share
5 answers

The std::time(0) function returns the time in seconds.

The problem is that the computers are so fast that the function std::time(0) will not be changed between calls to std::srand() if you call std::srand() every time you ask for a random number of std::srand() , will remain reset to get the same sequence of numbers until the std::time() function returns a different time (after a second).

In a second you can get the same number that is produced millions of times! This is not very random.

+5
source

Look at srand() source for this question: Rand implementation

In addition, an example implementation from this thread:

 static unsigned long int next = 1; int rand(void) // RAND_MAX assumed to be 32767 { next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768; } void srand(unsigned int seed) { next = seed; } 

As you can see, when you call srand(time(0)) you will get new digits on rand() , depending on the seed. The numbers will repeat after a few million, but calling srand again will make it different. In any case, it should be repeated after some cycles, but the order depends on the argument for srand . This is why C rand is not suitable for cryptography - you can predict the next number when you know the seeds.

If you have a fast loop, calling srand for each iteration makes no sense - you can get the same number while your time() (1 second is a very big time for modern processors) gives another seed.

In a simple application there is no reason to call srand several times - this generator is weak in design, and if you need real random numbers, you should use others (the best I know is Blum Blum Shub)

For me there are no more or less random numbers - it always depends on the seed, and they are repeated if you use the same seed. Using time is a good solution because it is easy to implement, but you should only use one (at the beginning of main() ) or when you are sure that you are calling srand(time(0)) in another second.

+3
source

A pseudo-random generator is an engine that produces numbers that look almost random. However, they are completely deterministic. In other words, given the seed x0 , they are created by repeatedly applying some injective function to x0 , call it f(x0) , so f^m(x0) very different from f^{m-1}(x0) or f^{m+1}(x0) , where the designation f^m denotes the functional composition m times. In other words, f(x) has huge jumps, almost uncorrelated with the previous ones.

If you use sradnd(time) several times per second, you can get the same seed, since the clock is not as fast as you can imagine. Thus, the resulting sequence of random numbers will be the same. And this can be a (huge) problem, especially in cryptographic applications (in any case, in the latter case, people buy good number generators based on real-time physical processes, such as the temperature difference in atmospheric data, etc. or, recently , for measuring quantum bits, for example, the imposition of polarized photons, the latter being really random if quantum mechanics is correct.)

There are other serious problems with rand . One of them is that the distribution is biased. See http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx for a discussion, although I remember that I saw something similar on SO, although I cannot find it now.

If you plan to use it in cryptographic applications, just don't do it. Use <random> and a serious random engine like Mersene twister std::mt19937 in combination with std::random_device

If you generate a random number generator twice using srand and get different seeds, then you will get two sequences that will be completely different. This may be satisfactory to you. However, each sequence alone will not be a good random distribution due to the problems mentioned above. On the other hand, if you use too much time for your rng, you will get the same seed, and THIS IS BAD, since you will generate the same numbers again and again.

PS: in the comments you can see that pseudo-numbers depend on the seed, and this is bad. This is a definition of pseudo-numbers, and it’s not so bad because it allows you to repeat numerical experiments with the same sequence. The idea is that every other seed should produce a sequence of (almost) random numbers different from the previous sequence (technically you cannot distinguish them from an ideal random sequence).

+2
source

The digits of rand() are actually returned not random, but "pseudo-random." This means that rand() generates a stream of numbers that look random for the given "look" and "random" values ​​from the internal state, which changes with every call.

Typically, rand() is what is called a linear congruent generator, which means it uses something like this:

 int state; // persistent state int rand() { state = (a * state + b) % c; return state; } 

with carefully chosen constants a , b and c . c in practice tends to be two, because it speeds up the calculation.

The "randomness" of this sequence depends in part on state preservation. If the sequence is constantly being pumped with predictable values, the returned rand() values ​​become more predictable. How important this is depends on the application, but this is not a purely academic consideration. Consider, for example, the case

 a = 69069 b = 1 c = 2^32 

which was used, for example, by older versions of glibc. Of course, I chose this example for the obviousness of the pattern, but the point remains in less obvious cases. Imagine that this RNG was seeded with a sequence of incremental numbers n, n + 1, n + 2, etc. - you will get a sequence of numbers from rand() , each of which is 69069 more than the last (modulo 2 ^ 32). The template will be clearly visible. Starting at 0, we get

 1 69070 138139 207208 ... 

growing to just over 4 billion in constant increments. And to make matters worse, some implementations actually returned the initial value on the first call to rand after calling srand , in which case you will simply return your seeds.

+2
source

The seed determines which random numbers will be generated, in order, i.e. srand(1) will always generate the same number on the first call to rand() , the same thing on the second call to rand() and so on.

In other words, if you re-sow the same seed before each rand() call, you must generate the same random number every time.

Thus, sequential seeding with time(0) for one second will mean that all your random numbers after re-seeding are actually equal to the number.

+1
source

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


All Articles