该问题与该问题中的评论有关。
建议初始化srand的方法?第一条评论说,srand()应仅在应用程序中调用ONCE。为什么会这样呢?
Answers:
这取决于您要实现的目标。
随机化是作为具有起始值的函数(即seed)执行的。
因此,对于相同的种子,您将始终获得相同的值序列。
如果您每次需要一个随机值时都尝试设置种子,并且种子是相同的数字,则您将始终获得相同的“随机”值。
种子通常从目前的时间,这是秒,在拍摄time(NULL),所以如果你总是设置种子取随机数之前,你会得到相同的数量,只要你调用函数srand /兰特组合多次在同一秒。
为避免此问题,每个应用程序只能设置一次srand,因为两个应用程序实例将在同一秒内初始化是令人怀疑的,因此每个实例将具有不同的随机数序列。
但是,您极有可能在一秒钟内多次运行您的应用程序(特别是短程序或命令行工具之类的应用程序),那么您将不得不采用其他方法来选择种子(除非您可以在不同的应用程序实例中使用相同的顺序)。但是就像我说的那样,这取决于您的应用程序使用情况。
另外,您可能希望尝试将精度提高到微秒(以最小化相同种子的机会),要求(sys/time.h):
struct timeval t1;
gettimeofday(&t1, NULL);
srand(t1.tv_usec * t1.tv_sec);
gettimeofday在POSIX 2008中已作废。相反,它引入clock_gettime了可能需要与链接的方法-lrt。但是,它可能在许多平台上均不可用。在Linux中,这没关系。在Mac上,我认为它尚不可用。在Windows中,它可能永远不可用。
随机数实际上是伪随机数。首先设置一个种子,每次调用rand都会从中获得一个随机数,并修改内部状态,并且在下一次rand调用中使用此新状态来获取另一个数。由于使用某个公式来生成这些“随机数”,因此在每次调用后设置一定的种子值rand将从该调用返回相同的数字。例如srand (1234); rand ();将返回相同的值。使用种子值初始化一次初始状态将生成足够的随机数,因为您无需使用设置内部状态srand,从而使这些数字更有可能是随机的。
通常,time (NULL)在初始化种子值时,我们使用返回的秒值。说srand (time (NULL));是一个循环。然后,循环可以在一秒内迭代一次以上,因此循环在循环中第二次rand调用中在循环内迭代的次数将返回相同的“随机数”,这是不希望的。在程序启动时对其进行一次初始化将设置一次种子,并且每次rand调用都将生成一个新数字并修改内部状态,因此下一次调用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;
}
内部状态next声明为全局。每次myrand调用都会修改并更新内部状态,并返回一个随机数。的每次调用myrand将具有不同的next值,因此该方法将在每次调用时返回不同的数字。
看一下mysrand实现;它只是设置您传递给的种子值next。因此,如果next每次调用前rand都将值设置为相同,则将返回相同的随机值,这是因为对其应用的公式相同,这是不希望的,因为该函数是随机的。
但是根据您的需要,您可以将种子设置为某个值,以在每次运行时生成相同的“随机序列”,例如针对某个基准或其他基准。
man srand。范围是0到32767(假设RAND_MAX),比long范围小很多。状态变量next是由long作为内部乘法和加法将超过的范围内unsigned int。之后,在上述指定范围内缩放或修改结果。虽然你可以做种子long。
简短的回答:呼叫srand()是不是就像“掷骰子”随机数发生器。这也不像洗牌一样。如果有的话,它更像是切开一副纸牌。
这样想吧。 rand()从一大副纸牌中进行交易,每次您调用它时,所要做的就是从纸牌顶部拾取下一张纸牌,给您值,然后将该卡返回到纸牌底部。(是的,这意味着“随机”序列将一段时间后重复这是一个。非常大的甲板,虽然:通常4,294,967,296卡)
此外,每一个程序运行时,卡一个全新的包从游戏商店买,和卡每一个全新的包总是具有相同的序列。因此,除非您执行一些特殊的操作,否则每次运行程序时,它都会从返回完全相同的“随机”数字rand()。
现在,您可能会说:“好吧,那我该如何洗牌呢?” 而答案-至少就rand和srand关注-是不存在洗牌甲板的方式。
那怎么srand办?根据我在这里构建的类比,调用srand(n)基本上就像是说:“n从顶部剪切卡片组”。但是,等等,还有一件事:它实际上是从另一个全新的牌组开始,并n从顶部切下来的牌。
所以,如果你打电话srand(n),rand(),srand(n),rand(),...,用相同的n每一次,你不会只是得到一个不是非常随机序列,你就会得到来自相同数量的背部rand()每次。(可能不是您递给的相同号码srand,而是rand一遍又一遍地递回的相同号码。)
所以,你能做的最好的就是削减甲板上一次,也就是通话srand()一次,在程序的开始,用n在大甲板每次那是相当随机的,所以,你会开始在不同的随机位置的程序运行。使用rand(),这确实是您可以做的最好的事情。
[PS是的,我知道,在现实生活中,当您购买一副崭新的纸牌时,通常是有顺序的,而不是随机的。为了进行类比,我想像一下您从游戏商店购买的每个牌组都是看似随机的顺序,但与您从同一商店购买的其他所有牌组的看似随机的顺序完全一样。有点像他们在桥牌比赛中使用的相同洗牌的扑克牌。]
1 \似乎每次rand()运行时,都会为下一个rand()设置新的种子。
2 \如果srand()运行多次,则问题是如果两个运行在一秒钟内发生(时间(NULL)不变),则下一个rand()将与前一个rand()相同srand()。
srand()相同的种子多次初始化会导致返回相同的值rand()。