摘 要偽隨機(jī)數(shù)在計(jì)算機(jī)軟件設(shè)計(jì)中有很廣泛的用途。本文介紹了基于數(shù)學(xué)方法的利用計(jì)算機(jī)產(chǎn)生偽隨機(jī)數(shù)的一種方法,即線性同余法,任何偽隨機(jī)數(shù)的產(chǎn)生都是運(yùn)用遞 推的原理來生成的。以及在Visual C++環(huán)境中產(chǎn)生偽隨機(jī)數(shù)的兩個(gè)重要函數(shù),rand和srand函數(shù),正確地使用這兩個(gè)函數(shù)是產(chǎn)生性能良好的偽隨機(jī)數(shù)的關(guān)鍵,最后介紹了利用偽隨機(jī)數(shù)生成 技術(shù)在MFC中生成基于C/S模式應(yīng)用程序的隨機(jī)校驗(yàn)碼以及利用一種軟件工具ImagePassword產(chǎn)生隨機(jī)密碼。

  關(guān)鍵詞偽隨機(jī)數(shù)生成;線性同余法;Visual C++;隨機(jī)校驗(yàn)碼

   為追求真正的隨機(jī)序列,人們?cè)捎煤芏喾N原始的物理方法用于生成一定范圍內(nèi)滿足精度(位數(shù))的均勻分布序列,其缺點(diǎn)在于:速度慢、效率低、需占用大量存 儲(chǔ)空間且不可重現(xiàn)等。為滿足計(jì)算機(jī)模擬研究的需求,人們轉(zhuǎn)而研究用算法生成模擬各種概率分布的偽隨機(jī)序列。偽隨機(jī)數(shù)是指用數(shù)學(xué)遞推公式所產(chǎn)生的隨機(jī)數(shù)。從 實(shí)用的角度看,獲取這種數(shù)的最簡單和最自然的方法是利用計(jì)算機(jī)語言的函數(shù)庫提供的隨機(jī)數(shù)發(fā)生器。典型情況下,它會(huì)輸出一個(gè)均勻分布在0和1區(qū)間內(nèi)的偽隨機(jī) 變量的值。其中應(yīng)用的最為廣泛、研究最徹底的一個(gè)算法即線性同余法。

  線性同余法LCG(Linear Congruence Generator)

  選取足夠大的正整數(shù)M和任意自然數(shù)n0,a,b,由遞推公式:

ni+1=(af(ni)+b)mod M i=0,1,…,M-1
  生成的數(shù)值序列稱為是同余序列。當(dāng)函數(shù)f(n)為線性函數(shù)時(shí),即得到線性同余序列:

ni+1=(a*ni+b)mod M i=0,1,…,M-1
  以下是線性同余法生成偽隨機(jī)數(shù)的偽代碼:

