forked from Agorath/ChummerGenSR4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
clsMTRNG.cs
172 lines (142 loc) · 4.64 KB
/
clsMTRNG.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//Using
using System;
using System.Security.Cryptography;
namespace Chummer
{
class MTRNG
{
private const int N = 624;
private const int M = 397;
private const uint MATRIX_A = 0x9908b0df;
private const uint UPPER_MASK = 0x80000000;
private const uint LOWER_MASK = 0x7fffffff;
private const uint TEMPERING_MASK_B = 0x9d2c5680;
private const uint TEMPERING_MASK_C = 0xefc60000;
private static uint TEMPERING_SHIFT_U(uint y) { return (y >> 11); }
private static uint TEMPERING_SHIFT_S(uint y) { return (y << 7); }
private static uint TEMPERING_SHIFT_T(uint y) { return (y << 15); }
private static uint TEMPERING_SHIFT_L(uint y) { return (y >> 18); }
private uint[] mt = new uint[N];
private short mti;
private static uint[] mag01 = { 0x0, MATRIX_A };
public uint usedSeed;
public MTRNG()
{
RNGCryptoServiceProvider rngcsp = new RNGCryptoServiceProvider();
byte[] bytes = new byte[4];
rngcsp.GetBytes(bytes);
usedSeed = BitConverter.ToUInt32(bytes,0);
mt[0] = usedSeed & 0xffffffffU;
for (mti = 1; mti < N; ++mti)
{
mt[mti] = (69069 * mt[mti - 1]) & 0xffffffffU;
}
}
public MTRNG(uint seed)
{
if (seed == 0)
{
RNGCryptoServiceProvider rngcsp = new RNGCryptoServiceProvider();
byte[] bytes = new byte[4];
rngcsp.GetBytes(bytes);
usedSeed = BitConverter.ToUInt32(bytes, 0);
}
usedSeed = seed;
mt[0] = usedSeed & 0xffffffffU;
for (mti = 1; mti < N; ++mti)
{
mt[mti] = (69069 * mt[mti - 1]) & 0xffffffffU;
}
}
protected uint GenerateUInt()
{
uint y;
if (mti >= N)
{
short kk = 0;
for (; kk < N - M; ++kk)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1];
}
for (; kk < N - 1; ++kk)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1];
}
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1];
mti = 0;
}
y = mt[mti++];
y ^= TEMPERING_SHIFT_U(y);
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
y ^= TEMPERING_SHIFT_L(y);
return y;
}
public virtual uint NextUInt()
{
return this.GenerateUInt();
}
public virtual uint NextUInt(uint maxValue)
{
return (uint)(this.GenerateUInt() / ((double)uint.MaxValue / maxValue));
}
public virtual uint NextUInt(uint minValue, uint maxValue)
{
if (minValue >= maxValue)
{
throw new ArgumentOutOfRangeException();
}
return (uint)(this.GenerateUInt() / ((double)uint.MaxValue / (maxValue - minValue)) + minValue);
}
public int Next()
{
return this.Next(int.MaxValue);
}
public int Next(int maxValue)
{
if (maxValue <= 1)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException();
}
return 0;
}
return (int)(this.NextDouble() * maxValue);
}
public int Next(int minValue, int maxValue)
{
if (maxValue < minValue)
{
throw new ArgumentOutOfRangeException();
}
else if (maxValue == minValue)
{
return minValue;
}
else
{
return this.Next(maxValue - minValue) + minValue;
}
}
public void NextBytes(byte[] buffer)
{
int bufLen = buffer.Length;
if (buffer == null)
{
throw new ArgumentNullException();
}
for (int idx = 0; idx < bufLen; ++idx)
{
buffer[idx] = (byte)this.Next(256);
}
}
public double NextDouble()
{
return (double)this.GenerateUInt() / ((ulong)uint.MaxValue + 1);
}
}
}