隨機數生成算法-初探

隨機數生成算法調查和思考

一、線性同餘算法:html

      如今用得最普遍的僞隨機數產生算法就是所謂的線性同餘算法。其隨機數序列{Xn}由方程:Xn+1 = ( aXn + c ) mod m獲得,其中m>0稱爲模數,0≤ a <m稱爲乘數,0≤c <m稱爲增量,0≤X0<m稱爲初始值或種子,當m、a、c、X0都是整數時,經過這個方程就能產生一系列[0,m)範圍內的整數了。ios

      很明顯,對一個線性同餘隨機產生算法來講,最重要的是m、a、c的選擇。咱們但願產生的序列足夠長,能包含[0,m)內全部的數,而且產生的數是隨機的,最好能用32bit算術高效實現。因而乎爲了有足夠的空間產生足夠長的隊列,咱們會使m足夠大;爲了使序列足夠完整,足夠象隨機序列,咱們會發現當m是素數,c爲0時就可使序列的週期(即序列不重複的長度)對於必定的a達到m-1;要能用32bit算術高效實現,咱們的m固然不能超過32bit,幸虧恰好有一個知足上述條件的很方便的素數2^31-1給咱們用,因而產生函數就變成了Xn+1 = ( aXn) mod ( 2^31 – 1 )。在超過20億個a的可選取值中,只有不多的幾個能夠知足上述全部條件,其中之一就是a = 7^5 = 16807。因而咱們能夠實現以下:
     unsigned myrand()
     {
         return (seed = (seed * 10807L) & 0x7fffffffL);
     }
      這種產生器獲得了普遍的使用和比其它產生器都完全的測驗,其產生的隨機數有在分佈上有很好的特性,可是卻不具有良好的不可預測性。因此咱們在使用時每每會以系統時鐘(模m)或系統時鐘與隨機數的和(模m)做爲種子來從新啓動序列,這也是如今絕大多數隨機數產生器的作法。
       另外一種產生僞隨機數序列的方法就是使用加密邏輯,經過加密算法的雪崩效應,輸入的每一位改變就會形成輸出的巨大改變,而且假如密鑰被妥善保存的話從序列中前面的數推出後面的數在計算上是不可行的,因而咱們可使用一個簡單的累加器來做爲輸入,獲得的隨機序列能夠直接使用(固然也能夠把系統時間等等因素考慮進去做爲輸入來產生更隨機的序列,不過這一般是沒有必要的),這種方法經常用來產生會話密鑰或是現時。具體採用的加密邏輯和運算方式有不少,這裏就不一一介紹了,你們感興趣能夠找本密碼學的書來看看。
        在密碼學領域裏比較流行的一種產生安全的僞隨機數的方法是BBS產生器,它用其研製者的名字命名(Blum Blum Shub,不是咱們常常灌水的那個BBS),它的密碼編碼強度聽說具備最強的公開證實。首先,咱們找兩個大素數p和q,要求它們被4除都餘3,令n = p×q,再選擇一個隨機數s,使s與n互素,而後咱們經過以下算法產生一系列比特Bi:
X0 = (s^2)mod n,
for i = 1 to ∞
Xi = (Xi-1^2)mod n
Bi = Xi mod 2
每次迭代都只取出最低位的bit。能夠看出BBS產生隨機數的過程很是複雜,運算量很大,嗯,這就是爲安全性付出的代價-c++

二、平方截取法:算法

找一個大數,如123456789 
平方,得15241578750190521 
取中段157875019 
把它平方,得24924521624250361 
取中段452162425 
平方....... 
這樣能得一個僞隨機序列 
123456789 
157875019 
452162425  數組

三、C語言算法示例:安全

/*1.從同一個種子開始*/
#include <stdio.h>
#include <conio.h>
static unsigned long int next=1;
int rand0(void)
{
next=next*1103515245+12345;
return (unsigned int)(next/65536)%32768;
}
int main(void)
{
int count;
for(count=0;count<5;count++)
    printf("%hd\n",rand0());
getch();
return 0;
}函數


/*2.重置種子*/
#include <stdio.h>
#include <conio.h>
static unsigned long int next=1;測試


int rand1(void)
{
next=next*1103515245+12345;
return (unsigned int)(next/65536)%32768;
}編碼


void srand1(unsigned int seed)
{
next=seed;
}加密


int main(void)
{
int count;
unsigned int seed;
printf("please input seed:");
scanf("%u",&seed);
srand1(seed);
for(count=0;count<5;count++)
    printf("%hd\n",rand1());
getch();
return 0;
}


