生成大量的唯一随机数(理论上)



这是一个理论问题;作为一名计算机科学爱好者,我一直在思考这个问题,并试图理解可能(或正在)用于解决这个问题的逻辑和方法。

问题:假设您有一个数字空间,可以在其中漫游某种ID值。您需要在此空间内生成随机数。

要求:

  • 在这个数字空间内,任何数字都不应永远生成一次以上当所有数字都用完时,您的"生成"算法失败是可以的。它失败总比静默地生成重复要好,但至少它应该在执行重复操作之前耗尽所有数字。生成的数字将用作唯一的ID值
  • 生成的数字的局部集合应该尽可能随机。例如:
    • 如果一秒钟内生成100个数字,然后以每天一个的速度生成另外100个数字时,集合的"随机性"应该几乎没有可检测的差异
    • 给定一个数字,甚至一组数字,应该"尽可能不可能"对这些数字进行统计分析,以确定它们产生的时间、速度等特征
  • 对于这个思想实验,假设重叠的ID是最糟糕的情况,不能允许发生。(例如,假设一个重叠的ID可能会导致巨大的安全漏洞,导致一场诉讼,在下雨天把你的组织放在众所周知的纸箱里。)然而,可统计分析的一串数字也可能被证明是有害的——例如:如果有人能找出一个模式,他们可以猜测ID并访问他人的私人数据

我考虑过四种方法来生成这些巨大的唯一数字集:

  • 天真的方法:只需使用大的数字空间,并使用基于加密算法的数字生成器。这个想法是,在理论上,关键空间应该很大,以至于给定一个好的算法,两个值可能重叠"不太可能"。如果你能为你的ID使用足够大的数字空间,比如256位,这可能就足够了。但是,如果你必须将你的ID限制在64位,那么重叠的可能性就太大了
  • 可怕的不可扩展方法:每次生成一个数字时,都要在已经生成的数字列表中搜索它。这对小数据集来说很好,但想象一下,如果你生成了50万亿个ID,现在你每次都必须扫描这个列表,以确保你刚刚生成的ID没有被使用
  • "可伸缩"方法:与之前的想法相同,但要构建一个优化的数据库,能够对庞大的数据集进行快速查询。实际使用的一种简单方法是,例如,制作100个表——所有以数字00结尾的数字都在第一个表中,01在下一个表中等等——然后你可以很快缩小并优化你的数据库查询
  • 使用类似GUID算法的算法来生成有保证的唯一数字。这是不合适的,因为GUID确实有一个"结构",大多数生成器都会遵循它,因此它的数据不是随机的,只是唯一的

当然,在不考虑实际用例的情况下,我认为没有"最佳"选项。我更感兴趣的只是这类问题带给我的思想和逻辑实验,我很想知道是否有其他人使用过其他技术,或者至少想过其他技术来处理这样的问题。你们确实在YouTube上看到了一些至少部分类似的视频ID。当然,谷歌是一家可以在不到一秒钟的时间内为你"搜索互联网"的公司,所以他们的方法可能不适合"其他人"。

这是一个理论答案。

由于在这个数字空间内,任何数字都不应该生成一次以上,永远,,因此该算法有效地生成了数字空间的一些排列。这暗示它应该选择某个排列,并按顺序生成它。

如果空间大小是N,则存在N!可能的排列。给定排列索引,生成它非常容易,一次生成一个元素。随机选择一个排列,并生成它。

选择的排列可能是一个身份(产生ID的0, 1, 2, ...序列)。它看起来并不是很随机,但攻击者仍然无法预测。

我想你事先知道你想要多少随机数。

我建议使用带有Bloom过滤器的可扩展方法来优化查找。请注意,Bloom过滤器不存储实际值,并且有可能认为它看到了一个没有看到的值。在这种情况下,这两个数字都不是一个重大的损害,而且几乎不可能预测哪些数字会被诬告为被看到了,而这些数字却没有被看到。

