该问题与该问题中的评论有关。
建议初始化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()
。