[英]Why do I always get the same sequence of random numbers with rand()?
這是我第一次用 C 嘗試隨機數(我想念 C#)。 這是我的代碼:
int i, j = 0;
for(i = 0; i <= 10; i++) {
j = rand();
printf("j = %d\n", j);
}
使用此代碼,每次運行代碼時我都會得到相同的序列。 但是如果我在for
循環之前添加srand(/*somevalue/*)
,它會生成不同的隨機序列。 誰能解釋為什么?
你必須播種。 隨時間播種是個好主意:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main ()
{
srand ( time(NULL) );
printf ("Random Number: %d\n", rand() %100);
return 0;
}
您會得到相同的序列,因為如果您不調用srand()
rand()
會自動以 1 的值作為種子。
由於評論
rand()
將返回一個介於 0 和RAND_MAX
(在標准庫中定義)之間的數字。 使用模運算符 ( %
) 給出除法rand() / 100
的余數。 這將強制隨機數在 0-99 范圍內。 例如,要獲得 0-999 范圍內的隨機數,我們將應用rand() % 1000
。
rand()
返回偽隨機數。 它根據給定的算法生成數字。
該算法的起點始終相同,因此您將看到為每次調用生成的相同序列。 當您需要驗證程序的行為和一致性時,這很方便。
您可以使用srand
函數設置隨機生成器的“種子”(在程序中只調用一次srand
)從rand()
生成器獲取不同序列的一種常用方法是將種子設置為當前時間或過程:
srand(time(NULL));
或srand(getpid());
在程序開始時。
對於計算機來說,生成真正的隨機性非常困難,但對於實際的非加密相關工作,嘗試均勻分布生成的序列的算法效果很好。
引用man rand :
srand() 函數將其參數設置為 rand() 返回的新偽隨機整數序列的種子。 這些序列可以通過使用相同的種子值調用 srand() 來重復。
如果未提供種子值,則 rand() 函數將自動以 1 值作為種子。
因此,在沒有種子值的情況下, rand()
將種子假定為 1(在您的情況下每次都是)並且具有相同的種子值, rand()
將產生相同的數字序列。
這里有很多答案,但似乎沒有人真正解釋過為什么 rand() 總是在給定相同的種子的情況下生成相同的序列 - 甚至種子實際上在做什么。 所以就到這里了。
rand() 函數維護一個內部狀態。 從概念上講,您可以將其視為某種稱為 rand_state 的全局變量。 每次調用 rand() 時,它都會做兩件事。 它使用現有狀態計算新狀態,並使用新狀態計算返回給您的數字:
state_t rand_state = INITIAL_STATE;
state_t calculate_next_state(state_t s);
int calculate_return_value(state_t s);
int rand(void)
{
rand_state = calculate_next_state(rand_state);
return calculate_return_value(rand_state);
}
現在您可以看到,每次調用 rand() 時,它都會使 rand_state 沿着預先確定的路徑移動一步。 您看到的隨機值僅基於您在該路徑上的位置,因此它們也將遵循預先確定的順序。
現在這里是 srand() 的用武之地。它可以讓你跳到路徑上的不同點:
state_t generate_random_state(unsigned int seed);
void srand(unsigned int seed)
{
rand_state = generate_random_state(seed);
}
state_t、calculate_next_state()、calculate_return_value() 和 generate_random_state() 的確切細節可能因平台而異,但它們通常非常簡單。
從中可以看出,每次程序啟動時,rand_state 都會從 INITIAL_STATE 開始(相當於 generate_random_state(1))——這就是為什么如果不使用 srand() 總是得到相同序列的原因。
如果我記得在隨機數生成一章開頭引用 Knuth 的開創性著作“計算機編程的藝術”,它是這樣的:
“任何試圖通過數學方法生成隨機數的人,從技術上講,都處於犯罪狀態”。
簡單地說,股票隨機數生成器是算法、數學和 100% 可預測的。 在很多情況下,這實際上是一件好事,其中需要可重復的“隨機”數字序列 - 例如對於某些統計練習,您不希望真正隨機數據引入的結果中的“擺動”,這要歸功於聚類效應。
盡管從計算機硬件中獲取“隨機”數據位是一種流行的第二種選擇,但它也不是真正的隨機——盡管操作環境越復雜,隨機性的可能性就越大——或者至少是不可預測性。
真正隨機的數據生成器傾向於尋找外部來源。 放射性衰變是最受歡迎的,類星體的行為也是如此。 任何源於量子效應的東西實際上都是隨機的——這讓愛因斯坦很惱火。
隨機數生成器實際上並不是隨機的,它們像大多數軟件一樣是完全可預測的。 rand 所做的是每次將其稱為 One 時創建一個不同的偽隨機數,這似乎是隨機的。 為了正確使用它,您需要給它一個不同的起點。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main ()
{
/* initialize random seed: */
srand ( time(NULL) );
printf("random number %d\n",rand());
printf("random number %d\n",rand());
printf("random number %d\n",rand());
printf("random number %d\n",rand());
return 0;
}
這是來自http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.13.html#rand :
宣言:
void srand(unsigned int seed);
此函數為 rand 函數使用的隨機數生成器設置種子。 用相同的種子播種 srand 將導致 rand 返回相同的偽隨機數序列。 如果未調用 srand,則 rand 的行為就像已調用 srand(1) 一樣。
rand() 返回系列中的下一個(偽)隨機數。 發生的事情是每次運行時您都有相同的系列(默認為“1”)。 要播種新系列,您必須在開始調用 rand() 之前調用 srand()。
如果你每次都想要一些隨機的東西,你可以嘗試:
srand (time (0));
蘭德不會給你一個隨機數。 它為您提供偽隨機數生成器生成的序列中的下一個數字。 要在每次啟動程序時獲得不同的序列,您必須通過調用srand為算法設定種子。
一種(非常糟糕的)方法是將當前時間傳遞給它:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL));
int i, j = 0;
for(i = 0; i <= 10; i++) {
j = rand();
printf("j = %d\n", j);
}
return 0;
}
為什么這是一個壞方法? 因為偽隨機數生成器與其種子一樣好,而且種子必須是不可預測的。 這就是為什么您可能需要更好的熵源,例如從/dev/urandom
讀取。
在調用rand()
之前調用srand(sameSeed)
rand()
。 更多細節在這里。
void srand (unsigned int seed)
此函數將種子建立為一系列新偽隨機數的種子。 如果在使用 srand 建立種子之前調用 rand,它將使用值 1 作為默認種子。
要在每次運行程序時生成不同的偽隨機序列,請執行 srand (time (0))
你們沒有人回答他的問題。
使用這段代碼,我每次代碼都會得到相同的序列,但是如果我在 for 循環之前添加 srand(/somevalue/) ,它會生成隨機序列。 有人可以解釋為什么嗎?
根據我的教授告訴我的,如果您想確保代碼正常運行並查看是否有問題或是否可以更改某些內容,則可以使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.