使用C++產生32位隨機數

提到生成隨機數,大多數人想到的是調用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.htmlhttp://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算法的分佈


  2. CryptGenRandom函數生成隨機數分佈圖

3. 使用三個rand()數生成一個32位隨機數的分佈圖



特別說明:

本文轉載自:http://www.cnblogs.com/thu539/archive/2011/11/14/2247717.html

發佈了42 篇原創文章 · 獲贊 5 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章