這個問題是關於在這個問題的意見 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)。 –