1 /******************************************
2 Copyright (c) 2019, Shaowei Cai
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 ***********************************************/
22
23 #ifndef CCNR_MERSENNE_H
24 #define CCNR_MERSENNE_H
25
26 namespace CCNR {
27
28 class Mersenne
29 {
30 static const int N = 624;
31 unsigned int mt[N];
32 int mti;
33 const int M = 397;
34 const unsigned int MATRIX_A = 0x9908b0dfUL;
35 const unsigned int UPPER_MASK = 0x80000000UL;
36 const unsigned int LOWER_MASK = 0x7fffffffUL;
37
38 public:
39 Mersenne(); // seed with time-dependent value
40 Mersenne(int seed); // seed with int value; see comments for the seed() method
41 Mersenne(unsigned int *array, int count); // seed with array
42 Mersenne(const Mersenne ©);
43 Mersenne &operator=(const Mersenne ©);
44 void seed(int s);
45 void seed(unsigned int *array, int len);
46 unsigned int next32(); // generates random integer in [0..2^32-1]
47 int next31(); // generates random integer in [0..2^31-1]
48 double nextClosed(); // generates random float in [0..1], 2^53 possible values
49 double nextHalfOpen(); // generates random float in [0..1), 2^53 possible values
50 double nextOpen(); // generates random float in (0..1), 2^53 possible values
51 int next(int bound); // generates random integer in [0..bound), bound < 2^31
52 };
53
54 //---------------------------
55 //functions in mersenne.h & mersenne.cpp
56
57 /*
58 Notes on seeding
59
60 1. Seeding with an integer
61 To avoid different seeds mapping to the same sequence, follow one of
62 the following two conventions:
63 a) Only use seeds in 0..2^31-1 (preferred)
64 b) Only use seeds in -2^30..2^30-1 (2-complement machines only)
65
66 2. Seeding with an array (die-hard seed method)
67 The length of the array, len, can be arbitrarily high, but for lengths greater
68 than N, collisions are common. If the seed is of high quality, using more than
69 N values does not make sense.
70 */
Mersenne()71 inline Mersenne::Mersenne()
72 {
73 seed(0);
74 }
Mersenne(int s)75 inline Mersenne::Mersenne(int s)
76 {
77 seed(s);
78 }
Mersenne(unsigned int * init_key,int key_length)79 inline Mersenne::Mersenne(unsigned int *init_key, int key_length)
80 {
81 seed(init_key, key_length);
82 }
Mersenne(const Mersenne & copy)83 inline Mersenne::Mersenne(const Mersenne ©)
84 {
85 *this = copy;
86 }
87 inline Mersenne &Mersenne::operator=(const Mersenne ©)
88 {
89 for (int i = 0; i < N; i++)
90 mt[i] = copy.mt[i];
91 mti = copy.mti;
92 return *this;
93 }
seed(int se)94 inline void Mersenne::seed(int se)
95 {
96 unsigned int s = ((unsigned int)(se << 1)) + 1;
97 // Seeds should not be zero. Other possible solutions (such as s |= 1)
98 // lead to more confusion, because often-used low seeds like 2 and 3 would
99 // be identical. This leads to collisions only for rarely used seeds (see
100 // note in header file).
101 mt[0] = s & 0xffffffffUL;
102 for (mti = 1; mti < N; mti++) {
103 mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
104 mt[mti] &= 0xffffffffUL;
105 }
106 }
seed(unsigned int * init_key,int key_length)107 inline void Mersenne::seed(unsigned int *init_key, int key_length)
108 {
109 int i = 1, j = 0, k = (N > key_length ? N : key_length);
110 seed(19650218UL);
111 for (; k; k--) {
112 mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) + init_key[j] + j;
113 mt[i] &= 0xffffffffUL;
114 i++;
115 j++;
116 if (i >= N) {
117 mt[0] = mt[N - 1];
118 i = 1;
119 }
120 if (j >= key_length)
121 j = 0;
122 }
123 for (k = N - 1; k; k--) {
124 mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941UL)) - i;
125 mt[i] &= 0xffffffffUL;
126 i++;
127 if (i >= N) {
128 mt[0] = mt[N - 1];
129 i = 1;
130 }
131 }
132 mt[0] = 0x80000000UL;
133 }
next32()134 inline unsigned int Mersenne::next32()
135 {
136 unsigned int y;
137 static unsigned int mag01[2] = {0x0UL, MATRIX_A};
138 if (mti >= N) {
139 int kk;
140 for (kk = 0; kk < N - M; kk++) {
141 y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
142 mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
143 }
144 for (; kk < N - 1; kk++) {
145 y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
146 mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
147 }
148 y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
149 mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
150 mti = 0;
151 }
152 y = mt[mti++];
153 y ^= (y >> 11);
154 y ^= (y << 7) & 0x9d2c5680UL;
155 y ^= (y << 15) & 0xefc60000UL;
156 y ^= (y >> 18);
157 return y;
158 }
next31()159 inline int Mersenne::next31()
160 {
161 return (int)(next32() >> 1);
162 }
nextClosed()163 inline double Mersenne::nextClosed()
164 {
165 unsigned int a = next32() >> 5, b = next32() >> 6;
166 return (a * 67108864.0 + b) * (1.0 / 9007199254740991.0);
167 }
nextHalfOpen()168 inline double Mersenne::nextHalfOpen()
169 {
170 unsigned int a = next32() >> 5, b = next32() >> 6;
171 return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
172 }
nextOpen()173 inline double Mersenne::nextOpen()
174 {
175 unsigned int a = next32() >> 5, b = next32() >> 6;
176 return (0.5 + a * 67108864.0 + b) * (1.0 / 9007199254740991.0);
177 }
next(int bound)178 inline int Mersenne::next(int bound)
179 {
180 unsigned int value;
181 do {
182 value = next31();
183 } while (value + (unsigned int)bound >= 0x80000000UL);
184 // Just using modulo doesn't lead to uniform distribution. This does.
185 return (int)(value % bound);
186 }
187
188 }
189
190 #endif
191