这个问题是关于在这个问题的意见 Recommended way to initialize srand?第一条评论说,srand()
应该只在应用程序中调用一次。为什么这样?srand() - 为什么只调用它一次?
回答
这取决于你想达到的目标。
随机化作为具有起始值,即种子的函数来执行。
因此,对于相同的种子,您将始终获得相同的值序列。
如果尝试每次你需要一个随机值时设置种子和种子是相同的号码,你总是会得到相同的“随机”值。
种子通常取自当前时间,即秒数,因为在time(NULL)
中,所以如果您始终在采用随机数之前设置种子,只要调用srand/rand,就会得到相同的数字在同一秒内组合多次。
为了避免这个问题,每个应用程序只设置一次srand,因为两个应用程序实例在同一秒内运行是有疑问的,所以每个实例都会有不同的随机数序列。
然而,你会在短时间内多次运行你的应用程序(特别是如果它是一个简短的,或命令行工具或类似的东西),那么你将不得不求助于其他应用程序选择种子的方法(除非你在不同的应用程序实例中的相同序列是可以的)。但正如我所说,这取决于您的应用程序使用情况。
此外,你可能想尝试,以增加精度微秒(减少同一种子的机会),要求(sys/time.h
):
struct timeval t1;
gettimeofday(&t1, NULL);
srand(t1.tv_usec * t1.tv_sec);
原因是,srand()
设置随机生成器的初始状态,并且如果您不在两者之间触摸状态,则生成器生成的所有值只是“随机的”。
例如,你可以这样做:
int getRandomValue()
{
srand(time(0));
return rand();
}
,然后如果你调用该函数反复,使time()
返回邻近的电话相同的价值观,你只得到生成相同的价值 - 这是由设计。
函数srand种子的伪随机数发生器。如果你多次呼叫它,你将重新设定RNG。如果你用相同的参数调用它,它将重新启动相同的序列。
为了证明这一点,如果你不喜欢简单的东西:
#include <cstdlib>
#include <cstdio>
int main() {
for(int i = 0; i != 100; ++i) {
srand(0);
printf("%d\n", rand());
}
}
,你会看到相同数量的印刷100次。
问题是关于C,而不是C++。 –
随机数实际上是伪随机数。首先设置种子,从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
的种子值。因此,如果在调用rand
之前每次将next
的值设置为相同,那么它将返回相同的随机值,因为应用了相同的公式,这是不可取的,因为该函数是随机的。
但根据您的需要,您可以将种子设置为某个特定值,以生成每次运行的相同“随机序列”,例如针对某个基准或其他基准。
使用srand为应用程序实例生成不同种子的简单解决方案可以在同一秒内运行。
srand(time(NULL)-getpid());
这种方法使你的种子非常接近随机,因为没有办法猜测你的线程什么时候开始,并且pid也会不同。
简短回答:打电话srand()
是不是就像随机数发生器的“滚动骰子”。它也不像洗牌一样。如果有的话,它更像是一副扑克牌。
想想这样吧。从一副大卡牌中获得一定数量的交易,每次你打电话时,只需从甲板顶部拿下下一张卡片,给你价值,然后将该卡牌返回到甲板的底部。 (是的,这意味着经过一段时间的“随机”序列会重复这是一个非常大甲板,但:。通常4,294,967,296卡)
而且,每次你的程序运行时间,卡全新包装是从游戏商店和购买的,每一款全新的套牌总是具有相同的顺序。所以除非你做了一些特别的事情,每次你的程序运行时,它会从rand()
返回完全相同的“随机”数字。
现在,你可能会说:“好吧,那么我该如何洗牌?”答案是(至少就rand
和srand
而言),没有办法改组甲板。
那么srand
是做什么的?根据我在这里建立的比喻,打电话srand(n)
基本上就像是说,“从顶部削减卡牌n
”。但等一等,还有一件事:它实际上是另一个全新的甲板,并从顶部削减它n
卡。
所以,如果你srand(n)
,rand()
,srand(n)
,rand()
,...,与同n
每一次,你不会只是得到一个不是非常随机序列,你就会得到相同数量的背每次从rand()
。 (不一定是你交给srand
相同数量,但同样的数量从rand
一遍又一遍回来。)
所以你能做的最好的就是削减甲板一次,就是叫srand()
一次,你的程序的开始,这是一个合理随机的n
,这样你就可以在每次程序运行时从一个不同的随机位置开始。
[P.S.是的,我知道,在现实生活中,当你购买一副全新的卡片时,它通常是按顺序排列的,而不是随机排列的。为了让这里的比喻起作用,我想象你从游戏商店购买的每张牌组都是以一种看似随机的顺序,但是与你从同一家商店购买的其他牌组完全相同,看似随机的顺序。有点像他们在桥牌比赛中使用的牌一样。]
1 \看起来每次rand()运行时,它都会为下一个rand()设置一个新的种子。如果srand()运行多次,问题是如果两次运行发生在一秒钟内(时间(NULL)不变),则下一个rand()将与rand()相同,在之前的srand()之后。
主要的一点是用'srand()'初始化几次相同的种子会导致'rand()'返回相同的值。 –
- 1. 为什么SqlDataAdapter.Update只能调用一次?
- 2. 为什么只能调用SmtpClient.SendAsync一次?
- 3. 为什么用argv []调用sscanf()只能使用一次?
- 4. 为什么evaluateJavaScript只能使用一次?
- 5. 为什么clearInterval只能使用一次?
- 6. 为什么只有一次调用析构函数?
- 7. 为什么构造函数只被调用一次?
- 8. 为什么run()只会被调用一次?
- 9. 数据事件点击只调用一次,为什么?
- 10. 我为什么只能调用GetResponseStream()一次
- 11. 为什么这个角度指令只调用一次?
- 12. Three.js + TypeScript。为什么只有一次调用动画的方法?
- 13. 为什么这个PHP函数调用只能工作一次?
- 14. 方法lcl_util只在循环中调用一次为什么?
- 15. 为什么JNDI资源只能在Tomcat中调用一次?
- 16. 为什么以下的jquery Ajax调用只执行一次?
- 17. 为什么两个线程在我只调用ExecutorService.execute()一次?
- 18. SetInterval只调用一次,不知道为什么?
- 19. 嘲笑&单元测试 - 为什么要检查一次只被调用一次?
- 20. 为什么Update()不止一次地调用它自己?
- 21. $ .ajax使API调用两次,尽管它只被调用一次
- 22. 为什么只循环一次?
- 23. 为什么setTimeout只执行一次?
- 24. 函数只返回一次,为什么?
- 25. 为什么popen()只能工作一次?
- 26. 为什么线程只运行一次
- 27. 为什么foreach只循环一次?
- 28. 为什么只记录一次?
- 29. 为什么只闪烁一次?
- 30. 为什么循环只执行一次?
尝试在循环中调用srand然后rand –
另请参阅Dilbert的[会计之旅](http://dilbert.com/strip/2001-10-25)。 –