C语言 srand()——为什么只调用一次?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7343833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:35:53  来源:igfitidea点击:

srand() — why call it only once?

crandomsrand

提问by Lipika Deka

This question is about a comment in this question Recommended way to initialize srand?The first comment says that srand()should be called only ONCE in an application. Why is it so?

这个问题是关于这个问题的评论 推荐的初始化srand的方法?第一条评论说srand()在应用程序中应该只调用一次。为什么会这样?

回答by Kornelije Petak

That depends on what you are trying to achieve.

这取决于您要实现的目标。

Randomization is performed as a function that has a starting value, namely the seed.

随机化作为具有起始值的函数执行,即种子

So, for the same seed, you will always get the same sequence of values.

因此,对于相同的种子,您将始终获得相同的值序列。

If you try to set the seed every time you need a random value, and the seed is the same number, you will always get the same "random" value.

如果每次需要随机值时都尝试设置种子,并且种子是相同的数字,那么您将始终获得相同的“随机”值。

Seed is usually taken from the current time, which are the seconds, as in time(NULL), so if you always set the seed before taking the random number, you will get the same number as long as you call the srand/rand combo multiple times in the same second.

种子通常取自当前时间,也就是秒,如time(NULL),所以如果你总是在取随机数之前设置种子,只要你在同样的第二

To avoid this problem, srand is set only once per application, because it is doubtful that two of the application instances will be initialized in the same second, so each instance will then have a different sequence of random numbers.

为了避免这个问题,每个应用程序只设置一次 srand,因为两个应用程序实例是否会在同一秒内被初始化是值得怀疑的,所以每个实例都会有不同的随机数序列。

