Fix pragma warning restore (dotnet/coreclr#26389)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Random.cs
blob66d0237f93b4309c87e7d4729e1f7dafb79b0477
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.
5 namespace System
7 public class Random
9 //
10 // Private Constants
12 private const int MBIG = int.MaxValue;
13 private const int MSEED = 161803398;
16 // Member Variables
18 private int _inext;
19 private int _inextp;
20 private readonly int[] _seedArray = new int[56];
23 // Public Constants
27 // Native Declarations
31 // Constructors
34 /*=========================================================================================
35 **Action: Initializes a new instance of the Random class, using a default seed value
36 ===========================================================================================*/
37 public Random()
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)
47 int ii = 0;
48 int mj, mk;
50 // Initialize our Seed array.
51 int subtraction = (Seed == int.MinValue) ? int.MaxValue : Math.Abs(Seed);
52 mj = MSEED - subtraction;
53 _seedArray[55] = mj;
54 mk = 1;
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;
58 _seedArray[ii] = mk;
59 mk = mj - mk;
60 if (mk < 0) mk += MBIG;
61 mj = _seedArray[ii];
63 for (int k = 1; k < 5; k++)
65 for (int i = 1; i < 56; i++)
67 int n = i + 30;
68 if (n >= 55) n -= 55;
69 _seedArray[i] -= _seedArray[1 + n];
70 if (_seedArray[i] < 0) _seedArray[i] += MBIG;
73 _inext = 0;
74 _inextp = 21;
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)
84 **Arguments: None
85 **Exceptions: None
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()
96 int retVal;
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;
110 _inext = locINext;
111 _inextp = locINextp;
113 return retVal;
116 [ThreadStatic]
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;
127 if (rnd == null)
129 int seed;
130 lock (s_globalRandom)
132 seed = s_globalRandom.Next();
134 rnd = new Random(seed);
135 t_threadRandom = rnd;
137 return rnd.Next();
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()
146 int result;
147 Interop.GetRandomBytes((byte*)&result, sizeof(int));
148 return result;
152 // Public Instance Methods
156 /*=====================================Next=====================================
157 **Returns: An int [0..int.MaxValue)
158 **Arguments: None
159 **Exceptions: None.
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
176 if (negative)
178 result = -result;
180 double d = result;
181 d += (int.MaxValue - 1); // get a number in range [0 .. 2 * Int32MaxValue - 1)
182 d /= 2 * (uint)int.MaxValue - 1;
183 return d;
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.
191 **Exceptions: None.
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);
205 else
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.
215 **Exceptions: None.
216 ==============================================================================*/
217 public virtual int Next(int maxValue)
219 if (maxValue < 0)
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)
229 **Arguments: None
230 **Exceptions: None
231 ==============================================================================*/
232 public virtual double NextDouble()
234 return Sample();
238 /*==================================NextBytes===================================
239 **Action: Fills the byte array with random bytes [0..0x7f]. The entire array is filled.
240 **Returns:Void
241 **Arguments: buffer -- the array to be filled.
242 **Exceptions: None
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();