com.wallstop-studios.unity-helpers 2.0.0-rc06 → 2.0.0-rc07
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Runtime/Core/Helper/Helpers.cs +1 -556
- package/Runtime/Core/Helper/Partials/LogHelpers.cs +13 -0
- package/Runtime/Core/Helper/Partials/LogHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/MathHelpers.cs +30 -0
- package/Runtime/Core/Helper/Partials/MathHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +388 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/TransformHelpers.cs +167 -0
- package/Runtime/Core/Helper/Partials/TransformHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials.meta +3 -0
- package/Runtime/Core/Random/AbstractRandom.cs +182 -150
- package/Runtime/Core/Random/SquirrelRandom.cs +9 -10
- package/Runtime/Core/Random/SystemRandom.cs +78 -41
- package/Tests/Runtime/Helper/ObjectHelperTests.cs +402 -0
- package/Tests/Runtime/Helper/ObjectHelperTests.cs.meta +3 -0
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +58 -3
- package/Tests/Runtime/Random/RandomTestBase.cs +261 -6
- package/Tests/Runtime/Random/SquirrelRandomTests.cs +5 -0
- package/package.json +1 -1
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
using System.Collections.Generic;
|
|
6
6
|
using System.Linq;
|
|
7
7
|
using System.Runtime.Serialization;
|
|
8
|
-
using System.Text.Json.Serialization;
|
|
9
8
|
using DataStructure.Adapters;
|
|
10
9
|
using UnityEngine;
|
|
11
10
|
|
|
@@ -16,24 +15,16 @@
|
|
|
16
15
|
private static readonly ConcurrentDictionary<Type, Array> EnumTypeCache = new();
|
|
17
16
|
|
|
18
17
|
protected const uint HalfwayUint = uint.MaxValue / 2;
|
|
19
|
-
protected const double MagicDouble = 4.6566128752458E-10;
|
|
20
18
|
protected const float MagicFloat = 5.960465E-008F;
|
|
21
19
|
|
|
22
20
|
protected double? _cachedGaussian;
|
|
23
21
|
|
|
24
|
-
protected AbstractRandom() { }
|
|
25
|
-
|
|
26
22
|
public abstract RandomState InternalState { get; }
|
|
27
23
|
|
|
28
|
-
public int Next()
|
|
24
|
+
public virtual int Next()
|
|
29
25
|
{
|
|
30
|
-
int
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
result = unchecked((int)NextUint());
|
|
34
|
-
} while (result < 0);
|
|
35
|
-
|
|
36
|
-
return result;
|
|
26
|
+
// Mask out the MSB to ensure the value is within [0, int.MaxValue]
|
|
27
|
+
return unchecked((int)NextUint() & 0x7FFFFFFF);
|
|
37
28
|
}
|
|
38
29
|
|
|
39
30
|
public int Next(int max)
|
|
@@ -55,30 +46,122 @@
|
|
|
55
46
|
);
|
|
56
47
|
}
|
|
57
48
|
|
|
58
|
-
uint range =
|
|
59
|
-
|
|
49
|
+
uint range = (uint)(max - min);
|
|
50
|
+
if (range == 0)
|
|
51
|
+
{
|
|
52
|
+
return unchecked((int)NextUint());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return unchecked((int)(min + NextUint(range)));
|
|
60
56
|
}
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
public T Next<T>(IEnumerable<T> enumerable)
|
|
59
|
+
{
|
|
60
|
+
if (enumerable is ICollection<T> collection)
|
|
61
|
+
{
|
|
62
|
+
return Next(collection);
|
|
63
|
+
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
return Next((IReadOnlyList<T>)enumerable.ToList());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public T Next<T>(ICollection<T> collection)
|
|
66
69
|
{
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
int count = collection.Count;
|
|
71
|
+
if (count <= 0)
|
|
72
|
+
{
|
|
73
|
+
throw new ArgumentException("Collection size cannot be less-than or equal-to 0");
|
|
74
|
+
}
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
Generates a uniform random number within the bound, avoiding modulo bias
|
|
72
|
-
*/
|
|
73
|
-
uint threshold = unchecked((uint)((0x100000000UL - max) % max));
|
|
74
|
-
while (true)
|
|
76
|
+
switch (collection)
|
|
75
77
|
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
case IList<T> list:
|
|
79
|
+
return Next(list);
|
|
80
|
+
case IReadOnlyList<T> readOnlyList:
|
|
81
|
+
return Next(readOnlyList);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
int index = Next(count);
|
|
85
|
+
int i = 0;
|
|
86
|
+
foreach (T element in collection)
|
|
87
|
+
{
|
|
88
|
+
if (i++ == index)
|
|
78
89
|
{
|
|
79
|
-
return
|
|
90
|
+
return element;
|
|
80
91
|
}
|
|
81
92
|
}
|
|
93
|
+
|
|
94
|
+
// Should never happen
|
|
95
|
+
return default;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public T Next<T>(IList<T> list)
|
|
99
|
+
{
|
|
100
|
+
if (ReferenceEquals(list, null))
|
|
101
|
+
{
|
|
102
|
+
throw new ArgumentNullException(nameof(list));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
For small lists, it's much more efficient to simply return one of their elements
|
|
107
|
+
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
108
|
+
*/
|
|
109
|
+
switch (list.Count)
|
|
110
|
+
{
|
|
111
|
+
case 1:
|
|
112
|
+
return list[0];
|
|
113
|
+
case 2:
|
|
114
|
+
return NextBool() ? list[0] : list[1];
|
|
115
|
+
default:
|
|
116
|
+
return list[Next(list.Count)];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private T Next<T>(IReadOnlyList<T> list)
|
|
121
|
+
{
|
|
122
|
+
/*
|
|
123
|
+
For small lists, it's much more efficient to simply return one of their elements
|
|
124
|
+
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
125
|
+
*/
|
|
126
|
+
switch (list.Count)
|
|
127
|
+
{
|
|
128
|
+
case 1:
|
|
129
|
+
return list[0];
|
|
130
|
+
case 2:
|
|
131
|
+
return NextBool() ? list[0] : list[1];
|
|
132
|
+
default:
|
|
133
|
+
return list[Next(list.Count)];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public T Next<T>()
|
|
138
|
+
where T : struct, Enum
|
|
139
|
+
{
|
|
140
|
+
Type enumType = typeof(T);
|
|
141
|
+
T[] enumValues;
|
|
142
|
+
if (EnumTypeCache.TryGetValue(enumType, out Array enumArray))
|
|
143
|
+
{
|
|
144
|
+
enumValues = (T[])enumArray;
|
|
145
|
+
}
|
|
146
|
+
else
|
|
147
|
+
{
|
|
148
|
+
enumValues = (T[])Enum.GetValues(enumType);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return RandomOf(enumValues);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Internal sampler
|
|
155
|
+
public abstract uint NextUint();
|
|
156
|
+
|
|
157
|
+
public uint NextUint(uint max)
|
|
158
|
+
{
|
|
159
|
+
if (max == 0)
|
|
160
|
+
{
|
|
161
|
+
throw new ArgumentException("Max cannot be zero");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return (uint)(NextDouble() * max);
|
|
82
165
|
}
|
|
83
166
|
|
|
84
167
|
public uint NextUint(uint min, uint max)
|
|
@@ -127,12 +210,10 @@
|
|
|
127
210
|
{
|
|
128
211
|
uint upper = NextUint();
|
|
129
212
|
uint lower = NextUint();
|
|
130
|
-
|
|
131
|
-
if (NextBool())
|
|
213
|
+
unchecked
|
|
132
214
|
{
|
|
133
|
-
return
|
|
215
|
+
return (long)((((ulong)upper << 32) | lower) & (0x1UL << 63));
|
|
134
216
|
}
|
|
135
|
-
return unchecked((long)((ulong)lower << 32) | upper);
|
|
136
217
|
}
|
|
137
218
|
|
|
138
219
|
public long NextLong(long max)
|
|
@@ -142,17 +223,7 @@
|
|
|
142
223
|
throw new ArgumentException($"Max {max} cannot be less-than or equal-to 0");
|
|
143
224
|
}
|
|
144
225
|
|
|
145
|
-
|
|
146
|
-
{
|
|
147
|
-
return Next(unchecked((int)max));
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
long withinRange;
|
|
151
|
-
do
|
|
152
|
-
{
|
|
153
|
-
withinRange = NextLong();
|
|
154
|
-
} while (withinRange < 0 || max <= withinRange);
|
|
155
|
-
return withinRange;
|
|
226
|
+
return (long)(NextDouble() * max);
|
|
156
227
|
}
|
|
157
228
|
|
|
158
229
|
public long NextLong(long min, long max)
|
|
@@ -164,17 +235,25 @@
|
|
|
164
235
|
);
|
|
165
236
|
}
|
|
166
237
|
|
|
167
|
-
|
|
238
|
+
ulong range = (ulong)(max - min);
|
|
239
|
+
if (range == 0)
|
|
240
|
+
{
|
|
241
|
+
return unchecked((long)NextUlong());
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return unchecked((long)(NextDouble() * range + min));
|
|
168
245
|
}
|
|
169
246
|
|
|
170
247
|
public ulong NextUlong()
|
|
171
248
|
{
|
|
172
|
-
|
|
249
|
+
uint upper = NextUint();
|
|
250
|
+
uint lower = NextUint();
|
|
251
|
+
return ((ulong)upper << 32) | lower;
|
|
173
252
|
}
|
|
174
253
|
|
|
175
254
|
public ulong NextUlong(ulong max)
|
|
176
255
|
{
|
|
177
|
-
return
|
|
256
|
+
return (ulong)(NextDouble() * max);
|
|
178
257
|
}
|
|
179
258
|
|
|
180
259
|
public ulong NextUlong(ulong min, ulong max)
|
|
@@ -186,10 +265,10 @@
|
|
|
186
265
|
);
|
|
187
266
|
}
|
|
188
267
|
|
|
189
|
-
return
|
|
268
|
+
return NextUlong(max - min) + min;
|
|
190
269
|
}
|
|
191
270
|
|
|
192
|
-
public bool NextBool()
|
|
271
|
+
public virtual bool NextBool()
|
|
193
272
|
{
|
|
194
273
|
return NextUint() < HalfwayUint;
|
|
195
274
|
}
|
|
@@ -201,7 +280,7 @@
|
|
|
201
280
|
throw new ArgumentException(nameof(buffer));
|
|
202
281
|
}
|
|
203
282
|
|
|
204
|
-
const byte sizeOfInt =
|
|
283
|
+
const byte sizeOfInt = sizeof(int); // May differ on some platforms
|
|
205
284
|
|
|
206
285
|
// See how many ints we can slap into it.
|
|
207
286
|
int chunks = buffer.Length / sizeOfInt;
|
|
@@ -233,8 +312,8 @@
|
|
|
233
312
|
double value;
|
|
234
313
|
do
|
|
235
314
|
{
|
|
236
|
-
value = NextUint() *
|
|
237
|
-
} while (
|
|
315
|
+
value = NextUint() * (1.0 / uint.MaxValue);
|
|
316
|
+
} while (1.0 <= value);
|
|
238
317
|
|
|
239
318
|
return value;
|
|
240
319
|
}
|
|
@@ -259,7 +338,51 @@
|
|
|
259
338
|
}
|
|
260
339
|
|
|
261
340
|
double range = max - min;
|
|
262
|
-
|
|
341
|
+
if (double.IsInfinity(range))
|
|
342
|
+
{
|
|
343
|
+
return NextDoubleWithInfiniteRange(min, max);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return min + (NextDouble() * range);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
protected double NextDoubleWithInfiniteRange(double min, double max)
|
|
350
|
+
{
|
|
351
|
+
double random;
|
|
352
|
+
do
|
|
353
|
+
{
|
|
354
|
+
random = NextDoubleFullRange();
|
|
355
|
+
} while (random < min || max <= random);
|
|
356
|
+
|
|
357
|
+
return random;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
protected double NextDoubleFullRange()
|
|
361
|
+
{
|
|
362
|
+
double value = double.NaN;
|
|
363
|
+
do
|
|
364
|
+
{
|
|
365
|
+
ulong randomBits = NextUlong();
|
|
366
|
+
|
|
367
|
+
// Extract exponent (bits 52-62)
|
|
368
|
+
const ulong exponentMask = 0x7FF0000000000000;
|
|
369
|
+
|
|
370
|
+
ulong exponent = (randomBits & exponentMask) >> 52;
|
|
371
|
+
|
|
372
|
+
// Ensure exponent is not all 1's to avoid Inf and NaN
|
|
373
|
+
if (exponent == 0x7FF)
|
|
374
|
+
{
|
|
375
|
+
continue; // Regenerate
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/*
|
|
379
|
+
For uniform distribution over all finite doubles, no further masking is necessary,
|
|
380
|
+
reassemble the bits
|
|
381
|
+
*/
|
|
382
|
+
value = BitConverter.Int64BitsToDouble(unchecked((long)randomBits));
|
|
383
|
+
} while (double.IsInfinity(value) || double.IsNaN(value));
|
|
384
|
+
|
|
385
|
+
return value;
|
|
263
386
|
}
|
|
264
387
|
|
|
265
388
|
public double NextGaussian(double mean = 0, double stdDev = 1)
|
|
@@ -285,7 +408,7 @@
|
|
|
285
408
|
x = 2 * NextDouble() - 1;
|
|
286
409
|
y = 2 * NextDouble() - 1;
|
|
287
410
|
square = x * x + y * y;
|
|
288
|
-
} while (square
|
|
411
|
+
} while (square == 0 || 1 < square);
|
|
289
412
|
|
|
290
413
|
double fac = Math.Sqrt(-2 * Math.Log(square) / square);
|
|
291
414
|
_cachedGaussian = x * fac;
|
|
@@ -297,9 +420,8 @@
|
|
|
297
420
|
float value;
|
|
298
421
|
do
|
|
299
422
|
{
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
} while (value < 0 || 1 <= value);
|
|
423
|
+
value = NextUint() / (1f * uint.MaxValue);
|
|
424
|
+
} while (1f <= value);
|
|
303
425
|
|
|
304
426
|
return value;
|
|
305
427
|
}
|
|
@@ -323,103 +445,13 @@
|
|
|
323
445
|
);
|
|
324
446
|
}
|
|
325
447
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
public T Next<T>(IEnumerable<T> enumerable)
|
|
330
|
-
{
|
|
331
|
-
if (enumerable is ICollection<T> collection)
|
|
448
|
+
float range = max - min;
|
|
449
|
+
if (float.IsInfinity(range))
|
|
332
450
|
{
|
|
333
|
-
return
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return Next((IReadOnlyList<T>)enumerable.ToList());
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
public T Next<T>(ICollection<T> collection)
|
|
340
|
-
{
|
|
341
|
-
int count = collection.Count;
|
|
342
|
-
if (count <= 0)
|
|
343
|
-
{
|
|
344
|
-
throw new ArgumentException("Collection size cannot be less-than or equal-to 0");
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
switch (collection)
|
|
348
|
-
{
|
|
349
|
-
case IList<T> list:
|
|
350
|
-
return Next(list);
|
|
351
|
-
case IReadOnlyList<T> readOnlyList:
|
|
352
|
-
return Next(readOnlyList);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
int index = Next(count);
|
|
356
|
-
int i = 0;
|
|
357
|
-
foreach (T element in collection)
|
|
358
|
-
{
|
|
359
|
-
if (i++ == index)
|
|
360
|
-
{
|
|
361
|
-
return element;
|
|
362
|
-
}
|
|
451
|
+
return (float)NextDouble(min, max);
|
|
363
452
|
}
|
|
364
453
|
|
|
365
|
-
|
|
366
|
-
return default;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
public T Next<T>(IList<T> list)
|
|
370
|
-
{
|
|
371
|
-
if (ReferenceEquals(list, null))
|
|
372
|
-
{
|
|
373
|
-
throw new ArgumentNullException(nameof(list));
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/*
|
|
377
|
-
For small lists, it's much more efficient to simply return one of their elements
|
|
378
|
-
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
379
|
-
*/
|
|
380
|
-
switch (list.Count)
|
|
381
|
-
{
|
|
382
|
-
case 1:
|
|
383
|
-
return list[0];
|
|
384
|
-
case 2:
|
|
385
|
-
return NextBool() ? list[0] : list[1];
|
|
386
|
-
default:
|
|
387
|
-
return list[Next(list.Count)];
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
private T Next<T>(IReadOnlyList<T> list)
|
|
392
|
-
{
|
|
393
|
-
/*
|
|
394
|
-
For small lists, it's much more efficient to simply return one of their elements
|
|
395
|
-
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
396
|
-
*/
|
|
397
|
-
switch (list.Count)
|
|
398
|
-
{
|
|
399
|
-
case 1:
|
|
400
|
-
return list[0];
|
|
401
|
-
case 2:
|
|
402
|
-
return NextBool() ? list[0] : list[1];
|
|
403
|
-
default:
|
|
404
|
-
return list[Next(list.Count)];
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
public T Next<T>()
|
|
409
|
-
where T : struct, Enum
|
|
410
|
-
{
|
|
411
|
-
Type enumType = typeof(T);
|
|
412
|
-
T[] enumValues;
|
|
413
|
-
if (EnumTypeCache.TryGetValue(enumType, out Array enumArray))
|
|
414
|
-
{
|
|
415
|
-
enumValues = (T[])enumArray;
|
|
416
|
-
}
|
|
417
|
-
else
|
|
418
|
-
{
|
|
419
|
-
enumValues = (T[])Enum.GetValues(enumType);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return RandomOf(enumValues);
|
|
454
|
+
return min + NextFloat(range);
|
|
423
455
|
}
|
|
424
456
|
|
|
425
457
|
public T NextCachedEnum<T>()
|
|
@@ -447,7 +479,7 @@
|
|
|
447
479
|
|
|
448
480
|
// Advances the RNG
|
|
449
481
|
// https://code2d.wordpress.com/2020/07/21/perlin-noise/
|
|
450
|
-
public float[,] NextNoiseMap(int width, int height, float scale, int octaves)
|
|
482
|
+
public float[,] NextNoiseMap(int width, int height, float scale = 2.5f, int octaves = 8)
|
|
451
483
|
{
|
|
452
484
|
if (width <= 0)
|
|
453
485
|
{
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
public override uint NextUint()
|
|
39
39
|
{
|
|
40
|
-
return
|
|
40
|
+
return NextUintInternal(ref _position);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// Does not advance the RNG
|
|
@@ -51,16 +51,15 @@
|
|
|
51
51
|
return new SquirrelRandom(InternalState);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
private static uint NextUintInternal(uint seed)
|
|
54
|
+
private static uint NextUintInternal(ref uint seed)
|
|
55
55
|
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return result;
|
|
56
|
+
seed *= BitNoise1;
|
|
57
|
+
seed ^= (seed >> 8);
|
|
58
|
+
seed += BitNoise2;
|
|
59
|
+
seed ^= (seed << 8);
|
|
60
|
+
seed *= BitNoise3;
|
|
61
|
+
seed ^= (seed >> 8);
|
|
62
|
+
return seed;
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
// https://youtu.be/LWFzPP8ZbdU?t=2906
|
|
@@ -12,14 +12,18 @@
|
|
|
12
12
|
[DataContract]
|
|
13
13
|
public sealed class SystemRandom : AbstractRandom
|
|
14
14
|
{
|
|
15
|
+
private const int HalfwayInt = int.MaxValue / 2;
|
|
16
|
+
private const int SeedArraySize = 56;
|
|
17
|
+
private const int LastSeedIndex = SeedArraySize - 1;
|
|
18
|
+
|
|
15
19
|
public static IRandom Instance => ThreadLocalRandom<SystemRandom>.Instance;
|
|
16
20
|
|
|
17
21
|
public override RandomState InternalState =>
|
|
18
22
|
new(
|
|
19
|
-
unchecked((ulong)
|
|
20
|
-
unchecked((ulong)
|
|
23
|
+
unchecked((ulong)_inext),
|
|
24
|
+
unchecked((ulong)_inextp),
|
|
21
25
|
_cachedGaussian,
|
|
22
|
-
ArrayConverter.IntArrayToByteArrayBlockCopy(
|
|
26
|
+
ArrayConverter.IntArrayToByteArrayBlockCopy(_seedArray)
|
|
23
27
|
);
|
|
24
28
|
|
|
25
29
|
/*
|
|
@@ -27,9 +31,9 @@
|
|
|
27
31
|
same across platforms, a fact which defeats the purpose of these serializable
|
|
28
32
|
randoms.
|
|
29
33
|
*/
|
|
30
|
-
private int
|
|
31
|
-
private int
|
|
32
|
-
private readonly int[]
|
|
34
|
+
private int _inext;
|
|
35
|
+
private int _inextp;
|
|
36
|
+
private readonly int[] _seedArray = new int[SeedArraySize];
|
|
33
37
|
|
|
34
38
|
public SystemRandom()
|
|
35
39
|
: this(Guid.NewGuid().GetHashCode()) { }
|
|
@@ -37,28 +41,34 @@
|
|
|
37
41
|
public SystemRandom(int seed)
|
|
38
42
|
{
|
|
39
43
|
int num1 = 161803398 - (seed == int.MinValue ? int.MaxValue : Math.Abs(seed));
|
|
40
|
-
|
|
44
|
+
_seedArray[LastSeedIndex] = num1;
|
|
41
45
|
int num2 = 1;
|
|
42
|
-
for (int index1 = 1; index1 <
|
|
46
|
+
for (int index1 = 1; index1 < LastSeedIndex; ++index1)
|
|
43
47
|
{
|
|
44
|
-
int index2 = 21 * index1 %
|
|
45
|
-
|
|
48
|
+
int index2 = 21 * index1 % LastSeedIndex;
|
|
49
|
+
_seedArray[index2] = num2;
|
|
46
50
|
num2 = num1 - num2;
|
|
47
51
|
if (num2 < 0)
|
|
52
|
+
{
|
|
48
53
|
num2 += int.MaxValue;
|
|
49
|
-
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
num1 = _seedArray[index2];
|
|
50
57
|
}
|
|
51
58
|
for (int index3 = 1; index3 < 5; ++index3)
|
|
52
59
|
{
|
|
53
|
-
for (int index4 = 1; index4 <
|
|
60
|
+
for (int index4 = 1; index4 < SeedArraySize; ++index4)
|
|
54
61
|
{
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
62
|
+
int value = _seedArray[index4] -= _seedArray[1 + (index4 + 30) % LastSeedIndex];
|
|
63
|
+
if (value < 0)
|
|
64
|
+
{
|
|
65
|
+
_seedArray[index4] += int.MaxValue;
|
|
66
|
+
}
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
|
|
70
|
+
_inext = 0;
|
|
71
|
+
_inextp = 21;
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
[JsonConstructor]
|
|
@@ -66,59 +76,86 @@
|
|
|
66
76
|
{
|
|
67
77
|
unchecked
|
|
68
78
|
{
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
_inext = (int)internalState.State1;
|
|
80
|
+
_inextp = (int)internalState.State2;
|
|
71
81
|
}
|
|
72
82
|
_cachedGaussian = internalState.Gaussian;
|
|
73
|
-
|
|
83
|
+
_seedArray = ArrayConverter.ByteArrayToIntArrayBlockCopy(internalState.Payload);
|
|
74
84
|
}
|
|
75
85
|
|
|
76
|
-
public override
|
|
86
|
+
public override int Next()
|
|
77
87
|
{
|
|
78
|
-
int
|
|
79
|
-
int
|
|
88
|
+
int localINext = _inext;
|
|
89
|
+
int localINextP = _inextp;
|
|
80
90
|
int index1;
|
|
81
|
-
if ((index1 =
|
|
91
|
+
if ((index1 = localINext + 1) >= SeedArraySize)
|
|
92
|
+
{
|
|
82
93
|
index1 = 1;
|
|
94
|
+
}
|
|
95
|
+
|
|
83
96
|
int index2;
|
|
84
|
-
if ((index2 =
|
|
97
|
+
if ((index2 = localINextP + 1) >= SeedArraySize)
|
|
98
|
+
{
|
|
85
99
|
index2 = 1;
|
|
86
|
-
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
int num = _seedArray[index1] - _seedArray[index2];
|
|
87
103
|
if (num == int.MaxValue)
|
|
104
|
+
{
|
|
88
105
|
--num;
|
|
106
|
+
}
|
|
107
|
+
|
|
89
108
|
if (num < 0)
|
|
109
|
+
{
|
|
90
110
|
num += int.MaxValue;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_seedArray[index1] = num;
|
|
114
|
+
_inext = index1;
|
|
115
|
+
_inextp = index2;
|
|
116
|
+
return num;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public override uint NextUint()
|
|
120
|
+
{
|
|
121
|
+
if (NextBool())
|
|
122
|
+
{
|
|
123
|
+
return unchecked((uint)(Next() ^ 0x80000000));
|
|
124
|
+
}
|
|
125
|
+
return unchecked((uint)Next());
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public override bool NextBool()
|
|
129
|
+
{
|
|
130
|
+
return Next() < HalfwayInt;
|
|
95
131
|
}
|
|
96
132
|
|
|
97
133
|
public override double NextDouble()
|
|
98
134
|
{
|
|
99
|
-
double
|
|
135
|
+
double random;
|
|
100
136
|
do
|
|
101
137
|
{
|
|
102
|
-
|
|
103
|
-
} while (
|
|
138
|
+
random = Next() / (1.0 * int.MaxValue);
|
|
139
|
+
} while (1.0 <= random);
|
|
104
140
|
|
|
105
|
-
return
|
|
141
|
+
return random;
|
|
106
142
|
}
|
|
107
143
|
|
|
108
144
|
public override float NextFloat()
|
|
109
145
|
{
|
|
110
|
-
|
|
146
|
+
float random;
|
|
147
|
+
do
|
|
148
|
+
{
|
|
149
|
+
random = Next() * (1f / int.MaxValue);
|
|
150
|
+
} while (1f <= random);
|
|
151
|
+
|
|
152
|
+
return random;
|
|
111
153
|
}
|
|
112
154
|
|
|
113
155
|
public override IRandom Copy()
|
|
114
156
|
{
|
|
115
157
|
SystemRandom copy = new(InternalState);
|
|
116
|
-
|
|
117
|
-
for (int i = 0; i < SeedArray.Length; ++i)
|
|
118
|
-
{
|
|
119
|
-
copy.SeedArray[i] = SeedArray[i];
|
|
120
|
-
}
|
|
121
|
-
|
|
158
|
+
Array.Copy(_seedArray, copy._seedArray, _seedArray.Length);
|
|
122
159
|
return copy;
|
|
123
160
|
}
|
|
124
161
|
}
|