Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.1.1/SimSharp-3.1.1/Random/Pcg.cs

Last change on this file was 17053, checked in by abeham, 5 years ago

#2975: merged to stable

File size: 13.5 KB
RevLine 
[16779]1// MIT License
2//
3// Copyright (c) 2016 Bismur Studios Ltd.
4// Copyright (c) 2016 Ioannis Giagkiozis
5//
6// This file is part of PCGSharp.
7//
8// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
9// and associated documentation files (the "Software"), to deal in the Software without restriction,
10// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
11// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
12// subject to the following conditions:
13//
14//  The above copyright notice and this permission notice shall be included in all copies or substantial
15//  portions of the Software.
16//
17//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
18//  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
19//  NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21//  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22//
23// This file is based on PCG, the original has the following license:
24/*
25 * PCG Random Number Generation for C.
26 *
27 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
28 *
29 * Licensed under the Apache License, Version 2.0 (the "License");
30 * you may not use this file except in compliance with the License.
31 * You may obtain a copy of the License at
32 *
33 *     http://www.apache.org/licenses/LICENSE-2.0
34 *
35 * Unless required by applicable law or agreed to in writing, software
36 * distributed under the License is distributed on an "AS IS" BASIS,
37 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
38 * See the License for the specific language governing permissions and
39 * limitations under the License.
40 *
41 * For additional information about the PCG random number generation scheme,
42 * including its license and other licensing options, visit
43 *
44 *       http://www.pcg-random.org
45 */
46
47using System;
48
49// Note, you will see that API is duplicated in PCG and PCGExtended, this is not by accident or
50// neglect. It would be "cleaner" to have a base class and just implement the core of the generator
51// in derived classes, however, this has a performance cost which for random number generators, in my
52// view, is too high. That said, there is still some room for performance optimisation.
53
54namespace SimSharp {
55
56  /// <summary>
57  /// PCG (Permuted Congruential Generator) is a C# port from C the base PCG generator
58  /// presented in "PCG: A Family of Simple Fast Space-Efficient Statistically Good
59  /// Algorithms for Random Number Generation" by Melissa E. O'Neill. The code follows closely the one
60  /// made available by O'Neill at her site: http://www.pcg-random.org/download.html
61  /// To understand how exactly this generator works read this:
62  /// http://www.pcg-random.org/pdf/toms-oneill-pcg-family-v1.02.pdf
63  /// </summary>
64  internal class Pcg {
65
66    ulong _state;
67    // This shifted to the left and or'ed with 1ul results in the default increment.
68    const ulong ShiftedIncrement = 721347520444481703ul;
69    ulong _increment = 1442695040888963407ul;
70    const ulong Multiplier = 6364136223846793005ul;
71    const double ToDouble01 = 1.0 / 4294967296.0;
72   
73    public int Next() {
74      uint result = NextUInt();
75      return (int)(result >> 1);
76    }
77
78    public int Next(int maxExclusive) {
79      if (maxExclusive <= 0)
80        throw new ArgumentException("Max Exclusive must be positive");
81
82      uint uMaxExclusive = (uint)(maxExclusive);
83      uint threshold = (uint)(-uMaxExclusive) % uMaxExclusive;
84
85      while (true) {
86        uint result = NextUInt();
87        if (result >= threshold)
88          return (int)(result % uMaxExclusive);
89      }
90    }
91
92    public int Next(int minInclusive, int maxExclusive) {
93      if (maxExclusive <= minInclusive)
94        throw new ArgumentException("MaxExclusive must be larger than MinInclusive");
95
96      uint uMaxExclusive = unchecked((uint)(maxExclusive - minInclusive));
97      uint threshold = (uint)(-uMaxExclusive) % uMaxExclusive;
98
99      while (true) {
100        uint result = NextUInt();
101        if (result >= threshold)
102          return (int)(unchecked((result % uMaxExclusive) + minInclusive));
103      }
104    }
105
106    public int[] NextInts(int count) {
107      if (count <= 0)
108        throw new ArgumentException("Zero count");
109
110      var resultA = new int[count];
111      for (var i = 0; i < count; i++) {
112        resultA[i] = Next();
113      }
114      return resultA;
115    }
116
117    public int[] NextInts(int count, int maxExclusive) {
118      if (count <= 0)
119        throw new ArgumentException("Zero count");
120
121      var resultA = new int[count];
122      for (int i = 0; i < count; i++) {
123        resultA[i] = Next(maxExclusive);
124      }
125      return resultA;
126    }
127
128    public int[] NextInts(int count, int minInclusive, int maxExclusive) {
129      if (count <= 0)
130        throw new ArgumentException("Zero count");
131
132      var resultA = new int[count];
133      for (int i = 0; i < count; i++) {
134        resultA[i] = Next(minInclusive, maxExclusive);
135      }
136      return resultA;
137    }
138
139    public uint NextUInt() {
140      ulong oldState = _state;
141      _state = unchecked(oldState * Multiplier + _increment);
142      uint xorShifted = (uint)(((oldState >> 18) ^ oldState) >> 27);
143      int rot = (int)(oldState >> 59);
144      uint result = (xorShifted >> rot) | (xorShifted << ((-rot) & 31));
145      return result;
146    }
147
148    public uint NextUInt(uint maxExclusive) {
149      uint threshold = (uint)(-maxExclusive) % maxExclusive;
150
151      while (true) {
152        uint result = NextUInt();
153        if (result >= threshold)
154          return result % maxExclusive;
155      }
156    }
157
158    public uint NextUInt(uint minInclusive, uint maxExclusive) {
159      if (maxExclusive <= minInclusive)
160        throw new ArgumentException();
161
162      uint diff = (maxExclusive - minInclusive);
163      uint threshold = (uint)(-diff) % diff;
164
165      while (true) {
166        uint result = NextUInt();
167        if (result >= threshold)
168          return (result % diff) + minInclusive;
169      }
170    }
171
172    public uint[] NextUInts(int count) {
173      if (count <= 0)
174        throw new ArgumentException("Zero count");
175
176      var resultA = new uint[count];
177      for (int i = 0; i < count; i++) {
178        resultA[i] = NextUInt();
179      }
180      return resultA;
181    }
182
183    public uint[] NextUInts(int count, uint maxExclusive) {
184      if (count <= 0)
185        throw new ArgumentException("Zero count");
186
187      var resultA = new uint[count];
188      for (int i = 0; i < count; i++) {
189        resultA[i] = NextUInt(maxExclusive);
190      }
191      return resultA;
192    }
193
194    public uint[] NextUInts(int count, uint minInclusive, uint maxExclusive) {
195      if (count <= 0)
196        throw new ArgumentException("Zero count");
197
198      var resultA = new uint[count];
199      for (int i = 0; i < count; i++) {
200        resultA[i] = NextUInt(minInclusive, maxExclusive);
201      }
202      return resultA;
203    }
204
205    public float NextFloat() {
206      return (float)(NextUInt() * ToDouble01);
207    }
208
209    public float NextFloat(float maxInclusive) {
210      if (maxInclusive <= 0)
211        throw new ArgumentException("MaxInclusive must be larger than 0");
212
213      return (float)(NextUInt() * ToDouble01) * maxInclusive;
214    }
215
216    public float NextFloat(float minInclusive, float maxInclusive) {
217      if (maxInclusive < minInclusive)
218        throw new ArgumentException("Max must be larger than min");
219
220      return (float)(NextUInt() * ToDouble01) * (maxInclusive - minInclusive) + minInclusive;
221    }
222
223    public float[] NextFloats(int count) {
224      if (count <= 0)
225        throw new ArgumentException("Zero count");
226
227      var resultA = new float[count];
228      for (int i = 0; i < count; i++) {
229        resultA[i] = NextFloat();
230      }
231      return resultA;
232    }
233
234    public float[] NextFloats(int count, float maxInclusive) {
235      if (count <= 0)
236        throw new ArgumentException("Zero count");
237
238      var resultA = new float[count];
239      for (int i = 0; i < count; i++) {
240        resultA[i] = NextFloat(maxInclusive);
241      }
242      return resultA;
243    }
244
245    public float[] NextFloats(int count, float minInclusive, float maxInclusive) {
246      if (count <= 0)
247        throw new ArgumentException("Zero count");
248
249      var resultA = new float[count];
250      for (int i = 0; i < count; i++) {
251        resultA[i] = NextFloat(minInclusive, maxInclusive);
252      }
253      return resultA;
254    }
255
256    public double NextDouble() {
257      return NextUInt() * ToDouble01;
258    }
259
260    public double NextDouble(double maxInclusive) {
261      if (maxInclusive <= 0)
262        throw new ArgumentException("Max must be larger than 0");
263
264      return NextUInt() * ToDouble01 * maxInclusive;
265    }
266
267    public double NextDouble(double minInclusive, double maxInclusive) {
268      if (maxInclusive < minInclusive)
269        throw new ArgumentException("Max must be larger than min");
270
271      return NextUInt() * ToDouble01 * (maxInclusive - minInclusive) + minInclusive;
272    }
273
274    public double[] NextDoubles(int count) {
275      if (count <= 0)
276        throw new ArgumentException("Zero count");
277
278      var resultA = new double[count];
279      for (int i = 0; i < count; i++) {
280        resultA[i] = NextDouble();
281      }
282      return resultA;
283    }
284
285    public double[] NextDoubles(int count, double maxInclusive) {
286      if (count <= 0)
287        throw new ArgumentException("Zero count");
288
289      var resultA = new double[count];
290      for (int i = 0; i < count; i++) {
291        resultA[i] = NextDouble(maxInclusive);
292      }
293      return resultA;
294    }
295
296    public double[] NextDoubles(int count, double minInclusive, double maxInclusive) {
297      if (count <= 0)
298        throw new ArgumentException("Zero count");
299
300      var resultA = new double[count];
301      for (int i = 0; i < count; i++) {
302        resultA[i] = NextDouble(minInclusive, maxInclusive);
303      }
304      return resultA;
305    }
306
307    public byte NextByte() {
308      var result = NextUInt();
309      return (byte)(result % 256);
310    }
311
312    public byte[] NextBytes(int count) {
313      if (count <= 0)
314        throw new ArgumentException("Zero count");
315
316      var resultA = new byte[count];
317      for (var i = 0; i < count; i++) {
318        resultA[i] = NextByte();
319      }
320      return resultA;
321    }
322
323    public bool NextBool() {
324      var result = NextUInt();
325      return result % 2 == 1;
326    }
327
328    public bool[] NextBools(int count) {
329      if (count <= 0)
330        throw new ArgumentException("Zero count");
331
332      var resultA = new bool[count];
333      for (var i = 0; i < count; i++) {
334        resultA[i] = NextBool();
335      }
336      return resultA;
337    }
338
339    public int PeriodPow2() {
340      return 64;
341    }
342
343    public void SetStream(int sequence) {
344      SetStream((ulong)sequence);
345    }
346
347    public void SetStream(ulong sequence) {
348      _increment = (sequence << 1) | 1;
349    }
350
351    public ulong CurrentStream() {
352      return _increment >> 1;
353    }
354
355    public Pcg() : this(PcgSeed.GuidBasedSeed()) {
356    }
357
358    public Pcg(int seed) : this((ulong)seed) {
359    }
360
361    public Pcg(int seed, int sequence) : this((ulong)seed, (ulong)sequence) {
362    }
363
364    public Pcg(ulong seed, ulong sequence = ShiftedIncrement) {
365      Initialize(seed, sequence);
366    }
367
368    void Initialize(ulong seed, ulong initseq) {
369      _state = 0ul;
370      SetStream(initseq);
371      NextUInt();
372      _state += seed;
373      NextUInt();
374    }
375
376  }
377
378// MIT License
379//
380// Copyright (c) 2016 Bismur Studios Ltd.
381// Copyright (c) 2016 Ioannis Giagkiozis
382//
383// This file is part of PCGSharp.
384//
385// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
386// and associated documentation files (the "Software"), to deal in the Software without restriction,
387// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
388// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
389// subject to the following conditions:
390//
391//  The above copyright notice and this permission notice shall be included in all copies or substantial
392//  portions of the Software.
393//
394//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
395//  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
396//  NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
397//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
398//  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
399//
400
401  internal static class PcgSeed {
402
403    /// <summary>
404    /// Provides a time-dependent seed value, matching the default behavior of System.Random.
405    /// </summary>
406    public static ulong TimeBasedSeed() {
407      return (ulong)(System.Environment.TickCount);
408    }
409
410    /// <summary>
411    /// Provides a seed based on time and unique GUIDs.
412    /// </summary>
413    public static ulong GuidBasedSeed() {
414      ulong upper = (ulong)(System.Environment.TickCount ^ Guid.NewGuid().GetHashCode()) << 32;
415      ulong lower = (ulong)(System.Environment.TickCount ^ Guid.NewGuid().GetHashCode());
416      return (upper | lower);
417    }
418
419  }
420}
Note: See TracBrowser for help on using the repository browser.