Random(n,m,seed,a,b)
{
 r0 = seed;
 for (i = 1;i<=n;i++)
 ri = (a*ri-1 + b) mod m
}

  其中種子參數(shù)seed可以任意選擇,常常將它設(shè)為計(jì)算機(jī)當(dāng)前的日期或者時(shí)間;m是一個(gè)較大數(shù),可以把它取為2w,w是計(jì)算機(jī)的字長;a可以是0.01w和0.99w之間的任何整數(shù)。

  應(yīng)用遞推公式產(chǎn)生均勻分布隨機(jī)數(shù)時(shí),式中參數(shù)n0,a,b,M的選取十分重要。

  例如,選取M=10,a=b =n0=7,生成的隨機(jī)序列為{6,9,0,7,6,9,……},周期為4。

  取M=16,a=5,b =3,n0=7,生成的隨機(jī)序列為{6,1,8,11,10,5,12,15,14,9,0,3,2,13,4,7,6,1……},周期為16。

  取M=8,a=5,b =1,n0=1,生成的隨機(jī)序列為{6,7,4,5,2,3,0,1,6,7……},周期為8。

  Visual C++中偽隨機(jī)數(shù)生成機(jī)制

   用VC產(chǎn)生隨機(jī)數(shù)有兩個(gè)函數(shù),分別為rand(void)和srand(seed)。rand()產(chǎn)生的隨機(jī)整數(shù)是在0~RAND_MAX之間平均分布 的,RAND_MAX是一個(gè)常量(定義為:#define RAND_MAX 0x7fff)。它是short型數(shù)據(jù)的最大值,如果要產(chǎn)生一個(gè)浮點(diǎn)型的隨機(jī)數(shù),可以將rand()/1000.0,這樣就得到一個(gè)0~32.767之間 平均分布的隨機(jī)浮點(diǎn)數(shù)。如果要使得范圍大一點(diǎn),那么可以通過產(chǎn)生幾個(gè)隨機(jī)數(shù)的線性組合來實(shí)現(xiàn)任意范圍內(nèi)的平均分布的隨機(jī)數(shù)。

  其用法是先調(diào)用srand函數(shù),如

srand( (unsigned)time( NULL ) )
   這樣可以使得每次產(chǎn)生的隨機(jī)數(shù)序列不同。如果計(jì)算偽隨機(jī)序列的初始數(shù)值(稱為種子)相同,則計(jì)算出來的偽隨機(jī)序列就是完全相同的。要解決這個(gè)問題,需要 在每次產(chǎn)生隨機(jī)序列前,先指定不同的種子,這樣計(jì)算出來的隨機(jī)序列就不會(huì)完全相同了。以time函數(shù)值(即當(dāng)前時(shí)間)作為種子數(shù),因?yàn)閮纱握{(diào)用rand函 數(shù)的時(shí)間通常是不同的,這樣就可以保證隨機(jī)性了。也可以使用srand函數(shù)來人為指定種子數(shù)。
分析以下兩個(gè)程序段,

  程序段1:

//包含頭文件
void main() {
 int count=0;
 for (int i=0;i<10;i++){
  srand((unsigned)time(NULL));
  count++;
  cout<<"No"<<<"="<<<" ?;

  程序段1中由于將srand()函數(shù)放在循環(huán)體內(nèi),而程序執(zhí)行的CPU時(shí)間較快,調(diào)用time函數(shù)獲取的時(shí)間精度卻較低(55ms),這樣循環(huán)體內(nèi)每次產(chǎn)生隨機(jī)數(shù)用到的種子數(shù)都是一樣的,因此產(chǎn)生的隨機(jī)數(shù)也是一樣的。而程序段2中第1次產(chǎn)生的隨機(jī)數(shù)要用到隨機(jī)種子,以后的每次產(chǎn)生隨機(jī)數(shù)都是利用遞推關(guān)系得到的。
?? 基于MFC的隨機(jī)校驗(yàn)碼生成

  Web應(yīng)用程序中經(jīng)常要利用到隨機(jī)校驗(yàn)碼,校驗(yàn)碼的主要作用是防止黑客利用工具軟件在線破譯用戶登錄密碼,校驗(yàn)碼、用戶名、密碼三者配合組成了進(jìn)入Web應(yīng)用系統(tǒng)的鑰匙。在利用VC開發(fā)的基于客戶機(jī)/瀏覽器(Client/Server)模式的應(yīng)用軟件系統(tǒng)中,為了防止非法用戶入侵系統(tǒng),通常也要運(yùn)用隨機(jī)校驗(yàn)碼生成技術(shù)。

  本實(shí)現(xiàn)要用到以上介紹到的偽隨機(jī)數(shù)生成技術(shù)。校驗(yàn)碼數(shù)據(jù)將以16進(jìn)制碼方式顯示。主要代碼如下:

void CRandompasswordDlg::OnCreatekey() {
 int RanCheckNum = 0;
 char out[25]={0};
 char keytemp[5]={0};
 memset(out,0x30,18);
 srand((unsigned)timeGetTime());//產(chǎn)生隨機(jī)數(shù)種子
 for(int i=0;i<6;i++){
  RanCheckNum = rand();//產(chǎn)生隨機(jī)數(shù)
  _itoa(RanCheckNum,keytemp,16);//將隨機(jī)數(shù)轉(zhuǎn)換成16進(jìn)制
  memcpy(&out[i*4],keytemp,strlen(keytemp));
 }
 out[24]=0x00;
 strcpy(m_key.GetBuffer(18),out);
 UpdateData(FALSE);
}

  運(yùn)行結(jié)果如圖1所示:



圖1 利用偽隨機(jī)數(shù)生成隨機(jī)校驗(yàn)碼

  程序運(yùn)行時(shí),由于每一次點(diǎn)擊"產(chǎn)生隨機(jī)校驗(yàn)碼"的系統(tǒng)時(shí)間不同,生成隨機(jī)數(shù)的種子就不一樣,因此產(chǎn)生的隨機(jī)數(shù)也是不一樣的,從而保證了校驗(yàn)碼生成的隨機(jī)性。

  利用ImagePassword工具產(chǎn)生隨機(jī)密碼

  ImagePassword提供一個(gè)可選擇的圖形陣列,通過隨機(jī)改變圖形陣列中的陣點(diǎn)圖形來產(chǎn)生隨機(jī)密碼。當(dāng)隨機(jī)點(diǎn)擊圖象陣列中的圖象陣點(diǎn),該陣點(diǎn)中的圖象發(fā)生變化。其運(yùn)行界面如圖2所示:



圖2 ImagePassword運(yùn)行界面

  點(diǎn)擊OK按鈕后所產(chǎn)生的隨機(jī)密碼如圖3所示:



圖3 ImagePassword運(yùn)行結(jié)果

  ImagePassword產(chǎn)生的密碼的隨機(jī)性依賴于用戶對(duì)圖象陣列中陣點(diǎn)圖象的隨機(jī)選擇,一般來說用戶在圖象陣列中隨機(jī)點(diǎn)擊鼠標(biāo)的次數(shù)越多,最后產(chǎn)生的密碼的隨機(jī)性越強(qiáng)。

  結(jié)束語

   偽隨機(jī)數(shù)在不同的軟件系統(tǒng)中都得到了很廣泛的應(yīng)用,如何選擇隨機(jī)數(shù)生成種子使得生成的偽隨機(jī)數(shù)性能更佳是軟件設(shè)計(jì)者追求的目標(biāo)之一。本文提到了利用系統(tǒng) 時(shí)間作為種子參數(shù)在一定條件下可以滿足軟件的隨機(jī)性需要。利用所產(chǎn)生的隨機(jī)數(shù)在游戲編程,如撲克類游戲中的隨機(jī)發(fā)牌,俄羅斯方塊的隨機(jī)生成等等其他應(yīng)用中 都起到很重要的作用。