MathgeomGLS
199 строк · 4.1 Кб
1unit Velthuis.RandomNumbers;
2
3interface
4
5type
6IRandom = interface
7function Next: Integer; overload;
8function Next(MaxValue: Integer): Integer; overload;
9function Next(MinValue, MaxValue: Integer): Integer; overload;
10function NextDouble: Double;
11procedure NextBytes(var Bytes: array of Byte);
12procedure SetSeed(Seed: Int64);
13function GetSeed: Int64;
14property Seed: Int64 read GetSeed write SetSeed;
15end;
16
17TRandom = class(TInterfacedObject, IRandom)
18private
19FSeed: Int64; // Only 48 bits are used.
20public
21constructor Create(Seed: Int64 = 0);
22function Next: Integer; overload; virtual;
23function Next(MaxValue: Integer): Integer; overload;
24function Next(MinValue, MaxValue: Integer): Integer; overload;
25procedure NextBytes(var Bytes: array of Byte);
26function NextDouble: Double;
27procedure SetSeed(ASeed: Int64);
28function GetSeed: Int64;
29end;
30
31TDelphiRandom = class(TInterfacedObject, IRandom)
32public
33constructor Create; overload;
34constructor Create(Seed: Int64); overload;
35function Next: Integer; overload;
36function Next(MaxValue: Integer): Integer; overload;
37function Next(MinValue, MaxValue: Integer): Integer; overload;
38procedure NextBytes(var Bytes: array of Byte);
39function NextDouble: Double;
40procedure SetSeed(ASeed: Int64);
41function GetSeed: Int64;
42end;
43
44implementation
45
46uses
47SysUtils;
48
49{ TRandom }
50
51const
52CSeedMask = Int64(1) shl 48 - 1;
53CMultiplicator = Int64($00000005DEECE66D);
54CConstant = Int64($000000000000000B);
55CSeedSize = 48 div 8;
56
57constructor TRandom.Create(Seed: Int64);
58begin
59FSeed := Seed and CSeedMask;
60end;
61
62function TRandom.Next: Integer;
63var
64Temp: Int64;
65begin
66{$IFOPT Q+}
67{$DEFINE HasRangeChecks}
68{$ENDIF}
69
70Result := FSeed and MaxInt;
71{$RANGECHECKS OFF}
72Temp := (FSeed * CMultiplicator + CConstant) and CSeedMask;
73FSeed := Temp;
74
75{$IFDEF HasRangeChecks}
76{$RANGECHECKS ON}
77{$ENDIF}
78end;
79
80function TRandom.Next(MaxValue: Integer): Integer;
81begin
82Result := UInt64(Cardinal(FSeed)) * UInt64(Cardinal(MaxValue)) shr 32;
83end;
84
85function TRandom.Next(MinValue, MaxValue: Integer): Integer;
86begin
87Result := MinValue + Next(MaxValue - MinValue);
88end;
89
90procedure TRandom.NextBytes(var Bytes: array of Byte);
91var
92I, Tail: Integer;
93Len: Integer;
94begin
95Len := Length(Bytes) and MaxInt;
96Tail := Len mod CSeedSize;
97Len := Len div CSeedSize;
98I := 0;
99while I < Len do
100begin
101Move(FSeed, Bytes[I * CSeedSize], CSeedSize);
102Inc(I);
103Next;
104end;
105if Tail > 0 then
106begin
107Move(FSeed, Bytes[I * CSeedSize], Tail);
108Next;
109end;
110end;
111
112function TRandom.NextDouble: Double;
113const
114Divisor: Double = (1.0 / $1000000) / $1000000; // 2^-48;
115begin
116Result := FSeed * Divisor;
117Next;
118end;
119
120function TRandom.GetSeed: Int64;
121begin
122Result := FSeed;
123end;
124
125procedure TRandom.SetSeed(ASeed: Int64);
126begin
127FSeed := ASeed and CSeedMask;
128end;
129
130{ TDelphiRandom }
131
132constructor TDelphiRandom.Create(Seed: Int64);
133begin
134System.RandSeed := Integer(Seed);
135end;
136
137constructor TDelphiRandom.Create;
138begin
139Randomize;
140end;
141
142function TDelphiRandom.GetSeed: Int64;
143begin
144Result := System.RandSeed;
145end;
146
147function TDelphiRandom.Next(MinValue, MaxValue: Integer): Integer;
148begin
149Result := MinValue + Next(MaxValue - MinValue);
150end;
151
152function TDelphiRandom.Next(MaxValue: Integer): Integer;
153begin
154Result := System.Random(MaxValue);
155end;
156
157function TDelphiRandom.Next: Integer;
158begin
159Result := System.Random(MaxInt);
160end;
161
162procedure TDelphiRandom.NextBytes(var Bytes: array of Byte);
163var
164I, Tail: Integer;
165Len: Integer;
166const
167CSeedSize = SizeOf(System.RandSeed);
168begin
169Len := Length(Bytes) and MaxInt;
170Tail := Len mod CSeedSize;
171Len := Len div CSeedSize;
172
173// Can't use a for-loop, because I is still needed afterward.
174I := 0;
175while I < Len do
176begin
177Move(System.RandSeed, Bytes[I * CSeedSize], CSeedSize);
178Next;
179Inc(I);
180end;
181
182if Tail > 0 then
183begin
184Move(System.RandSeed, Bytes[I * CSeedSize], Tail);
185Next;
186end;
187end;
188
189function TDelphiRandom.NextDouble: Double;
190begin
191Result := System.Random;
192end;
193
194procedure TDelphiRandom.SetSeed(ASeed: Int64);
195begin
196System.RandSeed := Integer(ASeed);
197end;
198
199end.
200
201
202
203