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 &copy);
43     Mersenne &operator=(const Mersenne &copy);
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 &copy)
84 {
85     *this = copy;
86 }
87 inline Mersenne &Mersenne::operator=(const Mersenne &copy)
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