However, there is a slight possibility that you will run your app (especially if it's a short one, or a command line tool or something like that) many times in a second, then you will have to resort to some other way of choosing a seed (unless the same sequence in different application instances is ok by you). But like I said, that depends on your application context of usage.

但是,您可能会在一秒钟内多次运行您的应用程序(特别是如果它是一个简短的应用程序或命令行工具或类似的东西),那么您将不得不求助于其他方式来选择种子(除非您可以在不同的应用程序实例中使用相同的序列)。但是就像我说的,这取决于您的应用程序使用上下文。

Also, you may want to try to increase the precision to microseconds (minimizing the chance of the same seed), requires (sys/time.h):

此外,您可能想尝试将精度提高到微秒(最小化相同种子的机会),需要 ( sys/time.h):

struct timeval t1;
gettimeofday(&t1, NULL);
srand(t1.tv_usec * t1.tv_sec);

回答by phoxis

Random numbers are actually pseudo random. A seed is set first, from which each call of randgets a random number, and modifies the internal state and this new state is used in the next randcall to get another number. Because a certain formula is used to generate these "random numbers" therefore setting a certain value of seed after every call to randwill return the same number from the call. For example srand (1234); rand ();will return the same value. Initializing once the initial state with the seed value will generate enough random numbers as you do not set the internal state with srand, thus making the numbers more probable to be random.

随机数实际上是伪随机数。首先设置一个种子,每次调用rand都会从中获取一个随机数,并修改内部状态,在下一次rand调用中使用这个新状态来获取另一个数字。因为使用某个公式来生成这些“随机数”,因此在每次调用后设置某个种子值rand将从调用中返回相同的数字。例如srand (1234); rand ();将返回相同的值。使用种子值初始化一次初始状态将生成足够的随机数,因为您没有使用 设置内部状态srand,从而使数字更有可能是随机的。

Generally we use the time (NULL)returned seconds value when initializing the seed value. Say the srand (time (NULL));is in a loop. Then loop can iterate more than once in one second, therefore the number of times the loop iterates inside the loop in a second randcall in the loop will return the same "random number", which is not desired. Initializing it once at program start will set the seed once, and each time randis called, a new number is generated and the internal state is modified, so the next call randreturns a number which is random enough.

通常我们time (NULL)在初始化种子值时使用返回的秒值。说srand (time (NULL));是在一个循环中。然后循环可以在一秒钟内迭代多次,因此循环在循环中的第二次rand调用中在循环内迭代的次数将返回相同的“随机数”,这是不希望的。在程序启动时初始化一次,将设置一次种子,每次rand调用都会生成一个新数字并修改内部状态,因此下一次调用rand返回一个足够随机的数字。

For example this code from http://linux.die.net/man/3/rand:

例如来自http://linux.die.net/man/3/rand 的代码:

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

The internal state nextis declared as global. Each myrandcall will modify the internal state and update it, and return a random number. Every call of myrandwill have a different nextvalue therefore the the method will return the different numbers every call.

内部状态next被声明为全局状态。每次myrand调用都会修改内部状态并更新它,并返回一个随机数。每次调用myrand都会有不同的next值,因此该方法将在每次调用时返回不同的数字。

Look at the mysrandimplementation; it simply sets the seed value you pass to next. Therefore if you set the nextvalue the same everytime before calling randit will return the same random value, because of the identical formula applied on it, which is not desirable, as the function is made to be random.

mysrand实现;它只是设置您传递给的种子值next。因此,如果您next每次在调用之前rand都将值设置为相同的值,则会返回相同的随机值,因为对其应用了相同的公式,这是不可取的,因为该函数是随机的。

But depending on your needs you can set the seed to some certain value to generate the same "random sequence" each run, say for some benchmark or others.

但是根据您的需要,您可以将种子设置为某个特定值,以在每次运行时生成相同的“随机序列”,比如某些基准测试或其他测试。

回答by Steve Summit

Short answer: calling srand()is notlike "rolling the dice" for the random number generator. Nor is it like shuffling a deck of cards. If anything, it's more like just cutting a deck of cards.

简短的回答:呼叫srand()不是就像“掷骰子”随机数发生器。这也不像洗牌。如果有的话,这更像是切一副纸牌。

Think of it like this. rand()deals from a big deck of cards, and every time you call it, all it does is pick the next card off the top of the deck, give you the value, and return that card to the bottom of the deck. (Yes, that means the "random" sequence will repeat after a while. It's a verybig deck, though: typically 4,294,967,296 cards.)

像这样想。 rand()从一副大牌中发牌,每次你叫它时,它所做的就是从一副牌的顶部挑选下一张牌,给你价值,然后把那张牌放回一副牌的底部。(是的,这意味着“随机”序列会在一段时间后重复。不过,这是一副非常大的牌:通常有 4,294,967,296 张牌。)

Furthermore, every time your program runs, a brand-new pack of cards is bought from the game shop, andevery brand-new pack of cards always has the same sequence. So unless you do something special, every time your program runs, it will get exactly the same "random" numbers back from rand().

而且,你的程序每次运行时,都会从游戏商店购买一副全新的卡牌,每一副全新的卡牌顺序总是相同的。所以除非你做了一些特别的事情,否则每次你的程序运行时,它都会从rand().

Now, you might say, "Okay, so how do I shuffle the deck?" And the answer -- at least as far as randand srandare concerned -- is that there is no way of shuffling the deck.

现在,你可能会说,“好吧,那我该如何洗牌呢?” 而答案-至少就randsrand关注-是不存在洗牌甲板的方式。

So what does sranddo? Based on the analogy I've been building here, calling srand(n)is basically like saying, "cut the deck ncards from the top". But wait, one more thing: it's actually start with another brand-new deck and cut it ncards from the top.

那么有什么作用srand呢?根据我在这里建立的类比,跟注srand(n)基本上就像在说“n从顶部剪下套牌”。但是等等,还有一件事:它实际上是从另一副全新的套牌开始,然后n从顶部剪下卡片

So if you call srand(n), rand(), srand(n), rand(), ..., with the same nevery time, you won't just get a not-very-random sequence, you'll actually get the same number back from rand()every time. (Probably not the same number you handed to srand, but the same number back from randover and over.)

因此,如果您每次都以相同的方式调用srand(n), rand(), srand(n), rand(), ... ,n您不仅会得到一个不太随机的序列,而且实际上rand()每次都会得到相同的数字。(可能不是您交给的同一个号码srand,而是rand一遍又一遍地返回相同的号码。)

So the best you can do is to cut the deck once, that is, call srand()once, at the beginning of your program, with an nthat's reasonably random, so that you'll start at a different random place in the big deck each time your program runs. With rand(), that really is the best you can do.

所以你能做的最好的事情就是在你的程序开始时切掉一次,也就是说,调用srand()一次,n它是相当随机的,这样你每次你都会从大牌中的不同随机位置开始程序运行。使用rand(),这确实是您能做的最好的事情。

[P.S. Yes, I know, in real life, when you buy a brand-new deck of cards it's typically in order, not in random order. For the analogy here to work, I'm imagining that each deck you buy from the game shop is in a seemingly random order, but the exact same seemingly-random order as every other deck of cards you buy from that same shop. Sort of like the identically shuffled decks of cards they use in bridge tournaments.]

[PS 是的,我知道,在现实生活中,当你购买一副全新的纸牌时,它通常是按顺序排列的,而不是随机顺序。为了让这里的类比有效,我想象你从游戏商店购买的每一副牌都是看似随机的顺序,但与你从同一家商店购买的其他每一副牌完全相同的看似随机的顺序。有点像他们在桥牌比赛中使用的相同洗牌的纸牌。]

回答by sharptooth

The reason is that srand()sets the initial state of the random generator, and all the values that generator produces are only "random enough" if you don't touch the state yourself in between.

原因是srand()设置随机生成器的初始状态,并且生成器生成的所有值只有“足够随机”,如果您不自己触及两者之间的状态。

For example you could do:

例如你可以这样做:

int getRandomValue()
{
    srand(time(0));
    return rand();
}

and then if you call that function repeatedly so that time()returns the same values in adjacent calls you just get the same value generated - that's by design.

然后,如果您重复调用该函数,以便time()在相邻调用中返回相同的值,您只会生成相同的值——这是设计使然。

回答by achoora

A simpler solution for using srand()for generating different seeds for application instances run at the same second is as seen.

用于srand()为在同一秒运行的应用程序实例生成不同种子的更简单的解决方案如图所示。

srand(time(NULL)-getpid());

This method makes your seed very close to random as there is no way to guess at what time your thread started and the pid will be different also.

这种方法使您的种子非常接近随机,因为无法猜测您的线程何时开始并且 pid 也会不同。

回答by Foo Bah

srand seeds the pseudorandom number generator. If you call it more than once, you will reseed the RNG. And if you call it with the same argument, it will restart the same sequence.

srand 为伪随机数生成器提供种子。如果您多次调用它,您将重新设定 RNG。如果您使用相同的参数调用它,它将重新启动相同的序列。

To prove it, if you do something simple like:

为了证明这一点,如果你做一些简单的事情:

#include <cstdlib>
#include <cstdio>
int main() {
for(int i = 0; i != 100; ++i) {
        srand(0);
        printf("%d\n", rand());
    }
}

you will see the same number printed 100 times.

您将看到打印了 100 次的相同数字。

回答by imoc

1\Seems every time rand() runs, it will set a new seed for the next rand().

1\似乎每次 rand() 运行时,它都会为下一个 rand() 设置一个新的种子。

2\If srand() runs multiple times, the problem is if the two running happen in one second(the time(NULL) does not change), the next rand() will be the same as the rand() right after the previous srand().

2\如果srand()多次运行,问题是如果两次运行发生在一秒内(时间(NULL)不改变),下一个rand()将与前一个rand()相同srand()