这是一个理论问题;作为一名计算机科学爱好者,我一直在思考这个问题,并试图理解可能(或正在)用于解决这个问题的逻辑和方法。
问题:假设您有一个数字空间,可以在其中漫游某种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.