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

回眸只為那壹抹淺笑 提交于 2019-11-28 01:15:20

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

The problem is that computers are so fast that the std::time(0) function will not have changed between calls to std::srand() if you call std::srand() each time you ask for a random number std::srand() will keep being reset to produce the same sequence of numbers until the std::time() function returns a different time (one second later).

In one second you can end up with the same number being produced millions of times! That's not very random.

aso

Look at the source of srand() from this question: Rand Implementation

Also, 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 calling srand(time(0)) you will got new numbers on rand() depends on seed. Numbers will repeat after some milions, but calling srand again will make it other. Anyway, it must repeat after some cycles - but order depends on argument for srand. This is why C rand isn't good for cryptography - you can predict next number when you know seed.

If you have fast loop, calling srand every iteration is without sense - you can got same number while your time() (1 second is very big time for modern CPUs) give another seed.

There is no reason in simple app to call srand multiple times - this generator are weak by design and if you want real random numbers, you must use other (the best I know is Blum Blum Shub)

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

The numbers rand() returns are not actually random but "pseudo-random." What this means is that rand() generates a stream of numbers that look random for given values of "look" and "random" from an internal state that changes with each call.

As a rule, rand() is what is called a linear congruental generator, which means that uses a mechanism roughly like this:

int state; // persistent state

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

with carefully chosen constants a, b and c. c tends to be a power of two in practice because that makes it faster to calculate.

The "randomness" of this sequence depends in part on the persistence of the state. If the sequence is constantly reseeded with predictable values, the return values of rand() become predictable in turn. How critical this is depends on the application, but it is not a purely academical consideration. Consider, for example, the case

a = 69069
b = 1
c = 2^32

which was used, for example, by old versions of glibc. Granted that I picked this example for the obviousness of the pattern, but the point remains in less obvious cases. Imagine this RNG were seeded with a sequence of incrementing numbers n, n+1, n+2 and so forth -- you will get from rand() a sequence of numbers, each 69069 larger than the last (modulo 2^32). The pattern will be plainly visible. Starting with 0, we would get

1
69070
138139
207208
...

rising until a bit over 4 billion in steady increments. And to make matters worse, some implementation actually returned the seed value in the first call of rand after a call to srand, in which case you'd just get your seeds back.

A pseudo random generator is an engine which produce numbers that look almost random. However, they are completely deterministic. In other words, given a seed x0, they are produced by repeated application of some injective function on x0, call it f(x0), so that f^m(x0) is quite different from f^{m-1}(x0) or f^{m+1}(x0), where the notation f^m denotes the function composition m times. In other words, f(x) has huge jumps, almost uncorrelated with the previous ones.

If you use sradnd(time) multiple times in a second, you may get the same seed, as the clock is not as fast as you may imagine. So the resulting sequence of random numbers will be the same. And this may be a (huge) problem, especially in cryptography applications (anyway, in the latter case, people buy good number generators based on real-time physical processes such as temperature difference in atmospheric data etc, or, recently, on measuring quantum bits, e.g. superposition of polarized photons, the latter being truly random, as long as quantum mechanics is correct.)

There are also other serious issues with rand. One of it is that the distribution is biased. See e.g. http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx for some discussion, although I remember I've seen something similar on SO, although cannot find it now.

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

If you seed your random number generator twice using srand, and get different seeds, then you will get two sequences that will be quite different. This may be satisfactory for you. However, each sequence per se will not be a good random distribution due to the issues I mentioned above. On the other hand, if you seed your rng too many times, you will get the same seed, and THIS IS BAD, as you'll generate the same numbers over and over again.

PS: seen in the comments that pseudo-numbers depend on a seed, and this is bad. This is the definition of pseudo-numbers, and it is not a bad thing as it allows you to repeat numerical experiments with the same sequence. The idea is that each different seed should produce a sequence of (almost) random numbers, different from a previous sequence (technically, you shouldn't be able to distinguish them from a perfect random sequence).

The seed determines what 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 on the second call to rand() and so on.

In other words, if you re-seeded with the same seed before each rand() invocation, you'd generate the same random number every single time.

So successive seeding with time(0), during a single second, will mean all your random numbers after re-seeding are actually the same number.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!