2011-08-27 85 views
23

新的C++ 11標準有一整章專用於隨機數生成器。但這樣做我怎麼執行用於編碼這樣最簡單,最常見的任務,但沒有訴諸標準C庫:如何使用C++ 11標準庫生成一個隨機數

srand((unsigned int)time(0)); 
int i = rand();

是否有隨機數的發動機,分佈和種子合理的默認值是人們可以使用現成的盒子?

+0

維基百科? http://en.wikipedia.org/wiki/C%2B%2B0x#Extensible_random_number_facility – quasiverse

+2

你的代碼有什麼問題? AFAIK,新的隨機數發生器被添加到更多「嚴重」的應用中,隨機數生成的方面真的很重要。 – GManNickG

+3

@GMan:公平的說,新標準中的幾個隨機數引擎可以被描述爲簡單和快速,我不會認爲它們特別「嚴重」。 –

回答

30

你應該能夠做這樣的事情:

std::default_random_engine e((unsigned int)time(0)); 
int i = e(); 

default_random_engine的質量依賴於實現。您也可以使用std::min_rand0std::min_rand

也許一種更好的種子隨機引擎的方法是使用真實的隨機數,而不是使用time

E.g.

​​
+1

爲了澄清,你的意思是「應該」,如「這不存在但它應該」或sd「存在並且你的編譯器應該支持它」? – GManNickG

+8

信息:這個答案和OP的例子最大的區別在於編碼器控制引擎狀態的位置:它在'e'中。在OP的代碼中,狀態被隱藏爲'rand'內的靜態數據。這是處理多線程程序時的一個重要區別。 'rand'必須具有某種保護才能保證線程安全。 'default_random_engine'不。如果你想從多個線程中調用它,你可以在外部自己提供同步機制。這意味着'default_random_engine'可以更快,如果你不需要同步它。 –

+0

@GMan:這意味着我目前唯一可以訪問的實現不支持它,所以我沒有能夠測試我的代碼;)。 –

2

如果你的現有代碼的新標準之前是適當的,那麼它將繼續。新的隨機數發生器被添加用於需要更高質量的僞隨機性的應用,例如,隨機模擬。

0

隨機數字的產生是一個難題。沒有真正的隨機的方式來做到這一點。如果你只是隨機產生一個遊戲環境,那麼你的方法應該沒問題。 rand()有幾個缺點。

如果您需要隨機性來生成加密密鑰,那麼您是S.O.L.在這種情況下,最好的辦法是去操作系統,通常有機制。在隨機()的POSIX上(或者如果你這麼處理,可以從/ dev/random中讀取)。在Windows中可以使用的CryptoAPI:

https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers

0

你可以使用RC4來生成隨機字節。這可能有你想要的屬性。這是快速和相當簡單的實施。當種子已知時,序列在所有實現中都是可重複的,而當種子未知時,序列是完全不可預知的。 http://en.wikipedia.org/wiki/RC4

2

我在我的項目中使用下面的代碼。 '引擎'和'發行'可以是圖書館提供的內容之一。

#include <random> 
#include <functional> 
#include <iostream> 
... 
std::uniform_int_distribution<unsigned int> unif; 
std::random_device rd; 
std::mt19937 engine(rd()); 
std::function<unsigned int()> rnd = std::bind(unif, engine); 

std::cout << rnd() << '\n'; 
6

統一和簡化一些已經提供我就總結到的樣本:

// Good random seed, good engine 
auto rnd1 = std::mt19937(std::random_device{}()); 

// Good random seed, default engine 
auto rnd2 = std::default_random_engine(std::random_device{}()); 

// like rnd1, but force distribution to int32_t range 
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}())); 

// like rnd3, but force distribution across negative numbers as well 
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}())); 

然後我進行了一些測試,看看默認的樣子:

#include <random> 
#include <functional> 
#include <limits> 
#include <iostream> 

template<class Func> 
void print_min_mean_max(Func f) { 
    typedef decltype(f()) ret_t; 
    ret_t min = std::numeric_limits<ret_t>::max(), max = std::numeric_limits<ret_t>::min(); 
    uint64_t total = 0, count = 10000000; 
    for (uint64_t i = 0; i < count; ++i) { 
     auto res = f(); 
     min = std::min(min,res); 
     max = std::max(max,res); 
     total += res; 
    } 
    std::cout << "min: " << min << " mean: " << (total/count) << " max: " << max << std::endl; 
} 

int main() { 
    auto rnd1 = std::mt19937(std::random_device{}()); 
    auto rnd2 = std::default_random_engine(std::random_device{}()); 

    auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}())); 
    auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}())); 

    print_min_mean_max(rnd1); 
    print_min_mean_max(rnd2); 
    print_min_mean_max(rnd3); 
    print_min_mean_max(rnd4); 
} 

主要生產的輸出:

min: 234 mean: 2147328297 max: 4294966759 
min: 349 mean: 1073305503 max: 2147483423 
min: 601 mean: 1073779123 max: 2147483022 
min: -2147481965 mean: 178496 max: 2147482978 

因此,我們可以看到,mt19937和default_random_engine具有不同的默認範圍,因此建議使用uniform_int_distribution。

另外,即使在使用有符號整數類型時,uniform_int_distribution的默認值是[0,max_int](非負)。必須明確提供範圍,如果你想全範圍。

最後,its important to remember this有時喜歡這些。

+2

值得注意的是,有一個64位版本的'std :: mt19937':'std :: mt19937_64',每個調用返回64位的隨機性。 'auto rnd5 = std :: mt19937_64(std :: random_device {}()); // min:4879020137534 mean:1655417118684 max:18446741225191893648' – Sean

+0

順便說一下,重複使用與許多發行版和std :: bind()相同的隨機數引擎是否安全,還是更好地將每個發行版綁定到新的引擎實例?這是如何:'std :: mt19937_64 random = std :: mt19937_64(std :: random_device {}());''auto randomCardinality = std :: bind(std :: uniform_int_distribution (1,4),random);' 'auto randomValue = std :: bind(std :: uniform_real_distribution (-1.0,1.0),random);' – Xharlie

2

你在這裏。隨機雙打範圍:

// For ints 
// replace _real_ with _int_, 
// <double> with <int> and use integer constants 

#include <random> 
#include <iostream> 
#include <ctime> 
#include <algorithm> 
#include <iterator> 

int main() 
{ 
    std::default_random_engine rng(std::random_device{}()); 
    std::uniform_real_distribution<double> dist(-100, 100); //(min, max) 

    //get one 
    const double random_num = dist(rng); 

    //or.. 
    //print 10 of them, for fun. 
    std::generate_n( 
     std::ostream_iterator<double>(std::cout, "\n"), 
     10, 
     [&]{ return dist(rng);}); 
    return 0; 
}