2011-09-08 97 views

回答

86

這取決於你想達到的目標。

隨機化作爲具有起始值,即種子的函數來執行。

因此,對於相同的種子,您將始終獲得相同的值序列。

如果嘗試每次你需要一個隨機值時設置種子和種子是相同的號碼,你總是會得到相同的「隨機」值。

種子通常取自當前時間,即秒數,因爲在time(NULL)中,所以如果您始終在採用隨機數之前設置種子,只要調用srand/rand,就會得到相同的數字在同一秒內組合多次

爲了避免這個問題,每個應用程序只設置一次srand,因爲兩個應用程序實例在同一秒內運行是有疑問的,所以每個實例都會有不同的隨機數序列。

然而,你會在短時間內多次運行你的應用程序(特別是如果它是一個簡短的,或命令行工具或類似的東西),那麼你將不得不求助於其他應用程序選擇種子的方法(除非你在不同的應用程序實例中的相同序列是可以的)。但正如我所說,這取決於您的應用程序使用情況。

此外,你可能想嘗試,以增加精度微秒(減少同一種子的機會),要求(sys/time.h):

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

@Kornelije ...詳細解釋。非常感謝。對不起,延遲..在過去的幾天裏沒有了。 –

+3

注意:'gettimeofday'在POSIX 2008中已經過時,而是引入'clock_gettime',可能需要使用'-lrt'鏈接。不過,它可能還不能在許多平臺上使用。在Linux中,這是沒問題的。在Mac上,我認爲它還不可用。在Windows中,它可能永遠不可用。 – Shahbaz

+0

t1.tv_usec是一個long int,srand將一個unsigned int作爲輸入。 (我遇到了一個問題,它有所作爲。) – Jiminion

6

原因是,srand()設置隨機生成器的初始狀態,並且如果您不在兩者之間觸摸狀態,則生成器生成的所有值只是「隨機的」。

例如,你可以這樣做:

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

,然後如果你調用該函數反覆,使time()返回鄰近的電話相同的價值觀,你只得到生成相同的價值 - 這是由設計。

2

函數srand種子的僞隨機數發生器。如果你多次呼叫它,你將重新設定RNG。如果你用相同的參數調用它,它將重新啓動相同的序列。

爲了證明這一點,如果你不喜歡簡單的東西:

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

,你會看到相同數量的印刷100次。

+2

問題是關於C,而不是C++。 –

21

隨機數實際上是僞隨機數。首先設置種子,從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的值設置爲相同,那麼它將返回相同的隨機值,因爲應用了相同的公式,這是不可取的,因爲該函數是隨機的。

但根據您的需要,您可以將種子設置爲某個特定值,以生成每次運行的相同「隨機序列」,例如針對某個基準或其他基準。

+3

我必須說你的答案是這個問題最詳細的答案。完美地解釋了幾乎'蘭特'和'斯蘭'的工作原理。 – manty

+0

你的意思是(無符號長種子)mysrand()的參數嗎? – Jiminion

+0

@Jiminion這是'man srand'的代碼片段。範圍從0到32767(假設RAND_MAX),遠小於「long」範圍。由於內部乘法和加法將超出'unsigned int'的範圍,因此狀態變量'next'被設置爲'long'。之後,結果在上述指定範圍內縮放或修改。雖然你可以讓種子「長」。 – phoxis

1

使用srand爲應用程序實例生成不同種子的簡單解決方案可以在同一秒內運行。

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

這種方法使你的種子非常接近隨機,因爲沒有辦法猜測你的線程什麼時候開始,並且pid也會不同。

4

簡短回答:打電話srand()不是就像隨機數發生器的「滾動骰子」。它也不像洗牌一樣。如果有的話,它更像是一副撲克牌。

想想這樣吧。從一副大卡牌中獲得一定數量的交易,每次你打電話時,只需從甲板頂部拿下下一張卡片,給你價值,然後將該卡牌返回到甲板的底部。 (是的,這意味着經過一段時間的「隨機」序列會重複這是一個非常大甲板,但:。通常4,294,967,296卡)

而且,每次你的程序運行時間,卡全新包裝是從遊戲商店購買的,每一款全新的套牌總是具有相同的順序。所以除非你做了一些特別的事情,每次你的程序運行時,它會從rand()返回完全相同的「隨機」數字。

現在,你可能會說:「好吧,那麼我該如何洗牌?」答案是(至少就randsrand而言),沒有辦法改組甲板。

那麼srand是做什麼的?根據我在這裏建立的比喻,打電話srand(n)基本上就像是說,「從頂部削減卡牌n」。但等一等,還有一件事:它實際上是另一個全新的甲板,並從頂部削減它n卡。

所以,如果你srand(n)rand()srand(n)rand(),...,與同n每一次,你不會只是得到一個不是非常隨機序列,你就會得到相同數量的背每次從rand()。 (不一定是你交給srand相同數量,但同樣的數量從rand一遍又一遍回來。)

所以你能做的最好的就是削減甲板一次,就是叫srand()一次,你的程序的開始,這是一個合理隨機的n,這樣你就可以在每次程序運行時從一個不同的隨機位置開始。

[P.S.是的,我知道,在現實生活中,當你購買一副全新的卡片時,它通常是按順序排列的,而不是隨機排列的。爲了讓這裏的比喻起作用,我想象你從遊戲商店購買的每張牌組都是以一種看似隨機的順序,但是與你從同一家商店購買的其他牌組完全相同,看似隨機的順序。有點像他們在橋牌比賽中使用的牌一樣。]

0

1 \看起來每次rand()運行時,它都會爲下一個rand()設置一個新的種子。如果srand()運行多次,問題是如果兩次運行發生在一秒鐘內(時間(NULL)不變),則下一個rand()將與rand()相同,在之前的srand()之後。

+0

主要的一點是用'srand()'初始化幾次相同的種子會導致'rand()'返回相同的值。 –

相關問題