2015-03-31 79 views
0

我正在從Objective C重寫一個蒙特卡洛仿真,用於從VBA/Excel的DLL。計算中的「引擎」是創建一個介於0和10001之間的隨機數,與5000-7000鄰域中的變量進行比較。每次迭代使用4-800次,我使用100000次迭代。所以這是每次運行約50萬次隨機數。避免Monte Carlo模擬中的基本rand()偏差?

雖然在Objective C中測試顯示沒有偏見,但我對C代碼有很大的問題。 Objective C是C的一個超集,所以95%的代碼是複製粘貼並且很難搞砸。我昨天和今天整天都經歷過很多次,而且我沒有發現任何問題。

我留下了與使用srand()arc4random_uniform()和rand()之間的差異,尤其是因爲偏向於更低的數字0到10000.我進行的測試與這種偏見一致對於低於大約5000的數字,0.5%到2%。其他任何解釋是如果我的代碼避免重複,我認爲它沒有做。

的代碼是非常簡單的(「spiller1evne」和「spiller2evne」是5500和6500之間的數字):

srand((unsigned)time(NULL)); 
for (j=0;j<antala;++j){ 
[..] 
     for (i=1;i<450;i++){ 
      chance = (rand() % 10001); 

[..] 

      if (grey==1) { 


       if (chance < spiller1evnea) vinder = 1; 
       else vinder = 2; 
      } 
      else{ 
       if (chance < spiller2evnea) vinder = 2; 
       else vinder = 1; 
      } 

現在我不需要真正的隨機性,僞隨機性是相當的精細。我只需要在累積的基礎上大致均勻分佈(如5555的可能性是5556的兩倍),這並不重要,5500-5599的可能性比5600-5699的可能性高5%如果對0-4000有一個明確的0.5-2%的偏差超過6000-9999。

首先,rand()是否是我的問題,是否有一個簡單的實現可以滿足我的低需求?

編輯:如果我的懷疑是合理的,我能使用任何在此:

http://www.azillionmonkeys.com/qed/random.html

我將能夠把剛纔複製粘貼在作爲替代(我寫在C和使用Visual Studio,真正的新手)?:

#include <stdlib.h> 

#define RS_SCALE (1.0/(1.0 + RAND_MAX)) 

double drand (void) { 
    double d; 
    do { 
     d = (((rand() * RS_SCALE) + rand()) * RS_SCALE + rand()) * RS_SCALE; 
    } while (d >= 1); /* Round off */ 
    return d; 
} 

#define irand(x) ((unsigned int) ((x) * drand())) 

EDIT2:那麼顯然上面的代碼工作沒有相同偏見,所以我會變成這樣的人推薦誰擁有相同的「中間道路」 - 就像我上面所描述的那樣。它確實帶來了罰款,因爲它調用了rand()三次。所以我仍然在尋找更快的解決方案。

+0

很簡單的答案是,你不應該真的使用rand()進行嚴肅的蒙特卡洛模擬。 rand()是基於線性全等的,這很糟糕,你應該檢查其他的RNG Mersenne Twister例如 – Jeanno 2015-03-31 14:06:39

回答

0

rand()函數生成範圍[0,RAND_MAX]中的int。如果您通過模數運算符(%)將其轉換爲不同的範圍,那麼會導致不一致,除非目標範圍的大小恰好等於RAND_MAX + 1。這聽起來像你所看到的。

你有多種選擇,但如果你想堅持使用基於rand()什麼話,我建議你原來的方法這種變化:

/* 
* Returns a pseudo-random int selected from the uniform distribution 
* over the half-open interval [0, limit), provided that limit does not 
* exceed RAND_MAX. 
*/ 
int range_rand(int limit) { 
    int rand_bound = (RAND_MAX/limit) * limit; 
    int r; 
    while ((r = rand()) >= rand_bound) { /* empty */ } 
    return r % limit; 
} 

雖然在原則rand()調用每次調用該函數的數量將生成的數據是無界的,實際上,對於相對較小的limit值,平均呼叫數僅略大於1,並且每個limit值的平均值小於2。它通過從[0,RAND_MAX]的子集中選擇初始隨機數來消除前面描述的非均勻性,其大小被limit均分。

相關問題