你可以调整过滤器的大小来权衡内存和你需要的随机数。将其调整为最终假阳性率为10%,这将使生成数字的速度变慢,但所需的内存比假阳性率1%要少。对于非常大的数据集,Bloom过滤器可以很容易地并行化,以便在多台机器上运行。对于想要快速生成的非常大的数据集,您甚至可以使用两级哈希,其中顶级哈希确定将检查哪个哈希函数子集,第二级哈希针对保存的数据运行。这种设计允许您在机器之间并行化这两种检查,并首先进行负载平衡。这将允许疯狂的吞吐量。

一个重要的缺点是,你必须提前决定最终的随机数池有多大。因为一旦过滤器被太多数据堵塞,你就无法轻易调整其大小。

一个众所周知的算法是在数字空间中使用一些值序列——例如,对于二次方的范围,可以使用线性同余序列——然后对值进行加密。由于加密函数必须是同构的——否则就不可能精确解密——所以这种情况不能重复,直到基本序列结束。

当然,你需要保护你的加密密钥,以及你在底层序列中使用的任何参数,而维护这些秘密的困难是一个问题。但是输出值看起来肯定是随机的。您必须在可能的安全问题与实际问题域的需求之间取得平衡。

O(1)中的k代可以改进一些循环生成器。如果你选择其中一个,你可以通过给每个并行进程一个合适的种子来并行生成"随机"数。如果一个进程运行了它的所有k值,它只会向主服务器请求一个新的范围分配,或者如果它可以访问持久存储,则自己执行。

如果不必生成特定长度的数字,则可以生成如下唯一随机数:

  • 将数字空间划分为唯一部分和随机的部分
  • 唯一部分只是一个从0开始按顺序分配的数字。当最后一个数字已经生成时,唯一数字生成失败
  • 随机部分是使用加密RNG生成的随机数。由于唯一部分已经确保了唯一性,因此不必担心生成重复随机部分的风险

为了这个答案的目的,唯一部分和随机部分的大小是任意的。对于大多数实际目的,唯一部分应至少64位长,而随机部分应至少128位长。

