2011-12-28 36 views
6

我想用0和1之間的C++生成統一的隨機數,其方式不使用標準的rand()srand(time(NULL))方法。原因是,如果我在同一秒鐘內多次運行應用程序,種子將完全相同併產生相同的輸出。使用TR1/dev/random在C++中生成隨機數

我不想依賴boost或OS /編譯器的細節。 x86可以被假定。

看起來好像是另一種方法來使用TR1(我沒有C++ 11)並以某種方式使用/dev/random進行播種?

現在我有這個,但它仍然使用time(NULL)的種子,這將不是1個第二運行部內很好地工作:

#include <iostream> 
#include <tr1/random> 

int main() 
{ 
    std::tr1::mt19937 eng; 
    eng.seed(time(NULL)); 
    std::tr1::uniform_int<int> unif(1, RAND_MAX); 
    int u = unif(eng); 
    std::cout << (float)u/RAND_MAX << std::endl; 
} 
+0

你是否願意使用OS /編譯器特有的功能? – Mysticial 2011-12-28 21:00:24

+0

我想避免這個......我將在各種系統上部署這個 – gnychis 2011-12-28 21:01:10

+0

各種各樣?他們仍然是x86嗎? – Mysticial 2011-12-28 21:01:45

回答

7

張貼在OP的要求:

這還是有點編譯器特定的,但仍然會工作在幾乎所有x86靶向編譯器:

#ifdef _WIN32 

// Windows 
#define rdtsc __rdtsc 

#else 

// For everything else 
unsigned long long rdtsc(){ 
    unsigned int lo,hi; 
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); 
    return ((unsigned long long)hi << 32) | lo; 
} 

#endif 

int main() 
{ 
    std::tr1::mt19937 eng; 
    eng.seed(rdtsc()); // Seed with rdtsc. 
    std::tr1::uniform_int<int> unif(1, RAND_MAX); 
    int u = unif(eng); 
    std::cout << (float)u/RAND_MAX << std::endl; 
} 

這裏的想法是種子的隨機號碼發生器與rdtsc週期計數器。

之所以這個作品是因爲在有關(往往是相同的)速度與CPU頻率rdtsc週期計數器進行迭代。因此,兩次調用返回相同值的機會非常渺茫 - 從而使它成爲RNG的優秀種子。

1

你的問題是有關您種子隨機數生成的方式。很明顯,隨着播種時間的增加(NULL)將在接下來的秒內產生相同的PRNG序列。這是種植蘭特最常見的方式,但不幸的是,由於這個問題,這是不好的做法。不僅如此,我讀到它可能會導致結果的偏見。

請注意,如果用相同的值接種,每個PRNG將產生相同的結果。所以你的問題與發電機無關,更重要的是播種。

我在幾周前問了一個關於在這裏播種的問題,並給出了以下文章的鏈接,您可能也會發現它們很有用。 Good Practice in (Pseudo) Random Number Generation for Bioinformatics Applications 請參閱播種或預熱發生器部分。

rand()不是最好的隨機數生成器,但在許多情況下適用,只要它適當播種。如果你想在重複序列非常大的地方更好,那麼在該鏈接中提供了一些。或者使用基於TR1的。就我個人而言,我會使用更便攜的基於C++ 03的代碼,並避開TR1。

還考慮Multiply with carry作爲替代PRNG算法。

4

TR1在[tr.rand.device]指定一個random_device類,從依賴於實現的源產生的無符號整數。所以下面應該工作,雖然我沒有編譯它自己:

int main() { 
    std::tr1::random_device dev_random; 
    std::tr1::mt19937 eng(dev_random()); 
    ... 

在TR1,直接傳遞dev_random不調用它的工作原理,更隨機初始化工程的狀態,但在C++ 11你必須包裝的種子參數轉換爲另一個類。既然調用這個參數在兩個庫中都有效,除非你有更多的需求,否則我會這樣做以保持可維護性。

+0

請注意,您無法保證從random_device()構造函數獲得_which_ random設備。它可能是'/ dev/random','/ dev/urandom','rdtsc',http://en.wikipedia.org/wiki/RdRand,甚至是另一個僞rng。實現可以爲構造函數定義一個字符串參數,以在選項之間進行選擇,但默認設置應該不錯。 – 2011-12-28 21:37:06

+1

random_device是一個函數對象,所以'eng(dev_random())' – Cubbi 2011-12-28 22:10:51

+0

@Cubbi:Nope:引擎有一個構造函數接受一個整數,一個構造函數接受一個函數對象:「'X(g)' - 創建一個引擎具有初始內部狀態,由連續調用'g'的結果給出。「 - [tr.rand.req]表16.這允許它們填充它們的整個狀態,而不僅僅是它的第一個單詞。 (當然,有可能任何給定的實現都沒有實現整個規範。) – 2011-12-28 22:29:22