隨機數計算法比較,更好的隨機數對於程序是否真的值得。


隨機數計算法比較,更好的隨機數對於程序是否真的值得。

本次,我們將評測四種隨機數生成法
測試語言為C++
測試有不嚴謹的地方歡迎提出。
本文僅僅發布於博客園

下面是他們時間表現

名稱 生成\(1\times 10^9\)個隨機數耗時(ms)
庫函數rand耗時 8634
mt19937 8176
xorshift32耗時 6724
modrand耗時 6116

算法介紹

庫函數rand

這個不用多說,cstdlib里的庫函數。

用的就是LCG(linear congruential generator)算法

基於\(X(n+1) = (a * X(n) + c) \mod m\)​這樣的公式

下面的modrand就是手寫實現的這種算法。

mt19937

也就是Mersenne Twister MT19937(馬特賽特旋轉演算法)的實現。

基於有限二進制字段上的矩陣線性再生。可以快速產生高質量的偽隨機數,修正了古老隨機數產生算法的很多缺陷。

轉載自百度百科:

Mersenne Twister算法的原理:Mersenne Twister算法是利用線性反饋移位寄存器(LFSR)產生隨機數的,LFSR的反饋函數是寄存器中某些位的簡單異或,這些位也稱之為抽頭序列。一個\(n\)位的LFSR能夠在重復之前產生\(2^n-1\)位長的偽隨機序列。只有具有一定抽頭序列的LFSR才能通過所有\(2^n-1\)個內部狀態,產生\(2^n - 1\)位長的偽隨機序列,這個輸出的序列就稱之為m序列。為了使LFSR成為最大周期的LFSR,由抽頭序列加上常數1形成的多項式必須是本原多項式。一個n階本原多項式是不可約多項式,它能整除\(x^(2*n-1)+1\)而不能整除\(x^d+1\),其中d能整除\(2^n-1\)。例如\((32,7,5,3,2,1,0)\)是指本原多項式\(x^32+x^7+x^5+x^3+x^2+x+1\),把它轉化為最大周期LFSR就是在LFSR的第\(32,7,5,2,1\)位抽頭。利用上述兩種方法產生周期為\(m\)的偽隨機序列后,只需要將產生的偽隨機序列除以序列的周期,就可以得到\((0,1)\)上均勻分布的偽隨機序列了。

Mersenne Twister有以下優點:隨機性好,在計算機上容易實現,占用內存較少(mt19937的C程式碼執行僅需\(624\)個字的工作區域),與其它已使用的偽隨機數發生器相比,產生隨機數的速度快、周期長,可達到2^19937-1,且具有623維均勻分布的性質,對於一般的應用來說,足夠大了,序列關聯比較小,能通過很多隨機性測試。

xorshift32

int xorshift32()
{
    static int x(13147);
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    return x;
}

是一個比較復雜的數論問題,作者也不會。

modrand

看代碼就知道是什么原理了

unsigned int modrand()
{
    static int seed(13147);
    seed = (seed * 31 + 13) % ((1 << 31) - 1);
    return seed;
}

實際表現

上面的算法,有的實現快,但是生成的質量不一定高,有的質量高,生成就更慢。

所以實際表現到底怎么樣呢?

我將對下面的項目進行測試

序號 項目名
1 FHQ_Treap實現普通平衡樹(數據加強版)

上面兩個應該是隨機函數比較常見的應用了。

結果

FHQ_Treap(Rand生成速度將影響總時間,而隨機數的質量將影響樹高,也會影響總時間)

名稱 耗時(s)
庫函數rand耗時 8.33s
mt19937 8.72s
xorshift32耗時 8.34s
modrand耗時 8.72s

可以發現rand本身就夠用了,除非有特殊要求沒必要換用其他的函數。更沒必要自己手寫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM