(注:這裏生成的隨機數所處的分佈爲 0-1 區間上的均勻分佈。不是 0-1 區間怎麼辦? 除以 (high-low), 再加上 low 就可以完成任務。我們需要的隨機數序列應具有非退化性,週期長,相關係數小等優點。)
這裏在迭代取中法中介紹平方取中法 , 其迭代式如下 :
Xn+1=(Xn^2/10^s)(mod 10^2s)
Rn+1=Xn+1/10^2s
其中,Xn+1是迭代算子,而 Rn+1 則是每次需要產生的隨機數。
第一個式子表示的是將 Xn 平方後右移 s 位,並截右端的 2s 位。
而第二個式子則是將截尾後的數字再壓縮 2s 倍,顯然 :0=<Rn+1<=1。
迭代取中法有一個顯著的不良特性就是它比較容易退化成 0。
#include <stdio.h>
#include <math.h>
#define S 2
float Xn=12345; //Seed & Iter
float Rn; //Return Val
void InitSeed(float inX0)
{
Xn=inX0;
}
float MyRnd()
{
//implementation: Xn+1=(Xn^2/10^S)(mod 10^2S)
Xn=(int)fmod((Xn*Xn/pow(10,S)),pow(10,2*S));//here can's use %
//implementation: Rn+1=Xn+1/10^2S
Rn=Xn/pow(10,2*S);
return Rn;
}
int main()
{
int i;
FILE * debugFile;
if((debugFile=fopen("outputData.txt","w"))==NULL)
{
fprintf(stderr,"open file error!");
return -1;
}
printf("\n");
for(i=0;i<100;i++)
{
tempRnd=MyRnd();
fprintf(stdout,"%f ",tempRnd);
fprintf(debugFile,"%f ",tempRnd);
}
getchar();
return 0;
}
前一百個測試生成的隨機數序列(明顯可見其容易退化爲0):
0.399000 0.920100 0.658400 0.349000 0.180100 0.243600 0.934000 0.235600 0.550700 0.327000 0.692900 0.011000 0.012100 0.014600 0.021300 0.045300 0.205200 0.210700 0.439400 0.307200 0.437100 0.105600 0.115100 0.324800 0.549500 0.195000 0.802500 0.400600 0.048000 0.230400 0.308400 0.511000 0.112100 0.256600 0.584300 0.140600 0.976800 0.413800 0.123000 0.512900 0.306600 0.400300 0.024000 0.057600 0.331700 0.002400 0.000500 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
2、乘同餘法:
乘同餘法的迭代式如下:
Xn+1=Lamda*Xn(mod M)
Rn+1=Xn/M
當然,這裏的參數選取是有一定理論基礎的,否則所產生的隨機數的週期將較小,相關性會較大。經過前人檢驗的兩組性能較好的素數取模乘同餘法迭代式的係數爲:
Lamda=5^5,M=2^35-31
Lamda=7^5,M=2^31-1
實現代碼(C語言)關鍵部分:
double long M;//請注意,這裏一定要用到double long,否則計算2^32會溢出
float MyRnd()
{
Xn=fmod(Lamda*Xn,M);//here can's use %
Rn=Xn/M;
return Rn;
}
另外初始化段應有:
Lamda=pow(5,5);
M=pow(2,35)-31;
前三百個測試生成的隨機數序列(可見該隨機數生成方法所生成的隨機序列比較符合0-1上的均勻分佈,不過在某些數據段還有些起伏):
圖1: 乘同餘法生成的300隨機數的產生序列圖
float MyRnd()
{
Xn=fmod(Lamda*Xn+Miu,M);
Rn=Xn/M;
return Rn;
}
另外初始化段應有:
M=pow(2,32);
Lamda=pow(2,16)+1;
Miu=(0.5+sqrt(3)/6)/M;