Delphi的Random函数有一个问题——每个版本的Delphi的Random函数的随机数产生方法都不一样,
如果你希望用不同版本的Delphi编译出来的程序产生的随机数有“可再现性”,必须自己定义一个
随机函数。
下面是我写的一个例子,献丑了。
unit Crypto;
interface
uses
Windows;
procedure MyRandomize(const RandomSeek,StartNum:Integer);
function MyRandom(const N
Word)
Word;
implementation
var
RandomSeekNum,NowNum:Integer;
procedure MyRandomize(const RandomSeek,StartNum:Integer);
begin
RandomSeekNum:=RandomSeek xor 2084626433;
NowNum:=StartNum xor 1041592654;
end;
function MyRandom(const N
Word)
Word;
var
m,m1:Integer;
begin
m:=((DWord(NowNum) and $80000000)shr 31)xor((DWord(NowNum) and $00200000)shr 21)xor((DWord(NowNum) and $00000400)shr 10)xor(DWord(NowNum) and $00000001);
m1:=((DWord(NowNum) and $80500000)shr 21)xor((DWord(NowNum) and $08200000)shr 20)xor((DWord(NowNum) and $00000400)shl 10)xor(DWord(NowNum) and $00000041);
NowNum:=(RandomSeekNum xor m1)+((NowNum shl 1)xor m);
Result:=DWord(NowNum) mod N;
end;
下面的过程用于产生一个随机的文件——如果文件足够大,你就会发现——该文件中各个ASCII码的出现概率完全一样。
uses Crypto;
procedure TForm1.Button1Click(Sender: TObject);
const
BufLength=8192;
var
i,j,n,key,m,Temp:Integer;
Buf:array[1..BufLength] of Byte;
Ay,By:array[0..BufLength-1]of Integer;
FS:TFileStream;
begin
n:=StrToIntDef(Edit1.Text,0);
//随机文件长度(以K为单位)
if n<1024 then
begin
Edit1.Text:='1024';
exit;
end
else
if n>40960 then
begin
Edit1.Text:='40960';
exit;
end;
FS:=TFileStream.Create('Random.dat',fmCreate);
m:=0;
key:=StrToIntDef(Edit2.Text,0);
//随机数种子
for i:=0 to BufLength-1do
By
:=1+i;
while n>0do
begin
for i:=0 to BufLength-1do
Ay:=1+(i+n) mod BufLength;
MyRandomize(key-n*2,m xor n);
for i:=0 to BufLength-1do
begin
j:=Integer(MyRandom(BufLength-i))+i;
Temp:=Ay[j];
Ay[j]:=Ay;
Ay:=Temp;
end;
for i:=0 to BufLength-1do
begin
j:=Integer(MyRandom(BufLength-i))+i;
Temp:=By[j];
By[j]:=By;
By:=Temp;
Buf[Ay]:=Temp;
end;
FS.Write(Buf,BufLength);
m:=m+PInteger(@Buf[BufLength-3])^;
Dec(n,BufLength div 1024);
end;
FS.Free;
Close;
end;