代码之家  ›  专栏  ›  技术社区  ›  fdmillion

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

  •  0
  • fdmillion  · 技术社区  · 7 年前

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

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

    • 在这个数字空间内,任何数字都不应该被多次、永久地生成。 当所有的数字都用完时,你的“生成”算法失败也没关系。与其默默地生成副本,不如让它失败,但至少它应该在执行副本之前耗尽所有数字。生成的数字将用作唯一的ID值。
    • 生成的一组局部数字应尽可能随机。例如:
      • 如果在一秒钟内生成100个数字,然后以每天一个的速度生成另外100个数字,那么在集合的“随机性”中应该几乎没有可检测的差异。
    • 对于这个思维实验,假设一个重叠的ID是最坏的情况,并且不能被允许发生。(例如,假设一个重叠的ID可能会导致一个巨大的安全漏洞,从而导致一场诉讼,在下雨天将您的组织置于众所周知的硬纸盒中。)然而,可以进行统计分析的数字串也可能被证明是有害的——例如:如果有人能找出一种模式,他们就可以猜测ID并访问其他人的私人数据。

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

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

    当然,如果不考虑实际的用例,我知道没有“最佳”选项。我更感兴趣的是这类问题带给我的思维和逻辑实验,我想知道是否有人使用过其他技术,或者至少想到过其他技术来解决这样的问题。你确实在YouTube上看到了一些类似的东西,比如视频ID。当然,谷歌是一家可以在不到一秒钟内为你“搜索互联网”的公司,所以他们的方法可能不适合“其他人”。

    4 回复  |  直到 7 年前
        1
  •  2
  •   user58697    7 年前

    这是一个理论上的答案。

    自从 在这个数字空间内,任何数字都不应该被多次、永久地生成 ,该算法有效地生成 一些 数空间的排列。这暗示它应该选择某个排列,并按顺序生成它。

    如果空间大小是 N ,有 N! 可能的排列。考虑到排列索引,很容易 generate it ,一次一个元素。随机选择一个排列,并生成它。

    一个选定的排列可能是一个身份(产生 0, 1, 2, ... ID序列)。事实并非如此 非常随机,但攻击者仍然无法预测。

        2
  •  1
  •   btilly    7 年前

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

    我建议使用可扩展的方法 Bloom filter 用于优化查找。请注意,Bloom过滤器不存储实际值,并且有可能认为它已经看到了一个它没有看到的值。在这种情况下,这两者都不是一个重大的危害,而且几乎不可能预测哪些数字在没有看到的情况下会被错误地指责为看到了。

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

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

        3
  •  1
  •   rici    7 年前

    一个著名的算法是使用数字空间中的一些值序列——例如,对于二次幂的范围,可以使用线性同余序列——然后加密这些值。由于加密函数必须是同构函数——否则就不可能进行准确的解密——因此,在基本序列结束之前,不能重复此操作。

    当然,你会想要保护你的加密密钥,以及你在底层序列中使用的任何参数,而维护这些秘密的难度是一个问题。但是输出值看起来肯定是随机的。你必须平衡可能的安全问题和你真正的问题领域的需求。

    一些循环发电机可以通过 k O(1)中的世代。如果你选择其中一个,你可以通过给每个并行进程分配一个合适的种子来并行“随机”数的生成。如果一个过程贯穿所有 K 在其值中,它只要求主服务器分配一个新的范围,或者如果可以访问持久性存储,它自己进行分配。

        4
  •  0
  •   Peter O. Manuel Pinto    6 年前

    如果不必生成特定长度的数字,则可以生成 unique random numbers 详情如下:

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

    在这个答案中,唯一部分和随机部分的大小是任意的。在大多数实际应用中,唯一部分的长度应至少为64位,随机部分的长度应至少为128位。

        5
  •  0
  •   Paolo Fassin    6 年前

    使用可扩展的方法,除了占用内存之外,提取的速度也会减慢。然而,假设有一个由N个数字组成的空间,如果它由一维数组表示,为了提取这样的空间中的数字,我将不得不平均进行(N/2)次迭代;但是,如果这个空间是一个平方矩阵,例如,对于我提取的每个数字,我将平均有(Sqrt(N)/2+Sqrt(N)/2)次迭代;这是行搜索和列搜索:迭代次数更少。对于三维矩阵,迭代次数甚至更小:(N^(1/3)/2+N^(1/3)/2+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.
    
    推荐文章