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

时间:2018-10-09 15:51:32

标签: algorithm theory

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

问题:假设您有一些数字空间可以漫游以获取某种ID值。您需要在该空间内生成RANDOM号码。

要求:

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

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

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

当然,在没有考虑实际用例的情况下,我没有“最佳”选择。我对这种问题带给我的思想和逻辑实验更感兴趣,并想知道是否有人使用了其他技术,或者至少想到了其他方法来解决这样的问题。在包含视频ID的YouTube中,您确实看到了至少与之类似的东西。当然,谷歌是可以在不到一秒钟的时间内为您“搜索互联网”的公司,因此,他们的方法可能不适用于“其他任何人”。

5 个答案:

答案 0 :(得分:2)

这是理论上的答案。

由于在此数字空间内永远不会重复生成任何数字,因此该算法有效地生成了数字空间的 some 排列。这暗示它应该选择一个特定的排列并顺序生成。

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

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

答案 1 :(得分:1)

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

我建议对Bloom filter使用可扩展方法来优化查询。请注意,Bloom过滤器不存储实际值,并且有可能认为它看到了没有的值。在这种情况下,这也不是一个重大损害,并且几乎不可能预测哪些数字将被错误地指控为没有被发现。

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

一个重要的缺点是您必须预先确定最终的随机数池有多大。因为一旦过滤器被过多的数据阻塞,您就无法轻易调整其大小。

答案 2 :(得分:1)

一种众所周知的算法是在数字空间中使用一些值序列-例如,对于2的幂范围,可以使用线性同余序列-然后对值进行加密。由于加密功能必须是同构的,否则将无法进行准确的解密,因此该重复操作会一直进行到基本序列结束为止。

当然,您将要保护您的加密密钥以及用于基础序列的任何参数,并且很难维护这些机密。但是输出值肯定看起来是随机的。您将不得不在可能的安全问题与实际问题域的需求之间取得平衡。

某些循环生成器可以在O(1)中提前k代。如果选择其中之一,则可以通过为每个并行进程分配适当的种子来并行化“随机”数生成。如果某个进程通过其所有k的值运行,它只会向主服务器请求新的范围分配,或者它本身是否可以访问持久性存储。

答案 3 :(得分:0)

使用可扩展的方法,除了占用内存之外,提取的速度也变慢了。但是,假设有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个数字,在一台旧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;
(* EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
   Can freely modify the EAX, ECX, AND EDX REGISTERs. *)
Asm

 Mov   EAX,PValue

End;

Function  GetPtrValue(P:Pointer):Integer; Assembler;
(* EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
   Can freely modify the EAX, ECX, AND EDX REGISTERs. *)
Asm

 Mov   EAX,P

End;

Procedure MyFillChar(M:Pointer;S,V:Cardinal); Assembler;
(* EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
   Can freely modify the EAX, ECX, AND EDX REGISTERs. *)
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;

{ EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
  Can freely modify the EAX, ECX, AND EDX REGISTERs. }

Var Am7P       { Salvat. OFFSET(TGRData5.GRNumArrAmount7) dell' elem. trovato },
Am6P       { Salvat. OFFSET(TGRData5.GRNumArrAmount6) dell' elem. trovato },
Am5P       { Salvat. OFFSET(TGRData5.GRNumArrAmount5) dell' elem. trovato },
Am4P       { Salvat. OFFSET(TGRData4.GRNumArrAmount4) dell' elem. trovato },
Am3P       { Salvat. OFFSET(TGRData3.GRNumArrAmount3) dell' elem. trovato },
Am2P       { Salvat. OFFSET(TGRData2.GRNumArrAmount2) dell' elem. trovato },
Am1P       { Salvat. OFFSET(TGRData1.GRNumArrAmount1) dell' elem. trovato },
GRData8Ptr { Salvataggio di GRConfig } :Integer;
RndN0      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN1      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN2      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN3      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN4      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN5      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN6      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN7      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RndN8      { Salvataggio num. casuale gener. dalla funzione RanInt() },
RC7    { Salvataggio pos. ("Real Counter") rec.TGRData7 trovato },
RC6    { Salvataggio pos. ("Real Counter") rec.TGRData6 trovato },
RC5    { Salvataggio pos. ("Real Counter") rec.TGRData5 trovato },
RC4    { Salvataggio pos. ("Real Counter") rec.TGRData4 trovato },
RC3    { Salvataggio pos. ("Real Counter") rec.TGRData3 trovato },
RC2    { Salvataggio pos. ("Real Counter") rec.TGRData2 trovato },
RC1    { Salvataggio pos. ("Real Counter") rec.TGRData1 trovato },
RC0    { Salvataggio pos. ("Real Counter") rec.TGRData0 trovato } :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    // 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            { ... }
 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.

答案 4 :(得分:0)

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

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

出于此答案的目的,唯一部分和随机部分的大小是任意的。出于大多数实际目的,唯一部分的长度至少应为64位,随机部分的长度至少应为128位。