使用可伸缩的方法,除了占用内存之外,还会减慢提取速度。然而,假设具有N个数的空间,如果它由一维阵列表示,则为了执行对多个这样的空间的提取,我将不得不平均执行(N/2)次迭代;但是,如果这个空间是正方形矩阵,例如,对于我提取的每个数字,我将平均具有(Sqrt(N)/2+Sqrt(N)/2)次迭代;它是行搜索和列搜索:更少的迭代。对于三维矩阵,迭代次数甚至更小:(N^(1/3)/2+N^(3/3)/2+N+N^(1/3/2),依此类推,增加与数字空间相关的结构的维数,总迭代次数总是更小。显然,对于第一个维度之上的每个维度,我必须考虑向量空间的较小维度的可用元素的数量。

例如,我报告了这个单元,它是在Delphi下用汇编程序(保护模式)编写的。要提取2^27个数字,旧的ACER TravelMate 4220笔记本电脑上的GetRndGRNum()功能需要37秒:

unit x;
interface
Const GRMinCellValue=-1 ShL 31;
GRMaxDeltaNum=(1 ShL 27)-1;
Type   {2} TGRData0=Record
{1}  GRNumArrAmount0,
{1}  GRNumArr0:Byte;
End;
{16} TGRArr1=Array [0..7] Of TGRData0;
{17} TGRData1=Record
{1}  GRNumArrAmount1:Byte;
{16}  GRNumArr1:TGRArr1;
End;
{136} TGRArr2=Array [0..7] Of TGRData1;
{137} TGRData2=Record
{1}  GRNumArrAmount2:Byte;
{136}  GRNumArr2:TGRArr2;
End;
{1096} TGRArr3=Array [0..7] Of TGRData2;
{1097} TGRData3=Record
{1}  GRNumArrAmount3:Byte;
{1096}  GRNumArr3:TGRArr3;
End;
{8776} TGRArr4=Array [0..7] Of TGRData3;
{8777} TGRData4=Record
{1}  GRNumArrAmount4:Byte;
{8776}  GRNumArr4:TGRArr4;
End;
{70216} TGRArr5=Array [0..7] Of TGRData4;
{70217} TGRData5=Record
{1}  GRNumArrAmount5:Byte;
{70216}  GRNumArr5:TGRArr5;
End;
{561736} TGRArr6=Array [0..7] Of TGRData5;
{561737} TGRData6=Record
{1}  GRNumArrAmount6:Byte;
{561736}  GRNumArr6:TGRArr6;
End;
{4493896} TGRArr7=Array [0..7] Of TGRData6;
{4493897} TGRData7=Record
{1}  GRNumArrAmount7:Byte;
{4493896}  GRNumArr7:TGRArr7;
End;
{35951176} TGRArr8=Array [0..7] Of TGRData7;
{35951185} TGRData8=Record
{1}  GRNumArrAmount8:Byte;
{4}  GRNumMin8,
{4}  GRNumMax8:Integer;
{35951176}  GRNumArr8:TGRArr8;
End;
TGRData8Ptr=^TGRData8;
TRndXSeed=Array[0..3] Of Cardinal;
Var RndXSeed:TRndXSeed=(123456789, (* X: Seed *)
362436000, (* Y: Must be <>0 *)
521288629, (* Z: Must be <>0 *)
7654321);  (* C: Must be <>0 *)
Function  GetPtr         (PValue:Integer):Pointer;
{Trasforma il valore PValue IN un PUNTATORE POINTER.
NOTE: È scritta IN ASSEMBLER.
Non chiama alcuna Sub-ROUTINE.
Testata con successo}
Function  GetPtrValue    (P:Pointer):Integer;
{Converte il PUNTATORE P IN un valore.
NOTE: È scritta IN ASSEMBLER.
Non chiama alcuna Sub-ROUTINE.
Testata con successo}
Procedure MyFillChar     (M:Pointer;S,V:Cardinal);
{ Analoga alla System.FillChar(), ma più veloce.
NOTE: è scritta interam. IN ASSEMBLER.
Non effettua alcun salto (CALL, Jmp o salto condizionato),
ed è molto veloce.
Per impostare a 0 la VAR. A
(di tipo BYTE, WORD, SMALLINT o INTEGER):
MyFillChar(@A,SIZEOF(A),0);
Per impostare a 0 la VAR. A
(di tipo T=RECORD):
MyFillChar(@A,SIZEOF(A),0) }
Procedure ReSetGRConfig  (GRConfig:TGRData8Ptr;
Min,Max:Integer);
(* (Re)inizializza l' estrazione di numeri casuali,
compresi tra Min e Max, con GetRndGRNum(GRConfig).
I valori ammessi per Min e Max
vanno da -2147483647 a +2147483647,
ma il numero massimo di numeri
che si possono estrarre è 134217728.
Se Min e Max costituiscono un range troppo ampio,
sarà ristretto il suddetto range e
sarà alzato il valore minimo.
è possibile specificare Min>Max *)
Function  GetRndGRNum    (GRConfig:TGRData8Ptr):Integer;
(* Estrae un numero casuale nel range Min-Max sempre
diverso da quelli estratti precedentemente.
Ritorna GRMinCellValue (-2147483648)
se non ci sono altri numeri da estrarre.
Inizializzare l' estrazione con ReSetGRConfig(GRConfig,Min,Max) *)
implementation
Uses Math;
Function  GetPtr(PValue:Integer):Pointer; Assembler;
Asm
Mov   EAX,PValue
End;
Function  GetPtrValue(P:Pointer):Integer; Assembler;
Asm
Mov   EAX,P
End;
Procedure MyFillChar(M:Pointer;S,V:Cardinal); Assembler;
Asm
Push  EDI
Mov   EDI,M (* EAX *)
Mov   EAX,V (* ECX *)
Mov   ECX,S (* EDX *)
ClD
Mov   AH,AL
Mov   DX,AX
ShL   EAX,16
Mov   AX,DX
Mov   EDX,ECX
ShR   ECX,2
Rep   StoSD
SetB  CL
Rep   StoSW
Test  DL,1
SetNE CL
Rep   StoSB
Pop   EDI
End;
Procedure ReSetGRConfig(GRConfig:TGRData8Ptr;
Min,Max:Integer);
Var I0,I1,I2,I3,I4,I5,I6,I7,I8:Byte;
Diff,Amount,Filled:Integer;
Begin
Inc(Min,Integer(Min=GRMinCellValue));
Diff:=Max-Min+Integer(Max=GRMinCellValue);
Dec(Diff,Integer(Abs(Diff)>GRMaxDeltaNum)*
(Diff-Sign(Diff)*GRMaxDeltaNum));
Filled:=0;
If Assigned(GRConfig) Then
With GRConfig^ Do
Begin
GRNumMin8:=Max-Diff*Integer(Diff>=0);
Diff:=Abs(Diff);
GRNumMax8:=GRNumMin8+Diff;
Amount:=Diff+1;
I8:=0;
Inc(Filled,9);
While (I8<8) And (Amount<>0) Do
With GRNumArr8[I8] Do
Begin
I7:=0;
Inc(Filled);
While (I7<8) And (Amount<>0) Do
With GRNumArr7[I7] Do
Begin
I6:=0;
Inc(Filled);
While (I6<8) And (Amount<>0) Do
With GRNumArr6[I6] Do
Begin
I5:=0;
Inc(Filled);
While (I5<8) And (Amount<>0) Do
With GRNumArr5[I5] Do
Begin
I4:=0;
Inc(Filled);
While (I4<8) And (Amount<>0) Do
With GRNumArr4[I4] Do
Begin
I3:=0;
Inc(Filled);
While (I3<8) And (Amount<>0) Do
With GRNumArr3[I3] Do
Begin
I2:=0;
Inc(Filled);
While (I2<8) And (Amount<>0) Do
With GRNumArr2[I2] Do
Begin
I1:=0;
Inc(Filled);
While (I1<8) And (Amount<>0) Do
With GRNumArr1[I1] Do
Begin
I0:=Integer((8+Amount-Abs(8-Amount)) ShR 1);
GRNumArrAmount0:=I0;
GRNumArr0:=0;
Dec(Amount,I0);
Inc(Filled,2);
Inc(I1);
End;
GRNumArrAmount1:=I1;
Inc(I2);
End;
GRNumArrAmount2:=I2;
Inc(I3);
End;
GRNumArrAmount3:=I3;
Inc(I4);
End;
GRNumArrAmount4:=I4;
Inc(I5);
End;
GRNumArrAmount5:=I5;
Inc(I6);
End;
GRNumArrAmount6:=I6;
Inc(I7);
End;
GRNumArrAmount7:=I7;
Inc(I8);
End;
GRNumArrAmount8:=I8;
(* 108'000'000= $66ff300
I6=7, I5=7, I4=16, I3=16, I2=3, I1=16, I0=16 = $7700300 *)
MyFillChar(GetPtr(GetPtrValue(GRConfig)+Filled),
SizeOf(GRConfig^)-Filled,0);
End;
End;
Function GetRndGRNum(GRConfig:TGRData8Ptr):Integer; Assembler;
Var Am7P,
Am6P,
Am5P,
Am4P,
Am3P,
Am2P,
Am1P,
GRData8Ptr:Integer;
RndN0,
RndN1,
RndN2,
RndN3,
RndN4,
RndN5,
RndN6,
RndN7,
RndN8,
RC7,
RC6,
RC5,
RC4,
RC3,
RC2,
RC1,
RC0:Byte;
Asm
Push  EDI          { Salva il registro EDI sullo STACK }
(* ---------------------------------------- *)
Mov   EDI,GRConfig     { Carica         GRConfig (EAX) nel reg. EDI }
Mov   EAX,GRMinCellValue   { Carica il reg. di output con GRMinCellValue }
Or    EDI,EDI          { Se GRConfig=Nil ... }
JE    @@00         { ... Ha finito, esce }
Cmp   Byte Ptr [EDI],0     { Se GRConfig^.GRNumArrAmount6=0 ... }
JE    @@00         { ... Ha finito, esce }
Mov   GRData8Ptr,EDI       { Salva GRConfig su GRData8Ptr }
(* ======================================== *)
LEA   EDI,RndXSeed     { Carica in EDI l' offs. di MyStrUt.MyRndXSeed }
(* ---------------------------------------- *)
(* - Generaz. di un num. casuale a 32 Bit - *)
(* ---------------------------------------- *)
Mov   EAX,[EDI]
Mov   EDX,69069
Mul   EDX
Add   EAX,12345
Mov   [EDI],EAX    // RndXSeed[0]:=69069*RndXSeed[0]+12345;
Mov   EAX,[EDI+4]
ShL   EAX,13
XOr   [EDI+4],EAX  // RndXSeed[1]:=RndXSeed[1] XOr (RndXSeed[1] ShL 13);
Mov   EAX,[EDI+4]
ShR   EAX,17
XOr   [EDI+4],EAX  // RndXSeed[1]:=RndXSeed[1] XOr (RndXSeed[1] ShR 17);
Mov   EAX,[EDI+4]
ShL   EAX,5
XOr   [EDI+4],EAX  // RndXSeed[1]:=RndXSeed[1] XOr (RndXSeed[1] ShL 5);
Mov   EAX,[EDI+8]
Mov   EDX,698769069
Mul   EDX
Add   EAX,[EDI+12]
AdC   EDX,0        // EDX:EAX:=698769069*RndXSeed[2]+RndXSeed[3];
Mov   [EDI+12],EDX // RndXSeed[3]:=T ShR 32;
Cmp   EAX,[EDI+8]
Mov   EAX,0
SetE  AL
Or    EDX,EDX
SetE  DL
And   AL,DL       // EAX:=Cardinal(RndXSeed[2]=T)
Add   EAX,[EDI]
Add   EAX,[EDI+4] // RndX:=RndXSeed[0]+RndXSeed[1]+Cardinal(RndXSeed[2]=T);
(* ---------------------------------------- *)
(* - Fine generazione numero casuale ------ *)
(* ---------------------------------------- *)
Mov   DL,AL            { Carica i 7 Bit meno significat ... }
And   DL,127           { ... del numero casuale generato ... }
Mov   RndN0,DL         { ... in RndN0 }
ShR   EAX,7
Mov   DL,AL            { Carica i 7 Bit meno significat ... }
And   DL,127           { ... del numero casuale generato ... }
Mov   RndN1,DL         { ... in RndN1 }
ShR   EAX,7
Mov   DL,AL            { Carica i 7 Bit meno significat ... }
And   DL,127           { ... del numero casuale generato ... }
Mov   RndN2,DL         { ... in RndN2 }
ShR   EAX,7
Mov   DL,AL            { Carica i 7 Bit meno significat ... }
And   DL,127           { ... del numero casuale generato ... }
Mov   RndN3,DL         { ... in RndN3 }
ShR   EAX,7
Mov   RndN4,AL
(* ---------------------------------------- *)
(* - Generaz. di un num. casuale a 32 Bit - *)
(* ---------------------------------------- *)
Mov   EAX,[EDI]
Mov   EDX,69069
Mul   EDX
Add   EAX,12345
Mov   [EDI],EAX
Mov   EAX,[EDI+4]
ShL   EAX,13
XOr   [EDI+4],EAX
Mov   EAX,[EDI+4]
ShR   EAX,17
XOr   [EDI+4],EAX
Mov   EAX,[EDI+4]
ShL   EAX,5
XOr   [EDI+4],EAX
Mov   EAX,[EDI+8]
Mov   EDX,698769069
Mul   EDX
Add   EAX,[EDI+12]
AdC   EDX,0
Mov   [EDI+12],EDX
Cmp   EAX,[EDI+8]
Mov   EAX,0
SetE  AL
Or    EDX,EDX
SetE  DL
And   AL,DL
Add   EAX,[EDI]
Add   EAX,[EDI+4]
(* ---------------------------------------- *)
(* - Fine generazione numero casuale ------ *)
(* ---------------------------------------- *)
Mov   DL,AL
And   DL,7
ShL   DL,4
Or    RndN4,DL
ShR   EAX,3
Mov   DL,AL            { Carica i 7 Bit meno significat ... }
And   DL,127           { ... del numero casuale generato ... }
Mov   RndN5,DL         { ... in RndN5 }
ShR   EAX,7
Mov   DL,AL            { Carica i 7 Bit meno significat ... }
And   DL,127           { ... del numero casuale generato ... }
Mov   RndN6,DL         { ... in RndN6 }
ShR   EAX,7
Mov   DL,AL            { Carica i 7 Bit meno significat ... }
And   DL,127           { ... del numero casuale generato ... }
Mov   RndN7,DL         { ... in RndN7 }
ShR   EAX,7
And   AL,127
Mov   RndN8,AL
Mov   EDI,GRData8Ptr       { Carica GRConfig in EDI }
(* ======================================== *)
(* = Ricerca del record TGRData7  ========= *)
(* ======================================== *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr8[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData8.GRNumArr8-TYPE(TGRData7) { EDI <- OFFSET ... }
{ ... GRConfig^.GRNumArr8-SizeOf(TGRData7) }
(* ---------------------------------------- *)
@@L8:Add   EDI,TYPE(TGRData7)   { EDI += SizeOf(TGRData7) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr8[CL].GRNumArrAmount7<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L8         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   Am7P,EDI         { Salva OFFS(GRNumArr8[CL].GRNumArrAmount7) ...}
{  ... (EDI) in Am7P }
Mov   RC7,CL           { Salva RC (CL) in RC7 }
(* ======================================== *)
(* = Ricerca del record TGRData6  ========= *)
(* ======================================== *)
Mov   AL,RndN7
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr7[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData7.GRNumArr7-TYPE(TGRData6) { EDI <- OFFSET ... }
{ ... GRConfig^.GRNumArr7-SizeOf(TGRData6) }
(* ---------------------------------------- *)
@@L7:Add   EDI,TYPE(TGRData6)   { EDI += SizeOf(TGRData6) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr7[CL].GRNumArrAmount6<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L7         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   Am6P,EDI         { Salva OFFS(GRNumArr7[CL].GRNumArrAmount6) ...}
{  ... (EDI) in Am6P }
Mov   RC6,CL           { Salva RC (CL) in RC6 }
(* ======================================== *)
(* = Ricerca del record TGRData5  ========= *)
(* ======================================== *)
Mov   AL,RndN6
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr6[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData6.GRNumArr6-TYPE(TGRData5) { EDI <- OFFSET ... }
{ ... GRConfig^.GRNumArr6-SizeOf(TGRData5) }
(* ---------------------------------------- *)
@@L6:Add   EDI,TYPE(TGRData5)   { EDI += SizeOf(TGRData5) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr6[CL].GRNumArrAmount5<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L6         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   Am5P,EDI         { Salva OFFS(GRNumArr6[CL].GRNumArrAmount5) ...}
{  ... (EDI) in Am5P }
Mov   RC5,CL           { Salva RC (CL) in RC5 }
(* ======================================== *)
(* = Ricerca del record TGRData4  ========= *)
(* ======================================== *)
Mov   AL,RndN5
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr5[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData5.GRNumArr5-TYPE(TGRData4) { EDI <- OFFSET ... }
{ ... TGRData5.GRNumArr5-SizeOf(TGRData4) }
(* ---------------------------------------- *)
@@L5:Add   EDI,TYPE(TGRData4)   { EDI += SizeOf(TGRData4) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr5[CL].GRNumArrAmount4<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L5         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   Am4P,EDI         { Salva OFFS(GRNumArr5[CL].GRNumArrAmount4) ...}
{  ... (EDI) in Am4P }
Mov   RC4,CL           { Salva RC (CL) in RC4 }
(* ======================================== *)
(* = Ricerca del record TGRData3  ========= *)
(* ======================================== *)
Mov   AL,RndN4
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr4[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData4.GRNumArr4-TYPE(TGRData3) { EDI <- OFFSET ... }
{ ... TGRData4.GRNumArr4-SizeOf(TGRData3) }
(* ---------------------------------------- *)
@@L4:Add   EDI,TYPE(TGRData3)   { EDI += SizeOf(TGRData3) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr4[CL].GRNumArrAmount3<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L4         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   Am3P,EDI         { Salva OFFS(GRNumArr4[CL].GRNumArrAmount3) ...}
{  ... (EDI) in Am3P }
Mov   RC3,CL           { Salva RC (CL) in RC3 }
(* ======================================== *)
(* = Ricerca del record TGRData2  ========= *)
(* ======================================== *)
Mov   AL,RndN3
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr3[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData3.GRNumArr3-TYPE(TGRData2) { EDI <- OFFSET ... }
{ ... TGRData3.GRNumArr3-SizeOf(TGRData2) }
(* ---------------------------------------- *)
@@L3:Add   EDI,TYPE(TGRData2)   { EDI += SizeOf(TGRData2) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr3[CL].GRNumArrAmount2<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L3         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   Am2P,EDI         { Salva OFFS(GRNumArr3[CL].GRNumArrAmount2) ...}
{  ... (EDI) in Am2P }
Mov   RC2,CL           { Salva RC (CL) in RC2 }
(* ======================================== *)
(* = Ricerca del record TGRData1  ========= *)
(* ======================================== *)
Mov   AL,RndN2
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr2[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData2.GRNumArr2-TYPE(TGRData1) { EDI <- OFFSET ... }
{ ... TGRData2.GRNumArr2-SizeOf(TGRData1) }
(* ---------------------------------------- *)
@@L2:Add   EDI,TYPE(TGRData1)   { EDI += SizeOf(TGRData1) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr2[CL].GRNumArrAmount1<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L2         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   Am1P,EDI         { Salva OFFS(GRNumArr2[CL].GRNumArrAmount1) ...}
{  ... (EDI) in Am1P }
Mov   RC1,CL           { Salva RC (CL) in RC1 }
(* ======================================== *)
(* = Ricerca del record TGRData0  ========= *)
(* ======================================== *)
Mov   AL,RndN1
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{EDI: GRNumArr1[CL].
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Add   EDI,OFFSET TGRData1.GRNumArr1-TYPE(TGRData0) { EDI <- OFFSET ... }
{ ... TGRData1.GRNumArr1-SizeOf(TGRData0) }
(* ---------------------------------------- *)
@@L1:Add   EDI,TYPE(TGRData0)   { EDI += SizeOf(TGRData0) }
Inc   CL           { RC += 1 }
Cmp   Byte Ptr [EDI],1     { Se GRNumArr1[CL].GRNumArrAmount0<>0, ... }
CmC                { ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L1         { Se VC<>0, ripete il ciclo }
(* ---------------------------------------- *)
Mov   RC0,CL           { Salva RC (CL) in RC0 }
(* ======================================== *)
(* = Ricerca del Bit selezionato  ========= *)
(* ======================================== *)
Mov   AL,RndN0
(* ---------------------------------------- *)
Mov   AH,[EDI]         { AH <- GRConfig^.GRNumArrAmount6 (amount) }
{in:127=out:amount-1
out<-in*amount/128}
Mul   AH           { AX <- in*amount }
ShR   AX,7         { AL <- in*amount/128 }
Inc   AL           { AL <- in*amount/128+1 }
(* ---------------------------------------- *)
{ DX: GRNumArr0.
AL: VC.
CL: RC.
CH: Temp=0}
Mov   CX,255           { RC <- -1; Temp <- 0}
Mov   DL,[EDI+OFFSET TGRData0.GRNumArr0] { DL <- TGRData0.GRNumArr0 }
(* ---------------------------------------- *)
@@L0:Inc   CL           { RC += 1 }
ShR   DL,1         { GRNumArr0>>1 }
CmC                { Se FCarry=0 ... }
SbB   AL,CH            { ... VC -= 1 }
JNE   @@L0         { Se VC<>0, ripete il ciclo }
(* ======================================== *)
Mov   DL,1         { ... }
ShL   DL,CL            { ... DL <- 1<<RC }
Or    [EDI+OFFSET TGRData0.GRNumArr0],DL { Marca il num. come già estratto}
(* ---------------------------------------- *)
Mov   EDX,GRData8Ptr       { Carica GRConfig in EDX }
Dec   Byte Ptr [EDI]       { TGRData0.GRNumArrAmount0 -= 1 }
JNE   @@01         { Se TGRData0.GRNumArrAmount0<>0, salta }
Mov   EDI,Am1P         { Carica OFFS(TGRData1.GRNumArrAmount1) in EDI }
Dec   Byte Ptr [EDI]       { TGRData1.GRNumArrAmount1 -= 1 }
JNE   @@01         { Se TGRData1.GRNumArrAmount1<>0, salta }
Mov   EDI,Am2P         { Carica OFFS(TGRData2.GRNumArrAmount2) in EDI }
Dec   Byte Ptr [EDI]       { TGRData2.GRNumArrAmount2 -= 1 }
JNE   @@01         { Se TGRData2.GRNumArrAmount2<>0, salta }
Mov   EDI,Am3P         { Carica OFFS(TGRData3.GRNumArrAmount3) in EDI }
Dec   Byte Ptr [EDI]       { TGRData3.GRNumArrAmount3 -= 1 }
JNE   @@01         { Se TGRData3.GRNumArrAmount3<>0, salta }
Mov   EDI,Am4P         { Carica OFFS(TGRData4.GRNumArrAmount4) in EDI }
Dec   Byte Ptr [EDI]       { TGRData4.GRNumArrAmount4 -= 1 }
JNE   @@01         { Se TGRData4.GRNumArrAmount4<>0, salta }
Mov   EDI,Am5P         { Carica OFFS(TGRData5.GRNumArrAmount5) in EDI }
Dec   Byte Ptr [EDI]       { TGRData5.GRNumArrAmount5 -= 1 }
JNE   @@01         { Se TGRData5.GRNumArrAmount5<>0, salta }
Mov   EDI,Am6P         { Carica OFFS(TGRData6.GRNumArrAmount6) in EDI }
Dec   Byte Ptr [EDI]       { TGRData6.GRNumArrAmount6 -= 1 }
JNE   @@01         { Se TGRData6.GRNumArrAmount6<>0, salta }
Mov   EDI,Am7P         { Carica OFFS(TGRData7.GRNumArrAmount7) in EDI }
Dec   Byte Ptr [EDI]       { TGRData7.GRNumArrAmount7 -= 1 }
JNE   @@01         { Se TGRData7.GRNumArrAmount7<>0, salta }
Dec   Byte Ptr [EDX]       { GRConfig^.GRNumArrAmount8 -= 1 }
(* ---------------------------------------- *)
@@01:MovZX EAX,RC7          { EAX <- pos. ("Real Count.") r. TGRData7 trov.}
ShL   Al,3         { EAX <<= 3 }
Or    AL,RC6           { EAX |= pos. ("Real Count.") r. TGRData6 trov.}
ShL   AX,3         { EAX <<= 3 }
Or    AL,RC5           { EAX |= pos. ("Real Count.") r. TGRData5 trov.}
ShL   AX,3         { EAX <<= 3 }
Or    AL,RC4           { EAX |= pos. ("Real Count.") r. TGRData4 trov.}
ShL   AX,3         { EAX <<= 3 }
Or    AL,RC3           { EAX |= pos. ("Real Count.") r. TGRData3 trov.}
ShL   EAX,3            { EAX <<= 3 }
Or    AL,RC2           { EAX |= pos. ("Real Count.") r. TGRData2 trov.}
ShL   EAX,3            { EAX <<= 3 }
Or    AL,RC1           { EAX |= pos. ("Real Count.") r. TGRData1 trov.}
ShL   EAX,3            { EAX <<= 3 }
Or    AL,RC0           { EAX |= pos. ("Real Count.") r. TGRData0 trov.}
ShL   EAX,3            { EAX <<= 3 }
Or    AL,CL            { EAX |= pos. Bit selezionato }
(* ---------------------------------------- *)
Add   EAX,[EDX+OFFSET TGRData8.GRNumMin8] { Somma GRConfig^.GRNumMin8 ... }
{ ... al numero cas. gen. }
(* ======================================== *)
@@00:Pop   EDI          { Ripristina il registro EDI dallo STACK }
End;
end.

相关内容

最新更新