提到生成隨機數,大多數人想到的是調用C++中的rand()函數,但是這裏有個問題,rand()只能產生0~RAND_MAX(如在Visual Studio 2010上面最大爲0x7FFF,即32767), 如果需要產生的隨機數範圍是0~232-1,則rand()函數會力不從心,需要使用其他更有效的方法來實現32位隨機數的生成。
本文采用三種方法,分別爲Mersenne twister算法,調用Windows API CryptGenRandom函數來生成隨機數,採用三個rand()生成的數字來拼合爲一個數字。本文對這三種方法分別進行了介紹,並在實驗中使用這三種方法分別生成了一百萬個隨機數,並畫出了三種生成方法的數字分佈圖。
一.三種方法的介紹
1. Mersenne twister號稱是目前最好的隨機數生成算法,它是由Takuji Nishimura 和 Makoto Matsumoto於1997年開發的一種隨機數生成方法,它基於有限二進制字段上的矩陣線性再生,可以快速產生高質量的僞隨機數,該算法的循環週期爲219937-1。Mersenne twister這個名字來自週期長度通常取Mersenne質數這樣一個事實,常見的有兩個變種Mersenne Twister MT19937和Mersenne Twister MT19937-64,本文實驗的就是MT19937算法。關於這種算法更詳細的介紹,可以參考博客http://www.cppblog.com/Chipset/archive/2011/11/01/73177.html和http://www.cppblog.com/Chipset/archive/2009/01/19/72330.html,如果對算法本身感興趣,可以去該算法作者的頁面http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html去下載代碼實現,如果希望看到關於這個算法的論文,http://wenku.baidu.com/view/bd6c1209bb68a98271fefa91.html?from=related,這篇文章或許會有幫助。
產生size個32位隨機數的函數,調用MT19937中的隨機生成方法
bool ProduceRandomNumberMT19937(UINT* RandomArray,UINT size)
{
time_t t;
init_genrand((unsigned)time(&t));
if(RandomArray==NULL)
{
return false;
}
for(UINT i=0;i<size;i++)
{
RandomArray[i]=genrand_int32();
}
return true;
}
2. 第二種方法採用的是調用Windows API CryptGenRandom方法,這個函數是windows用來提供給生成隨機密碼數字功能所用,一般應用在隨機給vector賦值或者生成噪聲點時使用。這個函數所提供的隨機性要好於rand()函數。具體關於這個函數的信息,請關注msdn關於這個函數的解釋http://msdn.microsoft.com/zh-cn/site/aa379942。
使用CryptGenRandom函數生成size個32位隨機數的函數
bool ProduceRandomNumberCrypt(UINT* RandomArray,UINT size)
{
HCRYPTPROV hCryptProv;
if(CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
0))
{
//printf("CryptAcquireContext succeeded. \n");
}
else
{
//MyHandleError("Error during CryptAcquireContext!\n");
}
if(CryptGenRandom(
hCryptProv,
size*sizeof(UINT),
(BYTE*)RandomArray))
{
//printf("Random sequence generated. \n");
return true;
}
else
{
//printf("Error during CryptGenRandom.\n");
return false;
}
}
3. 第三種方法,是使用rand()函數隨機生成的三個數來拼接成一個32位數字的方法,這種方法實現起來也很簡單,但是由於rand()的隨機性並不是很好,所以不推薦這種方法。一個32位隨機數由(rand()<<17)|(rand()<<2)|(rand())方法拼合而成。實現代碼如下:
使用三個rand()生成僞隨機數生成一個32位隨機數
bool ProduceRandomNumberCRand(UINT* RandomArray,UINT size)
{
time_t t;
srand((unsigned)time(&t));
if(RandomArray==NULL)
{
return false;
}
for(UINT i=0;i<size;i++)
{
RandomArray[i]=(rand()<<17)|(rand()<<3)|(rand());
}
return true;
}
二. 三種方法的實驗結果
每種方法均進行了100萬個32位隨機數的生成實驗,將這100萬個隨機數分爲0xFFF個組,組之間的間隔爲0xFFFFF,然後繪出各個組生成隨機數的分佈圖。
1. MT19937算法的分佈
3. 使用三個rand()數生成一個32位隨機數的分佈圖
特別說明:
本文轉載自:http://www.cnblogs.com/thu539/archive/2011/11/14/2247717.html