1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
12 private const int MBIG
= int.MaxValue
;
13 private const int MSEED
= 161803398;
20 private readonly int[] _seedArray
= new int[56];
27 // Native Declarations
34 /*=========================================================================================
35 **Action: Initializes a new instance of the Random class, using a default seed value
36 ===========================================================================================*/
38 : this(GenerateSeed())
42 /*=========================================================================================
43 **Action: Initializes a new instance of the Random class, using a specified seed value
44 ===========================================================================================*/
45 public Random(int Seed
)
50 // Initialize our Seed array.
51 int subtraction
= (Seed
== int.MinValue
) ? int.MaxValue
: Math
.Abs(Seed
);
52 mj
= MSEED
- subtraction
;
55 for (int i
= 1; i
< 55; i
++)
56 { // Apparently the range [1..55] is special (Knuth) and so we're wasting the 0'th position.
57 if ((ii
+= 21) >= 55) ii
-= 55;
60 if (mk
< 0) mk
+= MBIG
;
63 for (int k
= 1; k
< 5; k
++)
65 for (int i
= 1; i
< 56; i
++)
69 _seedArray
[i
] -= _seedArray
[1 + n
];
70 if (_seedArray
[i
] < 0) _seedArray
[i
] += MBIG
;
78 // Package Private Methods
81 /*====================================Sample====================================
82 **Action: Return a new random number [0..1) and reSeed the Seed array.
83 **Returns: A double [0..1)
86 ==============================================================================*/
87 protected virtual double Sample()
89 // Including this division at the end gives us significantly improved
90 // random number distribution.
91 return (InternalSample() * (1.0 / MBIG
));
94 private int InternalSample()
97 int locINext
= _inext
;
98 int locINextp
= _inextp
;
100 if (++locINext
>= 56) locINext
= 1;
101 if (++locINextp
>= 56) locINextp
= 1;
103 retVal
= _seedArray
[locINext
] - _seedArray
[locINextp
];
105 if (retVal
== MBIG
) retVal
--;
106 if (retVal
< 0) retVal
+= MBIG
;
108 _seedArray
[locINext
] = retVal
;
117 private static Random
? t_threadRandom
;
118 private static readonly Random s_globalRandom
= new Random(GenerateGlobalSeed());
120 /*=====================================GenerateSeed=====================================
121 **Returns: An integer that can be used as seed values for consecutively
122 creating lots of instances on the same thread within a short period of time.
123 ========================================================================================*/
124 private static int GenerateSeed()
126 Random
? rnd
= t_threadRandom
;
130 lock (s_globalRandom
)
132 seed
= s_globalRandom
.Next();
134 rnd
= new Random(seed
);
135 t_threadRandom
= rnd
;
140 /*==================================GenerateGlobalSeed====================================
141 **Action: Creates a number to use as global seed.
142 **Returns: An integer that is safe to use as seed values for thread-local seed generators.
143 ==========================================================================================*/
144 private static unsafe int GenerateGlobalSeed()
147 Interop
.GetRandomBytes((byte*)&result
, sizeof(int));
152 // Public Instance Methods
156 /*=====================================Next=====================================
157 **Returns: An int [0..int.MaxValue)
160 ==============================================================================*/
161 public virtual int Next()
163 return InternalSample();
166 private double GetSampleForLargeRange()
168 // The distribution of double value returned by Sample
169 // is not distributed well enough for a large range.
170 // If we use Sample for a range [int.MinValue..int.MaxValue)
171 // We will end up getting even numbers only.
173 int result
= InternalSample();
174 // Note we can't use addition here. The distribution will be bad if we do that.
175 bool negative
= (InternalSample() % 2 == 0) ? true : false; // decide the sign based on second sample
181 d
+= (int.MaxValue
- 1); // get a number in range [0 .. 2 * Int32MaxValue - 1)
182 d
/= 2 * (uint)int.MaxValue
- 1;
187 /*=====================================Next=====================================
188 **Returns: An int [minvalue..maxvalue)
189 **Arguments: minValue -- the least legal value for the Random number.
190 ** maxValue -- One greater than the greatest legal return value.
192 ==============================================================================*/
193 public virtual int Next(int minValue
, int maxValue
)
195 if (minValue
> maxValue
)
197 throw new ArgumentOutOfRangeException(nameof(minValue
), SR
.Format(SR
.Argument_MinMaxValue
, nameof(minValue
), nameof(maxValue
)));
200 long range
= (long)maxValue
- minValue
;
201 if (range
<= int.MaxValue
)
203 return ((int)(Sample() * range
) + minValue
);
207 return (int)((long)(GetSampleForLargeRange() * range
) + minValue
);
212 /*=====================================Next=====================================
213 **Returns: An int [0..maxValue)
214 **Arguments: maxValue -- One more than the greatest legal return value.
216 ==============================================================================*/
217 public virtual int Next(int maxValue
)
221 throw new ArgumentOutOfRangeException(nameof(maxValue
), SR
.Format(SR
.ArgumentOutOfRange_MustBePositive
, nameof(maxValue
)));
223 return (int)(Sample() * maxValue
);
227 /*=====================================Next=====================================
228 **Returns: A double [0..1)
231 ==============================================================================*/
232 public virtual double NextDouble()
238 /*==================================NextBytes===================================
239 **Action: Fills the byte array with random bytes [0..0x7f]. The entire array is filled.
241 **Arguments: buffer -- the array to be filled.
243 ==============================================================================*/
244 public virtual void NextBytes(byte[] buffer
)
246 if (buffer
== null) throw new ArgumentNullException(nameof(buffer
));
247 for (int i
= 0; i
< buffer
.Length
; i
++)
249 buffer
[i
] = (byte)InternalSample();
253 public virtual void NextBytes(Span
<byte> buffer
)
255 for (int i
= 0; i
< buffer
.Length
; i
++)
257 buffer
[i
] = (byte)Next();