2016-07-17 41 views
3

,我正在考慮的方法是:https://stackoverflow.com/a/19728404/6571958在C++中如何在計算上產生一個隨機數?

#include <random> 

std::random_device rd;  // only used once to initialise (seed) engine 
std::mt19937 rng(rd()); // random-number engine used (Mersenne-Twister in this case) 
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased 

auto random_integer = uni(rng); 

我也願意用rand()方法與srand(time(NULL))

我的問題:這些方法有多昂貴?比另一個快得多嗎?

+11

構建基準測試並找出答案。如果你關心表現,你會衡量它。如果你不測量,這意味着你並不在乎。 –

回答

4

性能很大程度上取決於您使用的發生器(反過來,這取決於您所需數字的質量)。

例如,std::mt19937很多快於std::random_device但產生僞隨機數。 如果您不需要密碼安全的隨機數,那麼對於大多數用途而言,這很好。但即使你這樣做,random_device可以在我的機器上以約50MB /秒的速度產生原始熵 - 你真正需要多少隨機性? (如果需要,mt19937產生的數量級大於該數量級)。

避免rand()。它只有非常差的特性和非常短的時間。

https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

+0

更好的鏈接:https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful –

+0

注意std :: random_device的性能取決於很多因素,包括哪個編譯器你使用(gcc和clang有不同的實現),甚至你運行你的程序的機器有多忙(因爲熵)。它可以佔用儘可能多的時間,所以你不一定假設你的速度在任何時候都會達到50MB/sec。 –

+1

的確如此,但我只是想說明一點。僞隨機==快,通常足夠好。真正的隨機==較慢,但通常足夠快。總結,除非你做了一些愚蠢的事情,否則兩者通常都足夠快達到預期的目的。 –

1

見我可以寫性能取決於實施和硬件,但它會作爲沒用,因爲正確的。表現的一個例子會更有用。

E7240筆記本電腦,Linux中,G ++ 4.8.4,-O3標誌

#include <cstdlib> 
#include <iostream> 

int main(int argc, const char** argv) { 
    const bool bPlain = (argv[1][0] == '-'); 
    if (bPlain) 
     argv++; 
    int n = atoi(argv[1]); 
    int sum = 0; 
    if (bPlain) 
     for (int i=0; i<n; i++) 
      sum |= i; 
    else 
     for (int i=0; i<n; i++) 
      sum |= rand(); 
    // To prevent the compilier from optimizing away the loop 
    if (sum == 0) 
     std::cout << sum << std::endl; 
} 

[~/CPP] time ./randbm 1000000000 
9.049u 0.000s 0:09.05 99.8% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm 1000000000 
9.059u 0.000s 0:09.06 99.8% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm 1000000000 
9.040u 0.008s 0:09.05 99.8% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm - 1000000000 
0.192u 0.000s 0:00.20 95.0% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm - 1000000000 
0.172u 0.000s 0:00.18 94.4% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm - 1000000000 
0.185u 0.004s 0:00.20 90.0% 0+0k 0+0io 0pf+0w 

所以,在這種特定情況下,一個呼叫到蘭特()需要大約9納秒,而一個循環迭代需要大約0.2納秒。

使用random比較慢。添加#include <random>並通過更換代碼的相關部分:

std::random_device rd;  // only used once to initialise (seed) engine 
std::mt19937 rng(rd()); // random-number engine used (Mersenne-Twister in this case) 
std::uniform_int_distribution<int> uni(0, 1048575); 

if (bPlain) 
    for (int i=0; i<n; i++) 
     sum |= i; 
else 
    for (int i=0; i<n; i++) 
     sum |= uni(rng); 

我們得到了(注意我們做1E8運行,不1E9):

[~/CPP] time ./randbm2 100000000 
2.478u 0.003s 0:02.49 99.1% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm2 100000000 
2.471u 0.004s 0:02.47 100.0% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm2 100000000 
2.445u 0.007s 0:02.48 98.3% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm2 100000000 
2.497u 0.004s 0:02.50 99.6% 0+0k 0+0io 0pf+0w 
[~/CPP] time ./randbm2 100000000 
2.482u 0.011s 0:02.49 100.0% 0+0k 0+0io 0pf+0w 

產生隨機數,這種方式需要大約25納秒。然而,與rand()不同,uni也會將該數字插入到區間中。

那些額外的工作是否重要?例如,如果你做

sum |= (rand() % 1048576); 

時間從9增加到9.5納秒。如果該數字不是2的冪,e。 G。

sum |= (rand() % 1000000); 

需要10納秒。將數字插入間隔的其他合理方法大致需要同一時間。

所以,對於一個特定的配置,rand()本身大約需要9納秒;連同隨機數插入間隔,大約需要9.5-10納秒; std::mt19937uniform_int_distribution<int>大致需要25納秒

我希望你不是那些以毫秒爲單位混淆納秒的人!

+1

請不要主張使用模運算來生成默認範圍以外的制服。它介紹了[modulo bias](http://stackoverflow.com/a/10984975/2166798)。 – pjs

+0

我寫道:「將數字插入間隔的其他合理方法大致需要同一時間。」我討論速度,而不是隨機數字的質量。最後,對於許多實現來說,rand()的質量很差。 – user31264