163 lines
4.7 KiB
C
163 lines
4.7 KiB
C
/**
|
|
* 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 <stdint.h>
|
|
#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;
|
|
}
|