我正在使用单位uBigIntsV4
和TInteger
组件
幸运的是,它有一个内置的random
程序,让您选择一个非常高的随机数并将其作为字符串返回。
但我无法找到一种方法来开发一个功能,让我可以从x
到n
拍摄一个高随机数而不会重复。
由于本机无符号整数范围可以涵盖所有情况,因此无法创建列表或数组。
我怎样才能解决这个问题?
答案 0 :(得分:1)
抱歉,我不熟悉uBigIntsV4。我希望它具有实现基本的芳基化操作(*,+,mod)所需的所有功能。如果是这样,您可以使用以下公式计算下一个伪随机数
a , c 和 m 值
有关详细信息,请参阅Linear congruential generator wiki。
答案 1 :(得分:1)
我没有太多时间评论我的答案,但是我创建的这个Delphi库将允许您提取最小-最大范围内的随机数,该数量始终不同于先前提取的数量,直到出现更多数量为止。 稍后,如果需要,我可以扩展此答案的解释。
注意:您必须启用编译器优化选项;使用GetRndGVNum(),您可以提取大于65535的范围内的数字,只需增加常数DefGVNumArrSize(范围= DefGVNumArrSize * 8)即可。
Unit so;
{$A-}
{$B-}
{$U+}
{$W-}
interface
Const DefGVNumArrSize=8192;
MinCellValue=-1 ShL 31;
MaxDeltaNum=DefGVNumArrSize*8-1;
Type TGVNumArr=Array[0..DefGVNumArrSize-1] Of Byte;
TGVConfig=Record
{0} GVNumArrAmount,
{4} GVNumArrMin:Integer;
{8} GVNumArr:TGVNumArr;
End;
Var MyRandSeed:Integer=0;
Procedure MyFillChar (M:Pointer;S,V:Cardinal);
{ Similar to the System.FillChar (), but faster.
NOTE: it is written entirely IN ASSEMBLER.
Skip not required (CALL, JMP or conditional jump),
and it's very fast.
To set the VAR to 0. A
(of type BYTE, WORD, SMALLINT or INTEGER):
MyFillChar (@ A, SIZEOF (A), 0);
To set the VAR to 0. A
(type T = RECORD):
MyFillChar (@ A, SIZEOF (A), 0) }
Function CopyInt (IntIn:Integer;
IntPtrOut:Pointer):Integer;
{Set the BOOLEAN parameter to IntPtrOut ^ with IntIn e
returns IntIn.
NOTE: It is written IN ASSEMBLER.
RESTRICTIONS: None}
Procedure MyInitRand;
{Initialize the glob. VAR. MyRandSeed for the function MyRandInt ().
RESTRICTIONS: None}
Function MyRandInt (Min,Max:Integer):Integer;
{Returns a random number between MIN and MAX (inclusive).
RESTRICTIONS: None.
NOTES: Permitted MIN> MAX.
Allow integer values with 32-bit SIGN for MIN and MAX.
Use a 32-bit conversion of Turbo-PASCAL System.RandInt ()}
Procedure ReSetGVConfig (Var GVConfig:TGVConfig;
Min,Max:Integer);
(* (Re) initializes the extraction of random numbers,
between Min and Max, with GetRndGVNum (GVConfig).
The values allowed for Min and Max
range from -2147483647 to +2147483647,
but the maximum number of numbers
which can be extracted is 65536.
If Min and Max constitute a too wide range,
the aforementioned range e will be restricted
the minimum value will be raised.
you can specify Min> Max *)
Function GetRndGVNum (Var GVConfig:TGVConfig):Integer;
(* Extracts a random number in the Min-Max range at all times
different from those previously extracted.
Return to MinCellValue (-2147483648)
if there are no other numbers to extract.
Initialize the extraction with ReSetGVConfig (GVConfig, Min, Max) *)
Procedure RndGVNum_Test (GVMin,GVMax:Integer);
(* Test program of this library *)
implementation
Uses Math,SysUtils;
Function CopyInt(IntIn:Integer;IntPtrOut:Pointer):Integer; Assembler;
(* EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
Can freely modify the EAX, ECX, AND EDX REGISTERs *)
Asm
Mov EAX,IntIn
Mov [EDX],EAX
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 MyInitRand;
Begin
MyRandSeed:=Round(Frac(Time)*4294967295);
End;
Function NextRand:Cardinal; Assembler;
{ EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
Can freely modify the EAX, ECX, AND EDX REGISTERs. }
Asm
Push EDI
(* ---------------------------------------- *)
LEA EDI,MyRandSeed
(* ---------------------------------------- *)
MovZX EAX,Word Ptr [EDI] { RandSeed.w0 }
Mov CX,8405H
Mul CX { New = Old.w0 * 8405H }
Mov CX,[EDI]
ShL CX,3 { New.w2 += Old.w0 * 808H }
Add Ch,CL
Add DX,CX
Mov CX,[EDI+2]
Add DX,CX { New.w2 += Old.w2 * 8405H }
ShL CX,2
Add DX,CX
Add DH,CL
ShL CX,5
Add DH,CL
Add AX,1
AdC DX,0 { New += 1 }
ShL EDX,16
Or EAX,EDX { EDX= DX:AX }
Mov [EDI],EAX
(* ---------------------------------------- *)
Pop EDI
End;
Function MyRandInt(Min,Max:Integer):Integer; Assembler;
{ EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
Can freely modify the EAX, ECX, AND EDX REGISTERs. }
Asm
Push ESI
Push EDI
Mov ESI,Max {A}
Mov EDI,Min {B}
{$IFDEF Delphi_7_Plus}
Mov ECX,EDI
Cmp EDI,ESI
CMovGE EDI,ESI {MIN}
CMovGE ESI,ECX {MAX}
{$ELSE}
XOr ECX,ECX
Sub EDI,ESI
Mov EAX,EDI
SetGE CL
Dec ECX
And EDI,ECX
Add EDI,ESI
Not ECX
And EAX,ECX
Add ESI,EAX
{$ENDIF}
Sub ESI,EDI
Inc ESI {ESI= MAX-MIN+1}
Call NextRand {EAX= 32 Bit Random number}
Mul ESI {EDX:EAX= EAX*(MAX-MIN+1)}
Add EDX,EDI
Mov EAX,EDX {@RESULT= EAX*(MAX-MIN+1)/(65536*65536)+MIN}
Pop EDI
Pop ESI
End;
Procedure ReSetGVConfig(Var GVConfig:TGVConfig;
Min,Max:Integer);
Var Diff:Integer;
Begin
With GVConfig Do
Begin
Inc(Min,Integer(Min=MinCellValue));
Diff:=Max-Min+
Integer(Max=MinCellValue);
Dec(Diff,
Integer(Abs(Diff)>MaxDeltaNum)*
(Diff-Sign(Diff)*MaxDeltaNum));
GVNumArrAmount:=Abs(Diff)+1;
GVNumArrMin:=Max-Diff*Integer(Diff>=0);
MyFillChar(@GVNumArr,SizeOf(GVNumArr),0);
End;
End;
Function GetRndGVNum(Var GVConfig:TGVConfig):Integer; Assembler;
{ EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
Can freely modify the EAX, ECX, AND EDX REGISTERs. }
Asm
Push EBX
Push ESI
Push EDI
Mov EDI,GVConfig
Mov EAX,MinCellValue
Mov EDX,[EDI+OFFSET TGVConfig.GVNumArrAmount]
Or EDX,EDX
JE @@00
Mov EAX,1
Call MyRandInt
{EDI: GRConfig.GRNumArr[I].
EAX: VC.
EBX: I.
ECX: RC.
DH: Mask}
Mov DH,128 {Mask}
Mov EBX,OFFSET TGVConfig.GVNumArr-1 {I}
Mov ECX,-1 {RC}
XOr ESI,ESI
{-----------}
@@01:RoL DH,1
AdC EBX,ESI
Inc ECX
Mov DL,[EDI+EBX]
And DL,DH
Sub DL,DH
SbB EAX,ESI
JNE @@01
{-----------}
Or [EDI+EBX],DH
Dec DWord Ptr [EDI+OFFSET TGVConfig.GVNumArrAmount]
Add ECX,[EDI+OFFSET TGVConfig.GVNumArrMin]
Mov EAX,ECX
@@00:Pop EDI
Pop ESI
Pop EBX
End;
Procedure RndGVNum_Test(GVMin,GVMax:Integer);
Var Num,Max,Count:Integer;
GVConfig:TGVConfig;
Begin
MyInitRand;
Count:=0;
ReSetGVConfig(GVConfig,GVMin,GVMax);
Max:=GVConfig.GVNumArrMin+
GVConfig.GVNumArrAmount-1;
WriteLn;
While (CopyInt(GetRndGVNum(GVConfig),@Num)<>MinCellValue) Do
Begin
Write(Num,#9);
Inc(Count);
End;
WriteLn;
WriteLn;
WriteLn('Minimum value:');
WriteLn(GVMin);
WriteLn('Maximum value:');
WriteLn(GVMax);
WriteLn('New minimum value:');
WriteLn(GVConfig.GVNumArrMin);
WriteLn('New maximum value:');
WriteLn(Max);
WriteLn('Maximum allowed value:');
WriteLn(GVConfig.GVNumArrMin+MaxDeltaNum);
WriteLn('Maximum extraction width:');
WriteLn(MaxDeltaNum+1);
WriteLn('Total number of numbers generated:');
WriteLn(Count);
WriteLn;
WriteLn('ALL NUMBERS HAVE BEEN EXTRACTS!');
WriteLn('Try extraction of other 3 numbers:');
WriteLn;
WriteLn(GetRndGVNum(GVConfig));
WriteLn(GetRndGVNum(GVConfig));
WriteLn(GetRndGVNum(GVConfig));
WriteLn;
Write('Press ENTER to exit ... ');
ReadLn;
End;
End.