2015-04-08 35 views
0

我正在運行一堆物理模擬,其中我需要隨機數。我在C++中使用標準的rand()函數。關於隨機整數數字生成(C)的標準

所以它的工作原理是這樣的:首先我預先計算一組形式爲1/(1+exp(a))的概率,對於一組不同的a。他們double類型作爲math庫返回由exp功能,然後事情必須與那些概率發生,只有兩個人,所以我產生一個隨機數0和1之間均勻分佈,並與預先計算相比,概率。要做到這一點,我用:

double p = double(rand()%101)/100.0; 

所以我給01之間的隨機值都包括在內。這並不能糾正物理結果。我試過這個:

double p = double(rand()%1000001)/1000000.0; 

這個工作。我不明白爲什麼所以我想要一些關於如何去做的標準。我的直覺告訴我,如果做

double p = double(rand()%(N+1))/double(N); 

N足夠大,使得最小師(1/N)比最小的概率1/1+exp(a)然後我會越來越現實的隨機數要小得多。

我想知道爲什麼,雖然。

回答

1

rand()返回0和RAND_MAX之間的隨機數。

因此,你需要這樣的:

double p = double(rand() % RAND_MAX)/double(RAND_MAX); 

而且運行這段代碼,你會明白:

int i; 

    for (i = 1; i < 30; i++) 
    { 
     int rnd = rand(); 
     double p0 = double(rnd % 101)/100.0; 
     double p1 = double(rnd % 1000001)/1000000.0; 
     printf ("%d\t%f\t%f\n", rnd, p0, p1); 
    } 

    for (i = 1; i < 30; i++) 
    { 
     int rnd = rand(); 
     double p0 = double(rnd)/double(RAND_MAX); 
     printf ("%d\t%f\n", rnd, p0); 
    } 
+0

嗯,這顯然會給最好的結果。謝謝 – MyUserIsThis

+0

順便說一句:'double(rand()%1000001)/1000000.0;'也不管用。 –

1

你有多個問題。

  1. rand()根本不是很隨意。在幾乎所有的操作系​​統上,它都會返回分佈不均,可怕的偏差數字。實際上很難找到一個好的隨機數發生器,但我可以保證你會發現rand()是最糟糕的。

  2. rand() % N給出了有偏差的分佈。想想鴿子的原理。讓我們簡化它,假設rand返回數字[0,7],N是6. 0到5映射到0到5,6映射到0和7映射到1,這意味着0和1有兩倍的可能性出。

  3. 將分割前的數字轉換爲雙精度值不等於從2中刪除偏差值,這只是使其不易看清。無論您做什麼轉換,鴿子的原理都適用。

  4. 將分佈良好的隨機數從整數轉換爲float/double比看起來更難。簡單的劃分忽略了浮點數學如何工作的問題。

我用1幫不了你,你需要做研究。查看網絡隨機數字庫。如果你想要一些非常隨機且不可預測的東西,你需要尋找密碼隨機庫。如果你想要一個可重複但很好的隨機數Mersenne Twister應該足夠好。但是你需要在這裏做研究。

對於2和3有標準解決方案。您正在將一組從M個元素映射到N個元素,並且rand % N將僅在M和N和M共享素數因子時起作用。由於在大多數系統中M將是2的冪,這意味着N也必須是2的冪。因此,假定M是2的冪,則該算法是:找到2的最近冪或者等於N,我們稱之爲P.生成randomness_source() % P。如果數字高於N,請將其丟棄並重試。這是執行此操作的唯一安全方法。比你和我更聰明的人在這個問題上花了多年的時間,沒有更好的方法來消除偏見。

對於4,你可以忽略這個問題,只是在絕大多數情況下,這應該足夠好。如果你真的想研究這個問題,我已經做了一些工作,併發布了代碼on github.在那裏,我通過了浮點數的工作原理以及它與生成隨機數的關係。

+0

謝謝你的回答。至於第1點和第4點,我會做一些研究。至於第二點,我意識到了這一點,但是在這種情況下,偏差將是M mod N的階數,所以如果M是N(卵巢)的倍數,則偏差爲零。現在,如果N非常小,則這個偏差幾乎爲零:例如,如果rand_max是奇數,則rand()%2具有1/Rand_Max的偏差,因爲它從N + 1,N組中選擇,其中N是rand_max/2的順序。在這種情況下,100會比rand_max小得多,對嗎?再次感謝您的幫助 – MyUserIsThis

+0

您可以計算偏差,但爲什麼?這很簡單,根本就沒有任何偏見,每當你最初的假設發生變化時,這都是很好的做法。下面是一個函數的免費實現,該函數可以從一個返回[0,2^32)的隨機源給出均勻分佈的數字(它使用比我提到的更快但更難解釋的算法):http:// cvsweb。 openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/crypt/arc4random_uniform.c?rev=1.1&content-type=text/plain – Art

+0

如果我不知道其他方法,我可能至少知道隨機偏差會導致錯誤有多大:D。我會看看這個。謝謝! – MyUserIsThis

0
// produces pseudorandom bits. These are NOT crypto quality bits. Has the same underlying unpredictability as uncooked 
// rand() output. It buffers rand() bits to produce a more convenient zero-to-the-argument range including negative 
// arguments, corrects for the toward-zero bias of the modular construction I'd be using otherwise, eliminates the 
// RAND_MAX range limitation, (use INT64_MAX instead) and effectively obscures biases and sequence telltales due to 
// annoyingly bad rand libraries. It does not correct these biases; anyone tracking the arguments and outputs has 
// enough information to reconstruct the rand() output and detect them. But it makes the relationships drastically more complicated. 

// needs stdint, stdlib. 

int64_t privaterandom(int64_t range, int reset){ 
    static uint64_t state = 0; 
    int64_t retval; 
    if (reset != 0){ 
     srand((unsigned int)range); 
     state = (uint64_t)range; 
    } 
    if (range == 0) return (0); 
    if (range < 0) return -privaterandom(-range, 0); 
    if (range > UINT64_MAX/0xFFFFFFFF){ 
     retval = (privaterandom(range/0xFFFFFFFF, 0) * 0xFFFFFFFF); // order of operations matters 
     return (retval + privaterandom(0xFFFFFFFF, 0)); 
    } 
    while (state < UINT64_MAX/0xFF){ 
     state *= RAND_MAX; 
     state += rand(); 
    } 
    retval = (state % range); 
    // makes "pigeonhole" bias alternate unpredictably between toward-even and toward-odd 
    if ((state/range > (state - (retval))/ range) && state % 2 == 0) retval++; 
    state /= range; 
    return retval; 
} 
int64_t Random(int64_t range){ return (privaterandom(range, 0));} 
int64_t Random_Init(int64_t seed){return (privaterandom(seed, 1));}