/** * Tiny Mersenne Twister: only 127-bit internal state. * Derived from the reference implementation version 1.1 (2015/04/24) * by Mutsuo Saito (Hiroshima University) and Makoto Matsumoto * (Hiroshima University). */ #include #include "rand.h" static void tinymt32_next_state(tinymt32_t *s); static uint32_t tinymt32_temper(tinymt32_t *s); tinymt32_t tinymt32_s; /** * Parameter set to use for this IETF specification. Don't change. * This parameter set is the first entry of the precalculated * parameter sets in tinymt32dc/tinymt32dc.0.1048576.txt by * Kenji Rikitake, available at: * https://github.com/jj1bdx/tinymtdc-longbatch/. * It is also the parameter set used in: * Rikitake, K., "TinyMT pseudo random number generator for * Erlang", Proceedings of the 11th ACM SIGPLAN Erlang Workshop, * September 2012. */ const uint32_t TINYMT32_MAT1_PARAM = UINT32_C(0x8f7011ee); const uint32_t TINYMT32_MAT2_PARAM = UINT32_C(0xfc78ff1f); const uint32_t TINYMT32_TMAT_PARAM = UINT32_C(0x3793fdff); /** * This function initializes the internal state array with a * 32-bit unsigned integer seed. * @param s pointer to tinymt internal state. * @param seed a 32-bit unsigned integer used as a seed. */ void tinymt32_init (tinymt32_t* s, uint32_t seed) { const uint32_t MIN_LOOP = 8; const uint32_t PRE_LOOP = 8; s->status[0] = seed; s->status[1] = s->mat1 = TINYMT32_MAT1_PARAM; s->status[2] = s->mat2 = TINYMT32_MAT2_PARAM; s->status[3] = s->tmat = TINYMT32_TMAT_PARAM; for (int i = 1; i < MIN_LOOP; i++) { s->status[i & 3] ^= i + UINT32_C(1812433253) * (s->status[(i - 1) & 3] ^ (s->status[(i - 1) & 3] >> 30)); } /* * NB: The parameter set of this specification warrants * that none of the possible 2^^32 seeds leads to an * all-zero 127-bit internal state. Therefore, the * period_certification() function of the original * TinyMT32 source code has been safely removed. If * another parameter set is used, this function will * have to be reintroduced here. */ for (int i = 0; i < PRE_LOOP; i++) { tinymt32_next_state(s); } } /** * This function outputs a 32-bit unsigned integer from * the internal state. * @param s pointer to tinymt internal state. * @return 32-bit unsigned integer r (0 <= r < 2^32). */ uint32_t tinymt32_get_uint32(tinymt32_t* s) { tinymt32_next_state(s); return tinymt32_temper(s); } /** * Internal tinymt32 constants and functions. * Users should not call these functions directly. */ const uint32_t TINYMT32_SH0 = 1; const uint32_t TINYMT32_SH1 = 10; const uint32_t TINYMT32_SH8 = 8; const uint32_t TINYMT32_MASK = UINT32_C(0x7fffffff); /** * This function changes the internal state of tinymt32. * @param s pointer to tinymt internal state. */ static void tinymt32_next_state (tinymt32_t* s) { uint32_t x; uint32_t y; y = s->status[3]; x = (s->status[0] & TINYMT32_MASK) ^ s->status[1] ^ s->status[2]; x ^= (x << TINYMT32_SH0); y ^= (y >> TINYMT32_SH0) ^ x; s->status[0] = s->status[1]; s->status[1] = s->status[2]; s->status[2] = x ^ (y << TINYMT32_SH1); s->status[3] = y; /* * The if (y & 1) {...} block below replaces: * s->status[1] ^= -((int32_t)(y & 1)) & s->mat1; * s->status[2] ^= -((int32_t)(y & 1)) & s->mat2; * The adopted code is equivalent to the original code * but does not depend on the representation of negative * integers by 2's complements. It is therefore more * portable but includes an if branch, which may slow * down the generation speed. */ if (y & 1) { s->status[1] ^= s->mat1; s->status[2] ^= s->mat2; } } /** * This function outputs a 32-bit unsigned integer from * the internal state. * @param s pointer to tinymt internal state. * @return 32-bit unsigned pseudorandom number. */ static uint32_t tinymt32_temper (tinymt32_t* s) { uint32_t t0, t1; t0 = s->status[3]; t1 = s->status[0] + (s->status[2] >> TINYMT32_SH8); t0 ^= t1; /* * The if (t1 & 1) {...} block below replaces: * t0 ^= -((int32_t)(t1 & 1)) & s->tmat; * The adopted code is equivalent to the original code * but does not depend on the representation of negative * integers by 2's complements. It is therefore more * portable but includes an if branch, which may slow * down the generation speed. */ if (t1 & 1) { t0 ^= s->tmat; } return t0; } uint16_t prng_scale16(uint16_t min, uint16_t max) { uint16_t rnd; rnd = prng_get16(); rnd *= (max - min); rnd >>= 16; rnd += min; return rnd; }