我有这样的结构
const
MaxSignalRecords=255;
type
TSignalRecord=record
signal1 : integer;
signal2 : integer;
signal3 : integer;
signal4 : integer;
signal5 : integer;
signal6 : integer;
bsignal1 : Boolean;
bsignal2 : Boolean;
bsignal3 : Boolean;
bsignal4 : Boolean;
bsignal5 : Boolean;
bsignal6 : Boolean;
end;
TListSignals = Array[0..MaxSignalRecords-1] of TSignalRecord;
以及生成随机样本数据的程序
Procedure FillRandomListSignals(var ListSignals:TListSignals);
var
i :Integer;
begin
for i := 0 to MaxSignalRecords - 1 do
with ListSignals[i] do
begin
signal1 :=Random(MaxInt);
signal2 :=Random(MaxInt);
signal3 :=Random(MaxInt);
signal4 :=Random(MaxInt);
signal5 :=Random(MaxInt);
signal6 :=Random(MaxInt);
bsignal1 :=Boolean(Random(2));
bsignal2 :=Boolean(Random(2));
bsignal3 :=Boolean(Random(2));
bsignal4 :=Boolean(Random(2));
bsignal5 :=Boolean(Random(2));
bsignal6 :=Boolean(Random(2));
end;
end;
如何改善FillRandomListSignals
程序的性能?
编辑:此结构用于制作数千(可能是数百万)的计算
for i:=1 to 1000000 do
begin
CleartheList(MyList);
FillRandomListSignals(MyList);
DotheMath(MyList);
DotheChart(MyList);
end;
答案 0 :(得分:6)
当您生成随机数据时,速度不是您唯一关心的问题,您实际上希望数据是随机的,您不希望您的实验受到重复数据或其他伪随机生成器问题的困扰。如果您更关心速度和随机性,您可以随时使用function like this one,这将是超快的! </joke>
。
Here's a post by Barry Kelly on Stack Overflow描述了内置随机数生成器可能出现的问题。不打算在这里引用它,自己去读它,这是好东西。
为了得出结论,当我需要一个足够好的PRNG来生成大量的随机数据时,我使用了一个Mersenne Twister (wikipedia link),由Delphi的PRNG播种。
来自维基百科的关于Mersene Twister的报道:
对于许多应用来说,梅森捻线机很快成为首选的伪随机数发生器。 Mersenne Twister的设计考虑了蒙特卡罗模拟和其他统计模拟。研究人员主要想要高质量的数字,但也从速度和便携性中受益。
为了打破我关于每个帖子的链接数量的所有记录,我使用了this Delphi implementation。
我最后的想法:除非你对数学非常好,否则要远离自制的PRNG实施。就像哈希函数一样,很容易出错,而且很难分析。
使用以下代码进行了一些计时。使用Mersenne Twister生成10,000,000条记录需要1480毫秒。使用Delphi的内置随机数生成器的相同代码仅花费250毫秒,对于相同的10M记录。有些东西告诉我,这不是需要优化的随机生成器,而是代码中的其他内容。
procedure TForm1.Button1Click(Sender: TObject);
var InitArray:array[0..99] of LongInt;
i, N:Integer;
TSR: TSignalRecord;
CStart, CStop: Int64;
begin
Randomize;
for i:=0 to 99 do InitArray[i] := Random($effffff);
InitMTbyArray(InitArray, Length(InitArray));
CStart := GetTickCount;
for i:=1 to 10000000 do
begin
TSR.signal1 := IRanMT;
TSR.signal2 := IRanMT;
TSR.signal3 := IRanMT;
TSR.signal4 := IRanMT;
TSR.signal5 := IRanMT;
TSR.signal6 := IRanMT;
N := IRanMT;
TSR.bsignal1 := (N and 1) <> 0;
TSR.bsignal2 := (N and 2) <> 0;
TSR.bsignal3 := (N and 4) <> 0;
TSR.bsignal4 := (N and 8) <> 0;
TSR.bsignal5 := (N and 16) <> 0;
TSR.bsignal6 := (N and 32) <> 0;
end;
CStop := GetTickCount;
Caption := IntToStr(CStop - CStart);
end;
答案 1 :(得分:5)
您可能不会在每个字段中使用内置的Random()函数,但在全局范围内使用流水线优化的访问权限,使用随机预生成的数组:
var
crc32tab: array[byte] of cardinal;
procedure InitCrc32Tab;
var i,n: integer;
crc: cardinal;
begin // this code size is only 105 bytes, generating 1 KB table content
for i := 0 to 255 do begin
crc := i;
for n := 1 to 8 do
if (crc and 1)<>0 then
// $edb88320 from polynomial p=(0,1,2,4,5,7,8,10,11,12,16,22,23,26)
crc := (crc shr 1) xor $edb88320 else
crc := crc shr 1;
crc32tab[i] := crc;
end;
end;
type NativeUInt = cardinal; // before Delphi 2007
procedure RandomData(P: PAnsiChar; Len: integer);
var i: integer;
seed0, seed1, seed2, seed3: cardinal;
begin
if Len>=16 then
begin
seed0 := Random(maxInt);
seed1 := seed0*$8088405;
seed2 := seed1*$8088405;
seed3 := seed2*$8088405;
for i := 1 to Len shr 4 do begin // pipelined loop for 16 bytes at once
PCardinalArray(P)[0] := crc32tab[byte(seed0)] xor seed0;
seed0 := seed0 xor NativeUInt(P);
PCardinalArray(P)[1] := crc32tab[byte(seed1)] xor seed1;
seed1 := seed1 xor NativeUInt(P);
PCardinalArray(P)[2] := crc32tab[byte(seed2)] xor seed2;
seed2 := seed3 xor NativeUInt(P);
PCardinalArray(P)[3] := crc32tab[byte(seed3)] xor seed3;
seed3 := seed3 xor NativeUInt(P);
inc(P,16);
end;
end;
for i := 1 to Len and 15 do begin
P^ := PAnsiChar(@crc32tab)[NativeUInt(P) and 1023];
inc(P);
end;
end;
可以像这样调用上面的函数(你必须在程序中调用一次InitCrc32Tab过程):
procedure FillRandomListSignals(var ListSignals: TListSignals);
begin
RandomData(@ListSignals,sizeof(ListSignals));
end;
它比使用Random()函数更快,因为此函数使用两个整数乘法,并且根本不进行流水线操作。上面的循环将同时处理16个字节,没有乘法,每个CPU时钟有多个操作,因为我优化它以使用尽可能多的CPU流水线。我们也许可以玩种子?变量,或使用一些优化的asm,但你已经有了这个想法。
<强> Postscriptum:强>
由于您使用随机数据填充列表,因此无需先清除它。只是浪费时间。
答案 2 :(得分:0)
如果你只有256条记录,我无法看到这段代码如何花费超过几毫秒的时间,所以为什么要这么麻烦。牢记阿姆达尔定律: - )