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. |
4 | // |
5 | // random.h |
6 | // |
7 | |
8 | // |
9 | // Defines a random number generator, initially from the System.Random code in the BCL. If you notice any problems, |
10 | // please compare to the implementation in src\mscorlib\src\system\random.cs. |
11 | // |
12 | // Main advantages over rand() are: |
13 | // |
14 | // 1) It generates better random numbers |
15 | // 2) It can have multiple instantiations with different seeds |
16 | // 3) It behaves the same regardless of whether we build with VC++ or GCC |
17 | // |
18 | // If you are working in the VM, we have a convenience method: code:GetRandomInt. This usess a thread-local |
19 | // Random instance if a Thread object is available, and otherwise falls back to a global instance |
20 | // with a spin-lock. |
21 | // |
22 | |
23 | #ifndef _CLRRANDOM_H_ |
24 | #define _CLRRANDOM_H_ |
25 | |
26 | #include <math.h> |
27 | |
28 | // |
29 | // Forbid the use of srand()/rand(), as these are globally shared facilities and our use of them would |
30 | // interfere with native user code in the same process. This override is not compatible with stl headers. |
31 | // |
32 | #if !defined(DO_NOT_DISABLE_RAND) && !defined(USE_STL) |
33 | |
34 | #ifdef srand |
35 | #undef srand |
36 | #endif |
37 | #define srand Do_not_use_srand |
38 | |
39 | #ifdef rand |
40 | #undef rand |
41 | #endif |
42 | #define rand Do_not_use_rand |
43 | |
44 | #endif //!DO_NOT_DISABLE_RAND && !USE_STL |
45 | |
46 | |
47 | class CLRRandom |
48 | { |
49 | private: |
50 | // |
51 | // Private Constants |
52 | // |
53 | static const int MBIG = INT_MAX; |
54 | static const int MSEED = 161803398; |
55 | static const int MZ = 0; |
56 | |
57 | |
58 | // |
59 | // Member Variables |
60 | // |
61 | int inext; |
62 | int inextp; |
63 | int SeedArray[56]; |
64 | |
65 | bool initialized; |
66 | |
67 | public: |
68 | // |
69 | // Constructors |
70 | // |
71 | |
72 | CLRRandom() |
73 | { |
74 | LIMITED_METHOD_CONTRACT; |
75 | initialized = false; |
76 | } |
77 | |
78 | void Init() |
79 | { |
80 | LIMITED_METHOD_CONTRACT; |
81 | LARGE_INTEGER time; |
82 | if (!QueryPerformanceCounter(&time)) |
83 | time.QuadPart = GetTickCount(); |
84 | Init((int)time.u.LowPart ^ GetCurrentThreadId() ^ GetCurrentProcessId()); |
85 | } |
86 | |
87 | void Init(int Seed) |
88 | { |
89 | LIMITED_METHOD_CONTRACT; |
90 | |
91 | int ii; |
92 | int mj, mk; |
93 | |
94 | //Initialize our Seed array. |
95 | mj = MSEED - abs(Seed); |
96 | SeedArray[55]=mj; |
97 | mk=1; |
98 | for (int i=1; i<55; i++) { //Apparently the range [1..55] is special (Knuth) and so we're wasting the 0'th position. |
99 | ii = (21*i)%55; |
100 | SeedArray[ii]=mk; |
101 | mk = mj - mk; |
102 | if (mk<0) mk+=MBIG; |
103 | mj=SeedArray[ii]; |
104 | } |
105 | for (int k=1; k<5; k++) { |
106 | for (int i=1; i<56; i++) { |
107 | SeedArray[i] -= SeedArray[1+(i+30)%55]; |
108 | if (SeedArray[i]<0) SeedArray[i]+=MBIG; |
109 | } |
110 | } |
111 | inext=0; |
112 | inextp = 21; |
113 | Seed = 1; |
114 | |
115 | initialized = true; |
116 | } |
117 | |
118 | bool IsInitialized() |
119 | { |
120 | LIMITED_METHOD_CONTRACT; |
121 | return initialized; |
122 | } |
123 | |
124 | private: |
125 | // |
126 | // Package Private Methods |
127 | // |
128 | |
129 | /*====================================Sample==================================== |
130 | **Action: Return a new random number [0..1) and reSeed the Seed array. |
131 | **Returns: A double [0..1) |
132 | **Arguments: None |
133 | **Exceptions: None |
134 | ==============================================================================*/ |
135 | double Sample() |
136 | { |
137 | LIMITED_METHOD_CONTRACT; |
138 | |
139 | //Including this division at the end gives us significantly improved |
140 | //random number distribution. |
141 | return (InternalSample()*(1.0/MBIG)); |
142 | } |
143 | |
144 | int InternalSample() |
145 | { |
146 | LIMITED_METHOD_CONTRACT; |
147 | |
148 | int retVal; |
149 | int locINext = inext; |
150 | int locINextp = inextp; |
151 | |
152 | if (++locINext >=56) locINext=1; |
153 | if (++locINextp>= 56) locINextp = 1; |
154 | |
155 | retVal = SeedArray[locINext]-SeedArray[locINextp]; |
156 | |
157 | if (retVal == MBIG) retVal--; |
158 | if (retVal<0) retVal+=MBIG; |
159 | |
160 | SeedArray[locINext]=retVal; |
161 | |
162 | inext = locINext; |
163 | inextp = locINextp; |
164 | |
165 | return retVal; |
166 | } |
167 | |
168 | double GetSampleForLargeRange() |
169 | { |
170 | LIMITED_METHOD_CONTRACT; |
171 | |
172 | // The distribution of double value returned by Sample |
173 | // is not distributed well enough for a large range. |
174 | // If we use Sample for a range [Int32.MinValue..Int32.MaxValue) |
175 | // We will end up getting even numbers only. |
176 | |
177 | int result = InternalSample(); |
178 | // Note we can't use addition here. The distribution will be bad if we do that. |
179 | bool negative = (InternalSample()%2 == 0) ? true : false; // decide the sign based on second sample |
180 | if( negative) { |
181 | result = -result; |
182 | } |
183 | double d = result; |
184 | d += (INT_MAX - 1); // get a number in range [0 .. 2 * Int32MaxValue - 1) |
185 | d /= 2*(unsigned int)INT_MAX - 1 ; |
186 | return d; |
187 | } |
188 | |
189 | public: |
190 | // |
191 | // Public Instance Methods |
192 | // |
193 | |
194 | |
195 | /*=====================================Next===================================== |
196 | **Returns: An int [0..Int32.MaxValue) |
197 | **Arguments: None |
198 | **Exceptions: None. |
199 | ==============================================================================*/ |
200 | int Next() |
201 | { |
202 | LIMITED_METHOD_CONTRACT; |
203 | _ASSERTE(initialized); |
204 | return InternalSample(); |
205 | } |
206 | |
207 | |
208 | /*=====================================Next===================================== |
209 | **Returns: An int [minvalue..maxvalue) |
210 | **Arguments: minValue -- the least legal value for the Random number. |
211 | ** maxValue -- One greater than the greatest legal return value. |
212 | **Exceptions: None. |
213 | ==============================================================================*/ |
214 | int Next(int minValue, int maxValue) |
215 | { |
216 | LIMITED_METHOD_CONTRACT; |
217 | _ASSERTE(initialized); |
218 | _ASSERTE(minValue < maxValue); |
219 | |
220 | LONGLONG range = (LONGLONG)maxValue-minValue; |
221 | double result; |
222 | |
223 | if( range <= (LONGLONG)INT_MAX) |
224 | result = (Sample() * range) + minValue; |
225 | else |
226 | result = (GetSampleForLargeRange() * range) + minValue; |
227 | |
228 | _ASSERTE(result >= minValue && result < maxValue); |
229 | return (int)result; |
230 | } |
231 | |
232 | |
233 | /*=====================================Next===================================== |
234 | **Returns: An int [0..maxValue) |
235 | **Arguments: maxValue -- One more than the greatest legal return value. |
236 | **Exceptions: None. |
237 | ==============================================================================*/ |
238 | int Next(int maxValue) |
239 | { |
240 | LIMITED_METHOD_CONTRACT; |
241 | _ASSERTE(initialized); |
242 | double result = Sample()*maxValue; |
243 | _ASSERTE(result >= 0 && result < maxValue); |
244 | return (int)result; |
245 | } |
246 | |
247 | |
248 | /*=====================================Next===================================== |
249 | **Returns: A double [0..1) |
250 | **Arguments: None |
251 | **Exceptions: None |
252 | ==============================================================================*/ |
253 | double NextDouble() |
254 | { |
255 | LIMITED_METHOD_CONTRACT; |
256 | _ASSERTE(initialized); |
257 | double result = Sample(); |
258 | _ASSERTE(result >= 0 && result < 1); |
259 | return result; |
260 | } |
261 | |
262 | |
263 | /*==================================NextBytes=================================== |
264 | **Action: Fills the byte array with random bytes [0..0x7f]. The entire array is filled. |
265 | **Returns:Void |
266 | **Arguments: buffer -- the array to be filled. |
267 | **Exceptions: None |
268 | ==============================================================================*/ |
269 | void NextBytes(__out_ecount(length) BYTE buffer[], int length) |
270 | { |
271 | LIMITED_METHOD_CONTRACT; |
272 | _ASSERTE(initialized); |
273 | for (int i=0; i<length; i++) { |
274 | buffer[i]=(BYTE)(InternalSample()%(256)); |
275 | } |
276 | } |
277 | }; |
278 | |
279 | #endif //_CLRRANDOM_H_ |
280 | |