【问题标题】:Generating huge amounts of unique random numbers (theoretical)生成大量唯一随机数(理论上)
【发布时间】:2018-10-09 15:51:32
【问题描述】:

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

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

要求:

  • 在这个数字空间内,任何数字都不应生成不止一次。当所有数字都用完时,您的“生成”算法失败是可以的。它失败比默默地生成副本要好,但至少它应该在进行欺骗之前耗尽所有数字。生成的数字将用作唯一 ID 值。
  • 本地生成的数字集应尽可能随机。例如:
    • 如果在一秒钟内生成 100 个数字,然后以每天一个的速度生成另外 100 个数字,则集合的“随机性”应该几乎没有可检测到的差异。
    • 给定一个数字甚至一组数字,对这些数字进行统计分析以确定其生成时间、生成速度等特征应该是“尽可能不可能”的。
  • 对于这个思想实验,假设重叠 ID 是最坏的情况,不允许发生。 (例如,假设一个重叠的 ID 可能会导致巨大的安全漏洞,从而引发一场诉讼,使您的组织在未雨绸缪的情况下陷入众所周知的纸板箱中。)但是,可统计分析的数字字符串也可能是有害的 - 例如:如果有人能找出一种模式,他们就可以猜出 ID 并访问其他人的私人数据。

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

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

当然,如果不考虑实际用例,我认为没有“最佳”选项。我更感兴趣的只是这类问题需要我进行的思想和逻辑实验,并且很想知道是否有其他人使用过其他技术,或者至少考虑过其他技术来解决这样的问题。你确实在视频 ID 的 YouTube 中看到了至少部分类似于此的内容。当然,Google 是一家可以在一秒钟内为您“搜索互联网”的公司,因此他们的方法可能不适合“其他所有人”。

【问题讨论】:

  • 存储此类数据以供搜索的常用数据结构是前缀树:en.wikipedia.org/wiki/Trie
  • 如何将随机生成的位与当前时间戳的位连接起来?
  • 关于"randomness"1,2,3,4,5 是一个随机序列,如果您无法确定6 将是该序列中的下一个条目。我们人类的随机性很糟糕。我们试图将尽可能多的噪音和“视觉”变化压入其中;这反过来实际上减少了序列的随机性。
  • 生成 youtube id 比您描述的问题更简单。
  • Linear-feedback shift register 符合您的要求,前提是您可以接受伪随机而不是真正随机。

标签: algorithm theory


【解决方案1】:

这是一个理论上的答案。

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

如果空间大小为N,则有N! 可能的排列。给定排列索引,很容易generate it,一次一个元素。随机选择一个排列,然后生成它。

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

【讨论】:

  • +1 我读了这个问题,我的第一个想法是“你会接受这些非重复随机数的排序列表吗”。
【解决方案2】:

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

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

您可以调整过滤器的大小以权衡内存和需要多少随机数。调整它的大小以使最终误报率为 10% 会使生成数字的速度变慢,但会比误报率为 1% 时占用更少的内存。对于非常大的数据集,布隆过滤器可以很容易地并行化以跨多台机器运行。对于您想要快速生成的非常大的数据集,您甚至可以有一个两级散列,其中顶级确定将检查哪个散列函数子集,第二个针对保存的数据运行。这种设计使您可以跨机器并行执行两项检查,首先是负载平衡。这将允许疯狂的吞吐量。

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

【讨论】:

    【解决方案3】:

    一种众所周知的算法是在数字空间中使用一些值序列——例如,对于 2 的幂范围,您可以使用线性同余序列——然后对这些值进行加密。由于加密函数必须是同构的 - 否则不可能准确解密 - 这不能重复,直到基本序列环绕。

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

    一些循环生成器可以在 O(1) 中通过 k 代来推进。如果您选择其中之一,您可以通过使用适当的种子处理每个并行进程来并行化“随机”数字生成。如果一个进程运行了它的所有k 值,它只会向主服务器请求新的范围分配,或者如果它可以访问持久存储,它会自行执行。

    【讨论】:

      【解决方案4】:

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

      • 将数字空间分为唯一部分和随机部分。
      • unique 部分只是一个顺序分配的编号,从 0 开始。当最后一个编号已经生成时,唯一编号生成失败。
      • random 部分是使用加密 RNG 生成的随机数。由于唯一部分已经保证了唯一性,所以不用担心产生重复随机部分的风险。

      就本答案而言,唯一部分和随机部分的大小是任意的。对于大多数实际用途,唯一部分应至少为 64 位长,随机部分应至少为 128 位长。

      【讨论】:

        【解决方案5】:

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

        比如我报告这个单元,在Delphi下用汇编程序(保护模式)写的。要提取 2 ^ 27 个数字,GetRndGRNum () 函数,在旧的 ACER TravelMate 4220 笔记本电脑上,需要 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.
        

        【讨论】:

        • 这不是一个有效的答案吗?或者我错了什么?请发表评论。是我创建的算法。
        • 此外,此例程总是提取不同但随机的数字。
        • 眼见为实
        • 我会尽快给你解释清楚
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-03
        相关资源
        最近更新 更多