/*3.利用利用時鐘產生種子
ANSI C程序庫提供了rand()函數來產生隨機數;
ANSI C程序庫提供了srand()函數來產生種子;
ANSI C程序庫提供了time()函數返回系統時間。
*/
#include <time.h>
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <stdlib.h>
int main(void)
{
   int i;
   time_t t;
   clrscr();
   t = time(NULL);
   srand((unsigned) t);
   for(i=0; i<10; i++) printf("%d\n", rand()%10);
   getch();
   return 0;
}

四、C++語言算法示例(洗牌算法):

1:首先將4*13的數組(52張牌,4種花色,每種13張)依次從1 ~52進行排列序號。

2:經過隨機數,隨機選取1個行與列(即隨機得到一種花色和此花色的一張牌),而後比較是否等於本來的序號。若是等於,則跳過,若是不等於,.那麼尋找牌的序號。在後,交換隨機位置的牌與序號牌。經過序號牌來判斷是否發牌結束。

C++算法:

#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include <time.h>

void shuff(int [][ 13 ] );      //洗牌
void deal(int [][ 13 ] );       //發牌

//void print(int [][ 13 ]);       //測試打印

int main()
{

int deck[ 4 ][ 13 ] = { 0 }; //初始化牌

srand( time( 0 ) ); //初始化隨機數種子
shuff( deck );
deal( deck );

// print( deck );

return 0;
}
//洗牌
void shuff(int wDeck[][ 13 ] )
{
int card = 1;
for(int i = 0; i < 4; i++ )
{
   for(int j = 0; j < 13; j++ )
   {
    wDeck[ i ][ j ] = card++;
   }
}
}
//發牌
void deal(int wDeck[][ 13 ] )
{
int cow,column;    //順序牌的所在位置
int hang,lie;      //隨機牌
int temp;          //交換變量
cow = column = hang = lie = temp = 0;
for(int card = 1; card <= 52; card++ )
{
   hang = rand() % 4;    //隨機牌的行
   lie = rand() % 13;    //隨機牌的列

   do{
    cow = rand() % 4;
    column = rand() % 13;
   }while( card != wDeck[ cow ][ column ] );   //取得順序牌

   if(wDeck[ cow ][ column ] != wDeck[ hang ][ lie ]) //交換牌
   {
    temp = wDeck[ cow ][ column ];
    wDeck[ cow ][ column ] = wDeck[ hang ][ lie ];
    wDeck[ hang ][ lie ] = temp;
   }
  
}
}
/*
//測試打印
void print(int wDeck[][ 13 ])
{
for(int i = 0; i < 4; i++ )
{
   for(int j = 0; j < 13; j++ )
   {
    cout << setw( 4 ) << wDeck[ i ][ j ] << " ";
   }
   cout << endl;
}

}*/

五、C++語言算法示例(VC6.0實驗):

#include<iostream.h>
#include <time.h>
#include <iomanip.h>
#include <stdlib.h>

//srand from [0,n),簡單的使用rand()%n,獲得的隨機數,不夠隨機
int ssrand(int n)
{
    if( n<=0 || n >RAND_MAX)
{
   cout<<"Error"<<endl;
   return -1;
}

return (rand()%n);
}

//srand from [0,n),隨機數更爲隨機些
int nsrand(int n)
{
if( n<=0 || n >RAND_MAX)
{
   cout<<"Error"<<endl;
   return -1;
}

const int bucket_size=RAND_MAX/n;

int r;

do r= rand()/bucket_size;
while(r >= n);


return r;
}

void main()
{
   int n=2; //29

   time_t t;
   t = time(NULL);
   srand((unsigned) t);

int i=0;
while( i< 10*n )
{
   cout<<ssrand(n)<<ends;
   i++;
}
   cout<<endl;


    i=0;
while( i< 10*n )
{
   cout<<nsrand(n)<<ends;
   i++;
}
   cout<<endl;

}

來自:

http://hi.baidu.com/%B6%E0%CE%AC%CA%FD%D7%E9/blog/item/05e92f343f7e783f5ab5f5c9.html

http://topic.csdn.net/t/20020701/19/842253.html

http://hi.baidu.com/pxyn/blog/item/9c9012385680f0f2b311c7eb.html

http://hi.baidu.com/watsy/blog/item/b71b5a3d2a593fe83c6d97d2.html

參考:accelerated c++

相關文章
相關標籤/搜索