簡體   English   中英

為什么我在第一次迭代中從 rand() function 中得到幾乎相同的數字?

[英]Why do I get nearly the same number out of the rand() function in the first iteration?

在我的 C99 程序中,我想使用介於 0 和 1 之間的偽隨機數。不幸的是,我的程序總是生成幾乎相同的第一個數字。 每次我重新運行我的程序時,它都會稍微增加一點。

這是我程序的相關部分:

srand(time(NULL));  
for(int i = 0; i < 10; i++){
    float a = (float)rand()/RAND_MAX;
    printf("%f\n",a);

以下是時間差低於 10 秒的兩次迭代的結果:

0.717103
0.357464
0.903628
0.271930
0.327478
0.917489
0.231215
0.026307
0.135259
0.290941

0.717221
0.330531
0.237708
0.151682
0.318986
0.201876
0.936884
0.209277
0.324705
0.311334

無論我之前計算了多少,我都試圖生成完全不同的數字,但第一個總是接近相同。

像這樣的模式通常是由低質量的線性同余偽隨機數生成器引起的。 每個隨機數的計算公式為X new = ( aX old + c ) mod m 當您以秒為單位播種時,一次播種后生成的第一個值與一秒后播種后生成的第一個值之間的變化m

如果你使用的是 Unix 系統(比如 macOS 或 Linux),你可以使用srandomrandom代替。

問題似乎是您的系統的rand()實現對time()的連續返回值相差不大這一事實很敏感——也就是說,沒有提供太多的熵。

我在我的機器上試過你的代碼,得到了非常相似的結果。

你需要提供更多的熵來“混淆”。

我喜歡使用的一種技術(至少,在類 Unix 系統上)是將進程 ID 添加到種子中,因為每次 pid 都會不同。 通常我是這樣做的:

srand(time(NULL) + getpid());

這是確保您的程序生成不同結果的好方法,即使您在同一秒內調用它兩次也是如此。

不幸的是,這不足以改變您在我機器上的代碼,而且我懷疑它對您的機器也無濟於事。 問題是(特別是在未加載的系統上)進程 ID 通常每次也只增加 1 或 2,並且它添加到相同的低位time的返回值中,這也沒有改變很多。 (並且 pid 的高階位根本沒有改變,並且被添加到一天中時間的高階位,這也沒有改變。)

在我的系統上,我得到了不錯的結果

srand(time(NULL) ^ (getpid() << 16));

我建議你試試這個。

如果這沒有幫助,您將需要使用明顯更好的熵源或明顯更好的偽隨機數生成器。

現在,幾乎所有類 Unix 系統都有一個很好的熵源,可以通過特殊文件/dev/random訪問。 因此,為偽隨機數生成器提供種子的一種更好的方法是使用如下代碼:

FILE *fp = fopen("/dev/random", "rb");
if(fp != NULL) {
    unsigned int seed;
    fread(&seed, sizeof(seed), 1, fp);
    srand(seed);
    fclose(fp);
}

(對於生產程序,顯然您必須決定如果fopen調用失敗該怎么辦。)

Eric Postpischil 的回答提到了random ,這是一種在大多數系統上都可用的明顯更好的 PRNG。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM