D
DarwinZhang
Unregistered / Unconfirmed
GUEST, unregistred user!
先祝大家新年好!给各位拜个年了!
偶尔看到:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=626178
因为Delphi产生的随机数字是伪随机的,其所有的随机性都来自第一次的Randomize,
其随机性约 1e-6/0.1=1/100000,用于加密等应用将有遭到破解的危险!
想到应该如何产生一个随机数,
我希望产生随机数的方法,即不需要特殊的硬件,又能有真正的不可预测性,
而且产生的速度要能够令人接受。
对原帖进行查找,发现了如下帖子对我很有启发,
http://www.delphibbs.com/delphibbs/dispq.asp?lid=650976
http://www.delphibbs.com/delphibbs/dispq.asp?LID=1019143
http://www.delphibbs.com/delphibbs/dispq.asp?lid=622076
经过仔细思考,我想到了一个产生随机数的办法,特贴出来供各位参考。
如有不正确的地方,还请各位指正!
原理:我发现硬盘有个指标叫平均寻道时间,精确到0.1ms,是不是0.1ms以下的时间是随机数呢?
经过测试,证实确实硬盘的读写时间到0.01ms级别的时候基本符合均匀随机分布!这样,
这样,利用磁盘读写包括机械动作,延迟时间(约ms级)远慢于电子设备的响应时间(约us~ns级),
从而利用高速计数器来获得不同写磁盘的时间,用其中的随机性来获得随机数。下面是代码:
测试平台: K6-2-450+128SDRAM+Win2K+Delphi7(Build4.453)
测试人: DarwinZhang 时间: 2003.1.31
--------------------UnitReadHD.pas---------------------------
unit UnitReadHD;
interface
uses
Classes,Windows;
//获得若干个整数随机变量 0~MaxValue-1区间 随机数据空间 数据长度
procedure DarwinZhangRandom(MaxValue:Integer;
DatasIntegerArray;
DataLength:Integer);
implementation
procedure DarwinZhangRandom(MaxValue:Integer;
DatasIntegerArray;
DataLength:Integer);
//获得一个
const
TempFN='C:/DarwinZhangTempFile.Temp';
BufferSize=512;
var
Buf:Array [0..BufferSize-1] of Byte;
f:File of Byte;
bt,et:Int64;
i,j,OldTP,
Hi,RealValue:Integer;
xouble;
begin
OldTP:=GetThreadPriority(GetCurrentThread);
SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_TIME_CRITICAL);
X:=ln(MaxValue)/ln(64);
Hi:=Trunc(x);
if X=Hi then
Dec(Hi);
//获得一个随机数需要获得的次
RealValue:=1 shl (Hi*6+6);
//区间大小
try
for i:=0 to DataLength-1do
begin
Datas:=0;
for j:=0 to Hido
begin
QueryPerformanceCounter(bt);
AssignFile(f,TempFN);
Rewrite(f);
BlockWrite(f,Buf,BufferSize);
CloseFile(f);
DeleteFile(TempFN);
QueryPerformanceCounter(et);
Datas:=Datas+((et-bt) mod 64)shl (j*6);
//获得写一个扇区的时间
end;
Datas:=Round(Datas*MaxValue/RealValue);
end;
finally
SetThreadPriority(GetCurrentThread,OldTP);
end;
end;
end.
----------------------------unit1.pas-仅作测试用而已----------------------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Image1: TImage;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
procedure DrawGraph;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses UnitReadHD;
//DarwinZhang的随机数产生方法,用DarwinZhang的图形显示方法
const MaxTime=10000;
var Datas:Array [0..MaxTime-1] of Integer;
procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
bt,etWord;
begin
if Button1.Tag<>0 then
exit;
Button1.Tag:=1;
bt:=GetTickCount;
DarwinZhangRandom(200,@Datas,MaxTime);
et:=GetTickCount;
//利用面来显示随机分布情况
Image1.Canvas.Brush.Color:=clGreen;
Image1.Canvas.FillRect(Rect(0,0,200,200));
for i:=0 to MaxTime-1do
Image1.Canvas.Pixels[(i mod 200),(Datas mod 200)]:=Clred;
Caption:='';
for i:=0 to 9do
Caption:=Caption+IntToStr(Datas[i*100])+' ';
ShowMessage(IntToStr(et-bt));
//生成10000随机数总时间,大约8ms产生一个随机数
Button1.Tag:=0;
end;
//Delphi的随机数产生方法,用DarwinZhang的图形显示方法
procedure TForm1.Button2Click(Sender: TObject);
const MaxTime=10000;
var
i:Integer;
bt,etWord;
begin
if Button2.Tag<>0 then
exit;
Button2.Tag:=1;
bt:=GetTickCount;
Randomize;
for i:=0 to MaxTime-1do
begin
// Randomize;
//把这一句有效,效果很差
Datas:=Random(200);
end;
et:=GetTickCount;
Image1.Canvas.Brush.Color:=clGreen;
Image1.Canvas.FillRect(Rect(0,0,200,200));
for i:=0 to MaxTime-1do
Image1.Canvas.Pixels[(i mod 200),Datas]:=Clred;
Caption:='';
for i:=0 to 9do
Caption:=Caption+IntToStr(Random(200))+' ';
ShowMessage(IntToStr(et-bt));
Button2.Tag:=0;
end;
const
DivNumber=2000;
var
RandRecord:array[0..DivNumber-1]of Integer;
procedure TForm1.DrawGraph;
//显示产生的数字是否均匀(此处分了200个区间,效果还可以)
var
i,h,w,x1,x2,y,max:Integer;
begin
h:=Image1.Height;
w:=Image1.Width;
max:=0;
for i:=0 to DivNumber-1do
if max<RandRecord then
max:=RandRecord;
with Image1.Canvasdo
begin
Brush.Color:=clBlack;
FillRect(Rect(0,0,w,h));
if max=0 then
exit;
Brush.Color:=clLime;
for i:=0 to DivNumber-1do
begin
x1:=w*i div DivNumber;
x2:=w*(i+1) div DivNumber;
y:=h*RandRecord div max;
FillRect(Rect(x1,h,x2,h-y));
end;
end;
end;
//DarwinZhang的随机数产生方法,用creation-zy----aimingoo的图形显示方法
procedure TForm1.Button3Click(Sender: TObject);
const MaxTime=600;
var
Datas:Array [0..MaxTime-1] of Integer;
i:Integer;
begin
if Button3.Tag<>0 then
exit;
Button3.Tag:=1;
DarwinZhangRandom(DivNumber,@Datas,MaxTime);
FillChar(RandRecord,SizeOf(RandRecord),0);
for i:=0 to MaxTime -1do
Inc(RandRecord[Datas]);
DrawGraph;
Button3.Tag:=0;
end;
end.
实验的结果基本达到我的预想!随机数的分布比较理想,基本符合均匀分布,
条件也很简单:只要您的C:盘上有一个蔟的空间(约2~32K Bytes)就可以!
而且速度可以接受: 2^1000(大约10^300)种可能每秒。
对比Delphi和aimingoo的随机算法,我的算法速度上要慢很多,但我的随机数的不可预测性要高很多。
看creation-zy兄的算法,有个疑问,windows的调度线程时间片算法产生的分配差额是否是真正随机。
我对windows的内核并无了解,如果是等待硬盘或响应其他外设产生的延时确实能引起的分配差,
那么本质上和我的原理是相类似的,但我的方法产生速度要快很多。
偶尔看到:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=626178
因为Delphi产生的随机数字是伪随机的,其所有的随机性都来自第一次的Randomize,
其随机性约 1e-6/0.1=1/100000,用于加密等应用将有遭到破解的危险!
想到应该如何产生一个随机数,
我希望产生随机数的方法,即不需要特殊的硬件,又能有真正的不可预测性,
而且产生的速度要能够令人接受。
对原帖进行查找,发现了如下帖子对我很有启发,
http://www.delphibbs.com/delphibbs/dispq.asp?lid=650976
http://www.delphibbs.com/delphibbs/dispq.asp?LID=1019143
http://www.delphibbs.com/delphibbs/dispq.asp?lid=622076
经过仔细思考,我想到了一个产生随机数的办法,特贴出来供各位参考。
如有不正确的地方,还请各位指正!
原理:我发现硬盘有个指标叫平均寻道时间,精确到0.1ms,是不是0.1ms以下的时间是随机数呢?
经过测试,证实确实硬盘的读写时间到0.01ms级别的时候基本符合均匀随机分布!这样,
这样,利用磁盘读写包括机械动作,延迟时间(约ms级)远慢于电子设备的响应时间(约us~ns级),
从而利用高速计数器来获得不同写磁盘的时间,用其中的随机性来获得随机数。下面是代码:
测试平台: K6-2-450+128SDRAM+Win2K+Delphi7(Build4.453)
测试人: DarwinZhang 时间: 2003.1.31
--------------------UnitReadHD.pas---------------------------
unit UnitReadHD;
interface
uses
Classes,Windows;
//获得若干个整数随机变量 0~MaxValue-1区间 随机数据空间 数据长度
procedure DarwinZhangRandom(MaxValue:Integer;
DatasIntegerArray;
DataLength:Integer);
implementation
procedure DarwinZhangRandom(MaxValue:Integer;
DatasIntegerArray;
DataLength:Integer);
//获得一个
const
TempFN='C:/DarwinZhangTempFile.Temp';
BufferSize=512;
var
Buf:Array [0..BufferSize-1] of Byte;
f:File of Byte;
bt,et:Int64;
i,j,OldTP,
Hi,RealValue:Integer;
xouble;
begin
OldTP:=GetThreadPriority(GetCurrentThread);
SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_TIME_CRITICAL);
X:=ln(MaxValue)/ln(64);
Hi:=Trunc(x);
if X=Hi then
Dec(Hi);
//获得一个随机数需要获得的次
RealValue:=1 shl (Hi*6+6);
//区间大小
try
for i:=0 to DataLength-1do
begin
Datas:=0;
for j:=0 to Hido
begin
QueryPerformanceCounter(bt);
AssignFile(f,TempFN);
Rewrite(f);
BlockWrite(f,Buf,BufferSize);
CloseFile(f);
DeleteFile(TempFN);
QueryPerformanceCounter(et);
Datas:=Datas+((et-bt) mod 64)shl (j*6);
//获得写一个扇区的时间
end;
Datas:=Round(Datas*MaxValue/RealValue);
end;
finally
SetThreadPriority(GetCurrentThread,OldTP);
end;
end;
end.
----------------------------unit1.pas-仅作测试用而已----------------------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Image1: TImage;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
procedure DrawGraph;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses UnitReadHD;
//DarwinZhang的随机数产生方法,用DarwinZhang的图形显示方法
const MaxTime=10000;
var Datas:Array [0..MaxTime-1] of Integer;
procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
bt,etWord;
begin
if Button1.Tag<>0 then
exit;
Button1.Tag:=1;
bt:=GetTickCount;
DarwinZhangRandom(200,@Datas,MaxTime);
et:=GetTickCount;
//利用面来显示随机分布情况
Image1.Canvas.Brush.Color:=clGreen;
Image1.Canvas.FillRect(Rect(0,0,200,200));
for i:=0 to MaxTime-1do
Image1.Canvas.Pixels[(i mod 200),(Datas mod 200)]:=Clred;
Caption:='';
for i:=0 to 9do
Caption:=Caption+IntToStr(Datas[i*100])+' ';
ShowMessage(IntToStr(et-bt));
//生成10000随机数总时间,大约8ms产生一个随机数
Button1.Tag:=0;
end;
//Delphi的随机数产生方法,用DarwinZhang的图形显示方法
procedure TForm1.Button2Click(Sender: TObject);
const MaxTime=10000;
var
i:Integer;
bt,etWord;
begin
if Button2.Tag<>0 then
exit;
Button2.Tag:=1;
bt:=GetTickCount;
Randomize;
for i:=0 to MaxTime-1do
begin
// Randomize;
//把这一句有效,效果很差
Datas:=Random(200);
end;
et:=GetTickCount;
Image1.Canvas.Brush.Color:=clGreen;
Image1.Canvas.FillRect(Rect(0,0,200,200));
for i:=0 to MaxTime-1do
Image1.Canvas.Pixels[(i mod 200),Datas]:=Clred;
Caption:='';
for i:=0 to 9do
Caption:=Caption+IntToStr(Random(200))+' ';
ShowMessage(IntToStr(et-bt));
Button2.Tag:=0;
end;
const
DivNumber=2000;
var
RandRecord:array[0..DivNumber-1]of Integer;
procedure TForm1.DrawGraph;
//显示产生的数字是否均匀(此处分了200个区间,效果还可以)
var
i,h,w,x1,x2,y,max:Integer;
begin
h:=Image1.Height;
w:=Image1.Width;
max:=0;
for i:=0 to DivNumber-1do
if max<RandRecord then
max:=RandRecord;
with Image1.Canvasdo
begin
Brush.Color:=clBlack;
FillRect(Rect(0,0,w,h));
if max=0 then
exit;
Brush.Color:=clLime;
for i:=0 to DivNumber-1do
begin
x1:=w*i div DivNumber;
x2:=w*(i+1) div DivNumber;
y:=h*RandRecord div max;
FillRect(Rect(x1,h,x2,h-y));
end;
end;
end;
//DarwinZhang的随机数产生方法,用creation-zy----aimingoo的图形显示方法
procedure TForm1.Button3Click(Sender: TObject);
const MaxTime=600;
var
Datas:Array [0..MaxTime-1] of Integer;
i:Integer;
begin
if Button3.Tag<>0 then
exit;
Button3.Tag:=1;
DarwinZhangRandom(DivNumber,@Datas,MaxTime);
FillChar(RandRecord,SizeOf(RandRecord),0);
for i:=0 to MaxTime -1do
Inc(RandRecord[Datas]);
DrawGraph;
Button3.Tag:=0;
end;
end.
实验的结果基本达到我的预想!随机数的分布比较理想,基本符合均匀分布,
条件也很简单:只要您的C:盘上有一个蔟的空间(约2~32K Bytes)就可以!
而且速度可以接受: 2^1000(大约10^300)种可能每秒。
对比Delphi和aimingoo的随机算法,我的算法速度上要慢很多,但我的随机数的不可预测性要高很多。
看creation-zy兄的算法,有个疑问,windows的调度线程时间片算法产生的分配差额是否是真正随机。
我对windows的内核并无了解,如果是等待硬盘或响应其他外设产生的延时确实能引起的分配差,
那么本质上和我的原理是相类似的,但我的方法产生速度要快很多。