alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
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)
59extern "C" {
60#endif
61
62/**
63 * tinymt32 internal state vector and parameters
64 */
65struct TINYMT32_T {
66 uint32_t status[4];
67 uint32_t mat1;
68 uint32_t mat2;
69 uint32_t tmat;
70};
71
72typedef struct TINYMT32_T tinymt32_t;
73
74inline void tinymt32_init(tinymt32_t * random, uint32_t seed);
75inline 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 */
84inline static int tinymt32_get_mexp(
85 tinymt32_t * random __attribute__((unused))) {
86 return TINYMT32_MEXP;
87}
88#else
89inline 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 */
99inline 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 */
125inline 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 */
148inline 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 */
178inline 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 */
207inline 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 */
220inline 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 */
231inline 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 */
242inline 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 */
253inline 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 */
264inline 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 */
277inline 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 */
295static 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 */
305static 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 */
313static 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 */
331void 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 */
354void 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