alpaka
Abstraction Library for Parallel Kernel Acceleration
tinymt32.h
Go to the documentation of this file.
1 /* Copyright 2011 - 2023 Mutsuo Saito, Makoto Matsumoto, Axel Hübl, Benjamin Worpitz, Bernhard Manfred Gruber
2  * SPDX-License-Identifier: BSD-3-Clause
3  */
4 // clang-format off
5 #ifndef TINYMT32_H
6 #define TINYMT32_H
7 /**
8  * @file tinymt32.h
9  *
10  * @brief Tiny Mersenne Twister only 127 bit internal state
11  *
12  * @author Mutsuo Saito (Hiroshima University)
13  * @author Makoto Matsumoto (University of Tokyo)
14  *
15  * Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto,
16  * Hiroshima University and The University of Tokyo.
17  * All rights reserved.
18  *
19  * The 3-clause BSD License is applied to this software, see
20  * LICENSE.txt
21  */
22 
24 
25 #include <cstdint>
26 /* work-around for glibc < 2.18 according to bug
27  * https://sourceware.org/bugzilla/show_bug.cgi?id=15366
28  */
29 #ifndef UINT32_MAX
30 # define UINT32_MAX ((uint32_t)-1u)
31 #endif
32 #ifndef UINT32_C
33 # define UINT32_C(value) uint_least32_t(value)
34 #endif
35 #include <cinttypes>
36 
37 #if BOOST_COMP_CLANG
38 # pragma clang diagnostic push
39 # pragma clang diagnostic ignored "-Wold-style-cast"
40 # pragma clang diagnostic ignored "-Wunused-function"
41 #endif
42 #if BOOST_COMP_GNUC
43 # pragma GCC diagnostic push
44 # pragma GCC diagnostic ignored "-Wold-style-cast"
45 #endif
46 #if BOOST_COMP_MSVC || defined(BOOST_COMP_MSVC_EMULATED)
47  #pragma warning(push)
48  #pragma warning(disable: 4100) // tinymt32.h(60): warning C4100: 'random': unreferenced formal parameter
49 #endif
50 
51 #define TINYMT32_MEXP 127
52 #define TINYMT32_SH0 1
53 #define TINYMT32_SH1 10
54 #define TINYMT32_SH8 8
55 #define TINYMT32_MASK UINT32_C(0x7fffffff)
56 #define TINYMT32_MUL (1.0f / 16777216.0f)
57 
58 #if defined(__cplusplus)
59 extern "C" {
60 #endif
61 
62 /**
63  * tinymt32 internal state vector and parameters
64  */
65 struct TINYMT32_T {
66  uint32_t status[4];
67  uint32_t mat1;
68  uint32_t mat2;
69  uint32_t tmat;
70 };
71 
72 typedef struct TINYMT32_T tinymt32_t;
73 
74 inline void tinymt32_init(tinymt32_t * random, uint32_t seed);
75 inline void tinymt32_init_by_array(tinymt32_t * random, uint32_t init_key[],
76  int key_length);
77 
78 #if defined(__GNUC__)
79 /**
80  * This function always returns 127
81  * @param random not used
82  * @return always 127
83  */
84 inline static int tinymt32_get_mexp(
85  tinymt32_t * random __attribute__((unused))) {
86  return TINYMT32_MEXP;
87 }
88 #else
89 inline static int tinymt32_get_mexp(tinymt32_t * random) {
90  return TINYMT32_MEXP;
91 }
92 #endif
93 
94 /**
95  * This function changes internal state of tinymt32.
96  * Users should not call this function directly.
97  * @param random tinymt internal status
98  */
99 inline static void tinymt32_next_state(tinymt32_t * random) {
100  uint32_t x;
101  uint32_t y;
102 
103  y = random->status[3];
104  x = (random->status[0] & TINYMT32_MASK)
105  ^ random->status[1]
106  ^ random->status[2];
107  x ^= (x << TINYMT32_SH0);
108  y ^= (y >> TINYMT32_SH0) ^ x;
109  random->status[0] = random->status[1];
110  random->status[1] = random->status[2];
111  random->status[2] = x ^ (y << TINYMT32_SH1);
112  random->status[3] = y;
113  int32_t const a = -((int32_t)(y & 1)) & (int32_t)random->mat1;
114  int32_t const b = -((int32_t)(y & 1)) & (int32_t)random->mat2;
115  random->status[1] ^= (uint32_t)a;
116  random->status[2] ^= (uint32_t)b;
117 }
118 
119 /**
120  * This function outputs 32-bit unsigned integer from internal state.
121  * Users should not call this function directly.
122  * @param random tinymt internal status
123  * @return 32-bit unsigned pseudorandom number
124  */
125 inline static uint32_t tinymt32_temper(tinymt32_t * random) {
126  uint32_t t0, t1;
127  t0 = random->status[3];
128 #if defined(LINEARITY_CHECK)
129  t1 = random->status[0]
130  ^ (random->status[2] >> TINYMT32_SH8);
131 #else
132  t1 = random->status[0]
133  + (random->status[2] >> TINYMT32_SH8);
134 #endif
135  t0 ^= t1;
136  if ((t1 & 1) != 0) {
137  t0 ^= random->tmat;
138  }
139  return t0;
140 }
141 
142 /**
143  * This function outputs floating point number from internal state.
144  * Users should not call this function directly.
145  * @param random tinymt internal status
146  * @return floating point number r (1.0 <= r < 2.0)
147  */
148 inline static float tinymt32_temper_conv(tinymt32_t * random) {
149  uint32_t t0, t1;
150  union {
151  uint32_t u;
152  float f;
153  } conv;
154 
155  t0 = random->status[3];
156 #if defined(LINEARITY_CHECK)
157  t1 = random->status[0]
158  ^ (random->status[2] >> TINYMT32_SH8);
159 #else
160  t1 = random->status[0]
161  + (random->status[2] >> TINYMT32_SH8);
162 #endif
163  t0 ^= t1;
164  if ((t1 & 1) != 0) {
165  conv.u = ((t0 ^ random->tmat) >> 9) | UINT32_C(0x3f800000);
166  } else {
167  conv.u = (t0 >> 9) | UINT32_C(0x3f800000);
168  }
169  return conv.f;
170 }
171 
172 /**
173  * This function outputs floating point number from internal state.
174  * Users should not call this function directly.
175  * @param random tinymt internal status
176  * @return floating point number r (1.0 < r < 2.0)
177  */
178 inline static float tinymt32_temper_conv_open(tinymt32_t * random) {
179  uint32_t t0, t1;
180  union {
181  uint32_t u;
182  float f;
183  } conv;
184 
185  t0 = random->status[3];
186 #if defined(LINEARITY_CHECK)
187  t1 = random->status[0]
188  ^ (random->status[2] >> TINYMT32_SH8);
189 #else
190  t1 = random->status[0]
191  + (random->status[2] >> TINYMT32_SH8);
192 #endif
193  t0 ^= t1;
194  if ((t1 & 1) != 0) {
195  conv.u = ((t0 ^ random->tmat) >> 9) | UINT32_C(0x3f800001);
196  } else {
197  conv.u = (t0 >> 9) | UINT32_C(0x3f800001);
198  }
199  return conv.f;
200 }
201 
202 /**
203  * This function outputs 32-bit unsigned integer from internal state.
204  * @param random tinymt internal status
205  * @return 32-bit unsigned integer r (0 <= r < 2^32)
206  */
207 inline static uint32_t tinymt32_generate_uint32(tinymt32_t * random) {
208  tinymt32_next_state(random);
209  return tinymt32_temper(random);
210 }
211 
212 /**
213  * This function outputs floating point number from internal state.
214  * This function is implemented using multiplying by (1 / 2^24).
215  * floating point multiplication is faster than using union trick in
216  * my Intel CPU.
217  * @param random tinymt internal status
218  * @return floating point number r (0.0 <= r < 1.0)
219  */
220 inline static float tinymt32_generate_float(tinymt32_t * random) {
221  tinymt32_next_state(random);
222  return (float)(tinymt32_temper(random) >> 8) * TINYMT32_MUL;
223 }
224 
225 /**
226  * This function outputs floating point number from internal state.
227  * This function is implemented using union trick.
228  * @param random tinymt internal status
229  * @return floating point number r (1.0 <= r < 2.0)
230  */
231 inline static float tinymt32_generate_float12(tinymt32_t * random) {
232  tinymt32_next_state(random);
233  return tinymt32_temper_conv(random);
234 }
235 
236 /**
237  * This function outputs floating point number from internal state.
238  * This function is implemented using union trick.
239  * @param random tinymt internal status
240  * @return floating point number r (0.0 <= r < 1.0)
241  */
242 inline static float tinymt32_generate_float01(tinymt32_t * random) {
243  tinymt32_next_state(random);
244  return tinymt32_temper_conv(random) - 1.0f;
245 }
246 
247 /**
248  * This function outputs floating point number from internal state.
249  * This function may return 1.0 and never returns 0.0.
250  * @param random tinymt internal status
251  * @return floating point number r (0.0 < r <= 1.0)
252  */
253 inline static float tinymt32_generate_floatOC(tinymt32_t * random) {
254  tinymt32_next_state(random);
255  return 1.0f - tinymt32_generate_float(random);
256 }
257 
258 /**
259  * This function outputs floating point number from internal state.
260  * This function returns neither 0.0 nor 1.0.
261  * @param random tinymt internal status
262  * @return floating point number r (0.0 < r < 1.0)
263  */
264 inline static float tinymt32_generate_floatOO(tinymt32_t * random) {
265  tinymt32_next_state(random);
266  return tinymt32_temper_conv_open(random) - 1.0f;
267 }
268 
269 /**
270  * This function outputs double precision floating point number from
271  * internal state. The returned value has 32-bit precision.
272  * In other words, this function makes one double precision floating point
273  * number from one 32-bit unsigned integer.
274  * @param random tinymt internal status
275  * @return floating point number r (0.0 <= r < 1.0)
276  */
277 inline static double tinymt32_generate_32double(tinymt32_t * random) {
278  tinymt32_next_state(random);
279  return tinymt32_temper(random) * (1.0 / 4294967296.0);
280 }
281 
282 #if defined(__cplusplus)
283 }
284 #endif
285 
286 #define MIN_LOOP 8
287 #define PRE_LOOP 8
288 
289 /**
290  * This function represents a function used in the initialization
291  * by init_by_array
292  * @param x 32-bit integer
293  * @return 32-bit integer
294  */
295 static uint32_t ini_func1(uint32_t x) {
296  return (x ^ (x >> 27)) * UINT32_C(1664525);
297 }
298 
299 /**
300  * This function represents a function used in the initialization
301  * by init_by_array
302  * @param x 32-bit integer
303  * @return 32-bit integer
304  */
305 static uint32_t ini_func2(uint32_t x) {
306  return (x ^ (x >> 27)) * UINT32_C(1566083941);
307 }
308 
309 /**
310  * This function certificate the period of 2^127-1.
311  * @param random tinymt state vector.
312  */
313 static void period_certification(tinymt32_t * random) {
314  if ((random->status[0] & TINYMT32_MASK) == 0 &&
315  random->status[1] == 0 &&
316  random->status[2] == 0 &&
317  random->status[3] == 0) {
318  random->status[0] = 'T';
319  random->status[1] = 'I';
320  random->status[2] = 'N';
321  random->status[3] = 'Y';
322  }
323 }
324 
325 /**
326  * This function initializes the internal state array with a 32-bit
327  * unsigned integer seed.
328  * @param random tinymt state vector.
329  * @param seed a 32-bit unsigned integer used as a seed.
330  */
331 void tinymt32_init(tinymt32_t * random, uint32_t seed) {
332  random->status[0] = seed;
333  random->status[1] = random->mat1;
334  random->status[2] = random->mat2;
335  random->status[3] = random->tmat;
336  for (unsigned int i = 1; i < MIN_LOOP; i++) {
337  random->status[i & 3] ^= i + UINT32_C(1812433253)
338  * (random->status[(i - 1) & 3]
339  ^ (random->status[(i - 1) & 3] >> 30));
340  }
341  period_certification(random);
342  for (unsigned int i = 0; i < PRE_LOOP; i++) {
343  tinymt32_next_state(random);
344  }
345 }
346 
347 /**
348  * This function initializes the internal state array,
349  * with an array of 32-bit unsigned integers used as seeds
350  * @param random tinymt state vector.
351  * @param init_key the array of 32-bit integers, used as a seed.
352  * @param key_length the length of init_key.
353  */
354 void tinymt32_init_by_array(tinymt32_t * random, uint32_t init_key[],
355  int key_length) {
356  const unsigned int lag = 1;
357  const unsigned int mid = 1;
358  const unsigned int size = 4;
359  unsigned int i, j;
360  unsigned int count;
361  uint32_t r;
362  uint32_t * st = &random->status[0];
363 
364  st[0] = 0;
365  st[1] = random->mat1;
366  st[2] = random->mat2;
367  st[3] = random->tmat;
368  if (key_length + 1 > MIN_LOOP) {
369  count = (unsigned int)key_length + 1;
370  } else {
371  count = MIN_LOOP;
372  }
373  r = ini_func1(st[0] ^ st[mid % size]
374  ^ st[(size - 1) % size]);
375  st[mid % size] += r;
376  r += (unsigned int)key_length;
377  st[(mid + lag) % size] += r;
378  st[0] = r;
379  count--;
380  for (i = 1, j = 0; (j < count) && (j < (unsigned int)key_length); j++) {
381  r = ini_func1(st[i % size]
382  ^ st[(i + mid) % size]
383  ^ st[(i + size - 1) % size]);
384  st[(i + mid) % size] += r;
385  r += init_key[j] + i;
386  st[(i + mid + lag) % size] += r;
387  st[i % size] = r;
388  i = (i + 1) % size;
389  }
390  for (; j < count; j++) {
391  r = ini_func1(st[i % size]
392  ^ st[(i + mid) % size]
393  ^ st[(i + size - 1) % size]);
394  st[(i + mid) % size] += r;
395  r += i;
396  st[(i + mid + lag) % size] += r;
397  st[i % size] = r;
398  i = (i + 1) % size;
399  }
400  for (j = 0; j < size; j++) {
401  r = ini_func2(st[i % size]
402  + st[(i + mid) % size]
403  + st[(i + size - 1) % size]);
404  st[(i + mid) % size] ^= r;
405  r -= i;
406  st[(i + mid + lag) % size] ^= r;
407  st[i % size] = r;
408  i = (i + 1) % size;
409  }
410  period_certification(random);
411  for (i = 0; i < PRE_LOOP; i++) {
412  tinymt32_next_state(random);
413  }
414 }
415 
416 #undef MIN_LOOP
417 #undef PRE_LOOP
418 
419 #if BOOST_COMP_CLANG
420 # pragma clang diagnostic pop
421 #endif
422 #if BOOST_COMP_GNUC
423 # pragma GCC diagnostic pop
424 #endif
425 #if BOOST_COMP_MSVC || defined(BOOST_COMP_MSVC_EMULATED)
426 # pragma warning(pop)
427 #endif
428 
429 #endif
uint32_t tmat
Definition: tinymt32.h:69
uint32_t status[4]
Definition: tinymt32.h:66
uint32_t mat2
Definition: tinymt32.h:68
uint32_t mat1
Definition: tinymt32.h:67
void tinymt32_init(tinymt32_t *random, uint32_t seed)
Definition: tinymt32.h:331
void tinymt32_init_by_array(tinymt32_t *random, uint32_t init_key[], int key_length)
Definition: tinymt32.h:354
#define TINYMT32_SH0
Definition: tinymt32.h:52
static uint32_t tinymt32_temper(tinymt32_t *random)
Definition: tinymt32.h:125
static double tinymt32_generate_32double(tinymt32_t *random)
Definition: tinymt32.h:277
#define PRE_LOOP
Definition: tinymt32.h:287
static float tinymt32_generate_float01(tinymt32_t *random)
Definition: tinymt32.h:242
static uint32_t ini_func2(uint32_t x)
Definition: tinymt32.h:305
static float tinymt32_temper_conv_open(tinymt32_t *random)
Definition: tinymt32.h:178
static void tinymt32_next_state(tinymt32_t *random)
Definition: tinymt32.h:99
static uint32_t tinymt32_generate_uint32(tinymt32_t *random)
Definition: tinymt32.h:207
#define TINYMT32_MUL
Definition: tinymt32.h:56
#define TINYMT32_SH8
Definition: tinymt32.h:54
static float tinymt32_generate_float12(tinymt32_t *random)
Definition: tinymt32.h:231
static int tinymt32_get_mexp(tinymt32_t *random)
Definition: tinymt32.h:89
#define TINYMT32_MEXP
Definition: tinymt32.h:51
#define TINYMT32_MASK
Definition: tinymt32.h:55
#define UINT32_C(value)
Definition: tinymt32.h:33
#define MIN_LOOP
Definition: tinymt32.h:286
#define TINYMT32_SH1
Definition: tinymt32.h:53
static float tinymt32_generate_floatOO(tinymt32_t *random)
Definition: tinymt32.h:264
static float tinymt32_generate_floatOC(tinymt32_t *random)
Definition: tinymt32.h:253
static float tinymt32_generate_float(tinymt32_t *random)
Definition: tinymt32.h:220
static float tinymt32_temper_conv(tinymt32_t *random)
Definition: tinymt32.h:148
static uint32_t ini_func1(uint32_t x)
Definition: tinymt32.h:295
static void period_certification(tinymt32_t *random)
Definition: tinymt32.h:313