diff options
author | Marc Sunet <msunet@shellblade.net> | 2022-05-07 08:09:10 -0700 |
---|---|---|
committer | Marc Sunet <msunet@shellblade.net> | 2022-05-07 08:09:10 -0700 |
commit | 344960f7470d7b6e5cb0c0b1d7e751d47063a98c (patch) | |
tree | 138d163f10f8f5c5bb8d5624d5914bc7506da33c /random/src/mt19937-64.c | |
parent | e504a003cf5e88c9440ab49e10792e0e26b96c45 (diff) |
Add random library.
Diffstat (limited to 'random/src/mt19937-64.c')
-rw-r--r-- | random/src/mt19937-64.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/random/src/mt19937-64.c b/random/src/mt19937-64.c new file mode 100644 index 0000000..b6f7be6 --- /dev/null +++ b/random/src/mt19937-64.c | |||
@@ -0,0 +1,183 @@ | |||
1 | // http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/VERSIONS/C-LANG/mt19937-64.c | ||
2 | |||
3 | /* | ||
4 | A C-program for MT19937-64 (2004/9/29 version). | ||
5 | Coded by Takuji Nishimura and Makoto Matsumoto. | ||
6 | |||
7 | This is a 64-bit version of Mersenne Twister pseudorandom number | ||
8 | generator. | ||
9 | |||
10 | Before using, initialize the state by using init_genrand64(seed) | ||
11 | or init_by_array64(init_key, key_length). | ||
12 | |||
13 | Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, | ||
14 | All rights reserved. | ||
15 | |||
16 | Redistribution and use in source and binary forms, with or without | ||
17 | modification, are permitted provided that the following conditions | ||
18 | are met: | ||
19 | |||
20 | 1. Redistributions of source code must retain the above copyright | ||
21 | notice, this list of conditions and the following disclaimer. | ||
22 | |||
23 | 2. Redistributions in binary form must reproduce the above copyright | ||
24 | notice, this list of conditions and the following disclaimer in the | ||
25 | documentation and/or other materials provided with the distribution. | ||
26 | |||
27 | 3. The names of its contributors may not be used to endorse or promote | ||
28 | products derived from this software without specific prior written | ||
29 | permission. | ||
30 | |||
31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
32 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
33 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
34 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
35 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
36 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
37 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
38 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
39 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
40 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
41 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
42 | |||
43 | References: | ||
44 | T. Nishimura, ``Tables of 64-bit Mersenne Twisters'' | ||
45 | ACM Transactions on Modeling and | ||
46 | Computer Simulation 10. (2000) 348--357. | ||
47 | M. Matsumoto and T. Nishimura, | ||
48 | ``Mersenne Twister: a 623-dimensionally equidistributed | ||
49 | uniform pseudorandom number generator'' | ||
50 | ACM Transactions on Modeling and | ||
51 | Computer Simulation 8. (Jan. 1998) 3--30. | ||
52 | |||
53 | Any feedback is very welcome. | ||
54 | http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html | ||
55 | email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces) | ||
56 | */ | ||
57 | |||
58 | /* | ||
59 | Modifications: | ||
60 | |||
61 | - Remove stdio.h and the main() function. | ||
62 | - Replace 'unsigned long long' with 'uint64_t' (include stdint.h). | ||
63 | - Remove the global state and instead store the generator's state in the new | ||
64 | mt19937_64 struct. | ||
65 | - Naming and formatting. | ||
66 | */ | ||
67 | |||
68 | #include <random/mt19937-64.h> | ||
69 | |||
70 | #include <assert.h> | ||
71 | |||
72 | #define NN 312 | ||
73 | #define MM 156 | ||
74 | #define MATRIX_A 0xB5026F5AA96619E9ULL | ||
75 | #define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */ | ||
76 | #define LM 0x7FFFFFFFULL /* Least significant 31 bits */ | ||
77 | |||
78 | mt19937_64 mt19937_64_make() { | ||
79 | mt19937_64 rng; | ||
80 | rng.mti = NN+1; // Not initialized. | ||
81 | return rng; | ||
82 | } | ||
83 | |||
84 | /* initializes mt[NN] with a seed */ | ||
85 | void mt19937_64_init(mt19937_64* rng, uint64_t seed) { | ||
86 | assert(rng); | ||
87 | rng->mt[0] = seed; | ||
88 | for (rng->mti = 1; rng->mti < NN; rng->mti++) { | ||
89 | rng->mt[rng->mti] = | ||
90 | (6364136223846793005ULL * (rng->mt[rng->mti - 1] ^ (rng->mt[rng->mti - 1] >> 62)) + rng->mti); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* initialize by an array with array-length */ | ||
95 | /* init_key is the array for initializing keys */ | ||
96 | /* key_length is its length */ | ||
97 | void mt19937_64_init_by_array64(mt19937_64* rng, uint64_t init_key[], uint64_t key_length) { | ||
98 | assert(rng); | ||
99 | uint64_t i, j, k; | ||
100 | mt19937_64_init(rng, 19650218ULL); | ||
101 | i=1; j=0; | ||
102 | k = (NN>key_length ? NN : key_length); | ||
103 | for (; k; k--) { | ||
104 | rng->mt[i] = (rng->mt[i] ^ ((rng->mt[i-1] ^ (rng->mt[i-1] >> 62)) * 3935559000370003845ULL)) | ||
105 | + init_key[j] + j; /* non linear */ | ||
106 | i++; j++; | ||
107 | if (i>=NN) { rng->mt[0] = rng->mt[NN-1]; i=1; } | ||
108 | if (j>=key_length) j=0; | ||
109 | } | ||
110 | for (k=NN-1; k; k--) { | ||
111 | rng->mt[i] = (rng->mt[i] ^ ((rng->mt[i-1] ^ (rng->mt[i-1] >> 62)) * 2862933555777941757ULL)) | ||
112 | - i; /* non linear */ | ||
113 | i++; | ||
114 | if (i>=NN) { rng->mt[0] = rng->mt[NN-1]; i=1; } | ||
115 | } | ||
116 | |||
117 | rng->mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */ | ||
118 | } | ||
119 | |||
120 | /* generates a random number on [0, 2^64-1]-interval */ | ||
121 | uint64_t mt19937_64_gen64u(mt19937_64* rng) { | ||
122 | assert(rng); | ||
123 | int i; | ||
124 | uint64_t x; | ||
125 | static uint64_t mag01[2]={0ULL, MATRIX_A}; | ||
126 | |||
127 | if (rng->mti >= NN) { /* generate NN words at one time */ | ||
128 | |||
129 | /* if mt19937_64_init() has not been called, */ | ||
130 | /* a default initial seed is used */ | ||
131 | if (rng->mti == NN+1) | ||
132 | mt19937_64_init(rng, 5489ULL); | ||
133 | |||
134 | for (i=0;i<NN-MM;i++) { | ||
135 | x = (rng->mt[i]&UM)|(rng->mt[i+1]&LM); | ||
136 | rng->mt[i] = rng->mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; | ||
137 | } | ||
138 | for (;i<NN-1;i++) { | ||
139 | x = (rng->mt[i]&UM)|(rng->mt[i+1]&LM); | ||
140 | rng->mt[i] = rng->mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; | ||
141 | } | ||
142 | x = (rng->mt[NN-1]&UM)|(rng->mt[0]&LM); | ||
143 | rng->mt[NN-1] = rng->mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; | ||
144 | |||
145 | rng->mti = 0; | ||
146 | } | ||
147 | |||
148 | x = rng->mt[rng->mti++]; | ||
149 | |||
150 | x ^= (x >> 29) & 0x5555555555555555ULL; | ||
151 | x ^= (x << 17) & 0x71D67FFFEDA60000ULL; | ||
152 | x ^= (x << 37) & 0xFFF7EEE000000000ULL; | ||
153 | x ^= (x >> 43); | ||
154 | |||
155 | return x; | ||
156 | } | ||
157 | |||
158 | /* generates a random number on [0, 2^63-1]-interval */ | ||
159 | int64_t mt19937_64_gen64i(mt19937_64* rng) { | ||
160 | return (int64_t)(mt19937_64_gen64u(rng) >> 1); | ||
161 | } | ||
162 | |||
163 | /* generates a random number on [0,1]-real-interval */ | ||
164 | double mt19937_64_gen_real1(mt19937_64* rng) { | ||
165 | return (mt19937_64_gen64u(rng) >> 11) * (1.0/9007199254740991.0); | ||
166 | } | ||
167 | |||
168 | /* generates a random number on [0,1)-real-interval */ | ||
169 | double mt19937_64_gen_real2(mt19937_64* rng) { | ||
170 | return (mt19937_64_gen64u(rng) >> 11) * (1.0/9007199254740992.0); | ||
171 | } | ||
172 | |||
173 | /* generates a random number on (0,1)-real-interval */ | ||
174 | double mt19937_64_gen_real3(mt19937_64* rng) { | ||
175 | return ((mt19937_64_gen64u(rng) >> 12) + 0.5) * (1.0/4503599627370496.0); | ||
176 | } | ||
177 | |||
178 | /* generates a random number on (-1,+1)-real-interval */ | ||
179 | double mt19937_64_gen_real4(mt19937_64* rng) { | ||
180 | const double x01 = mt19937_64_gen_real3(rng); // (0,1) interval. | ||
181 | const double x11 = x01 * 2. - 1.; // (-1, +1) interval. | ||
182 | return x11; | ||
183 | } | ||