1
|
/*
|
2
|
Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
|
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
of this software and associated documentation files (the "Software"), to deal
|
5
|
in the Software without restriction, including without limitation the rights
|
6
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
copies of the Software, and to permit persons to whom the Software is
|
8
|
furnished to do so, subject to the following conditions:
|
9
|
|
10
|
The above copyright notice and this permission notice shall be included in
|
11
|
all copies or substantial portions of the Software.
|
12
|
|
13
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
SOFTWARE.
|
20
|
*/
|
21
|
using System;
|
22
|
using System.Diagnostics;
|
23
|
using SCG = System.Collections.Generic;
|
24
|
namespace C5
|
25
|
{
|
26
|
/// <summary>
|
27
|
/// A modern random number generator based on G. Marsaglia:
|
28
|
/// Seeds for Random Number Generators, Communications of the
|
29
|
/// ACM 46, 5 (May 2003) 90-93; and a posting by Marsaglia to
|
30
|
/// comp.lang.c on 2003-04-03.
|
31
|
/// </summary>
|
32
|
public class C5Random : Random
|
33
|
{
|
34
|
private uint[] Q = new uint[16];
|
35
|
|
36
|
private uint c = 362436, i = 15;
|
37
|
|
38
|
|
39
|
private uint Cmwc()
|
40
|
{
|
41
|
ulong t, a = 487198574UL;
|
42
|
uint x, r = 0xfffffffe;
|
43
|
|
44
|
i = (i + 1) & 15;
|
45
|
t = a * Q[i] + c;
|
46
|
c = (uint)(t >> 32);
|
47
|
x = (uint)(t + c);
|
48
|
if (x < c)
|
49
|
{
|
50
|
x++;
|
51
|
c++;
|
52
|
}
|
53
|
|
54
|
return Q[i] = r - x;
|
55
|
}
|
56
|
|
57
|
|
58
|
/// <summary>
|
59
|
/// Get a new random System.Double value
|
60
|
/// </summary>
|
61
|
/// <returns>The random double</returns>
|
62
|
public override double NextDouble()
|
63
|
{
|
64
|
return Cmwc() / 4294967296.0;
|
65
|
}
|
66
|
|
67
|
|
68
|
/// <summary>
|
69
|
/// Get a new random System.Double value
|
70
|
/// </summary>
|
71
|
/// <returns>The random double</returns>
|
72
|
protected override double Sample()
|
73
|
{
|
74
|
return NextDouble();
|
75
|
}
|
76
|
|
77
|
|
78
|
/// <summary>
|
79
|
/// Get a new random System.Int32 value
|
80
|
/// </summary>
|
81
|
/// <returns>The random int</returns>
|
82
|
public override int Next()
|
83
|
{
|
84
|
return (int)Cmwc();
|
85
|
}
|
86
|
|
87
|
|
88
|
/// <summary>
|
89
|
/// Get a random non-negative integer less than a given upper bound
|
90
|
/// </summary>
|
91
|
/// <exception cref="ArgumentException">If max is negative</exception>
|
92
|
/// <param name="max">The upper bound (exclusive)</param>
|
93
|
/// <returns></returns>
|
94
|
public override int Next(int max)
|
95
|
{
|
96
|
if (max < 0)
|
97
|
throw new ArgumentException("max must be non-negative");
|
98
|
|
99
|
return (int)(Cmwc() / 4294967296.0 * max);
|
100
|
}
|
101
|
|
102
|
|
103
|
/// <summary>
|
104
|
/// Get a random integer between two given bounds
|
105
|
/// </summary>
|
106
|
/// <exception cref="ArgumentException">If max is less than min</exception>
|
107
|
/// <param name="min">The lower bound (inclusive)</param>
|
108
|
/// <param name="max">The upper bound (exclusive)</param>
|
109
|
/// <returns></returns>
|
110
|
public override int Next(int min, int max)
|
111
|
{
|
112
|
if (min > max)
|
113
|
throw new ArgumentException("min must be less than or equal to max");
|
114
|
|
115
|
return min + (int)(Cmwc() / 4294967296.0 * (max - min));
|
116
|
}
|
117
|
|
118
|
/// <summary>
|
119
|
/// Fill a array of byte with random bytes
|
120
|
/// </summary>
|
121
|
/// <param name="buffer">The array to fill</param>
|
122
|
public override void NextBytes(byte[] buffer)
|
123
|
{
|
124
|
for (int i = 0, length = buffer.Length; i < length; i++)
|
125
|
buffer[i] = (byte)Cmwc();
|
126
|
}
|
127
|
|
128
|
|
129
|
/// <summary>
|
130
|
/// Create a random number generator seed by system time.
|
131
|
/// </summary>
|
132
|
public C5Random() : this(DateTime.Now.Ticks)
|
133
|
{
|
134
|
}
|
135
|
|
136
|
|
137
|
/// <summary>
|
138
|
/// Create a random number generator with a given seed
|
139
|
/// </summary>
|
140
|
/// <exception cref="ArgumentException">If seed is zero</exception>
|
141
|
/// <param name="seed">The seed</param>
|
142
|
public C5Random(long seed)
|
143
|
{
|
144
|
if (seed == 0)
|
145
|
throw new ArgumentException("Seed must be non-zero");
|
146
|
|
147
|
uint j = (uint)(seed & 0xFFFFFFFF);
|
148
|
|
149
|
for (int i = 0; i < 16; i++)
|
150
|
{
|
151
|
j ^= j << 13;
|
152
|
j ^= j >> 17;
|
153
|
j ^= j << 5;
|
154
|
Q[i] = j;
|
155
|
}
|
156
|
|
157
|
Q[15] = (uint)(seed ^ (seed >> 32));
|
158
|
}
|
159
|
|
160
|
/// <summary>
|
161
|
/// Create a random number generator with a specified internal start state.
|
162
|
/// </summary>
|
163
|
/// <exception cref="ArgumentException">If Q is not of length exactly 16</exception>
|
164
|
/// <param name="Q">The start state. Must be a collection of random bits given by an array of exactly 16 uints.</param>
|
165
|
[CLSCompliant(false)]
|
166
|
public C5Random(uint[] Q)
|
167
|
{
|
168
|
if (Q.Length != 16)
|
169
|
throw new ArgumentException("Q must have length 16, was " + Q.Length);
|
170
|
Array.Copy(Q, this.Q, 16);
|
171
|
}
|
172
|
}
|
173
|
}
|