dbf-halloween2015

diff src/rng.cc @ 0:50683c78264e

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 01 Nov 2015 00:09:12 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/rng.cc	Sun Nov 01 00:09:12 2015 +0200
     1.3 @@ -0,0 +1,217 @@
     1.4 +#include <stdlib.h>
     1.5 +#include <string.h>
     1.6 +#include "rng.h"
     1.7 +
     1.8 +//#define USE_STD_RAND
     1.9 +
    1.10 +// defined at the end
    1.11 +/**
    1.12 + * tinymt32 internal state vector and parameters
    1.13 + */
    1.14 +struct tinymt32_t {
    1.15 +	uint32_t status[4];
    1.16 +	uint32_t mat1;
    1.17 +	uint32_t mat2;
    1.18 +	uint32_t tmat;
    1.19 +};
    1.20 +
    1.21 +#ifndef USE_STD_RAND
    1.22 +static void tinymt32_init(tinymt32_t * random, uint32_t seed);
    1.23 +inline static uint32_t tinymt32_generate_uint32(tinymt32_t * random);
    1.24 +inline static float tinymt32_generate_float(tinymt32_t * random);
    1.25 +#endif
    1.26 +
    1.27 +static RandGen defrng;
    1.28 +
    1.29 +struct RandGenState {
    1.30 +	tinymt32_t st;
    1.31 +};
    1.32 +
    1.33 +RandGen::RandGen()
    1.34 +{
    1.35 +	state = new RandGenState;
    1.36 +	memset(state, 0, sizeof *state);
    1.37 +#ifndef USE_STD_RAND
    1.38 +	tinymt32_init(&state->st, 0);
    1.39 +#endif
    1.40 +}
    1.41 +
    1.42 +RandGen::~RandGen()
    1.43 +{
    1.44 +	delete state;
    1.45 +}
    1.46 +
    1.47 +void RandGen::seed(uint32_t s)
    1.48 +{
    1.49 +#ifndef USE_STD_RAND
    1.50 +	tinymt32_init(&state->st, s);
    1.51 +#else
    1.52 +	srand(s);
    1.53 +#endif
    1.54 +}
    1.55 +
    1.56 +uint32_t RandGen::generate()
    1.57 +{
    1.58 +#ifndef USE_STD_RAND
    1.59 +	return tinymt32_generate_uint32(&state->st);
    1.60 +#else
    1.61 +	return rand();
    1.62 +#endif
    1.63 +}
    1.64 +
    1.65 +float RandGen::generate_float()
    1.66 +{
    1.67 +#ifndef USE_STD_RAND
    1.68 +	return tinymt32_generate_float(&state->st);
    1.69 +#else
    1.70 +	return (float)rand() / (float)RAND_MAX;
    1.71 +#endif
    1.72 +}
    1.73 +
    1.74 +void rng_srand(uint32_t s)
    1.75 +{
    1.76 +	defrng.seed(s);
    1.77 +}
    1.78 +
    1.79 +uint32_t rng_rand()
    1.80 +{
    1.81 +	return defrng.generate();
    1.82 +}
    1.83 +
    1.84 +float rng_frand()
    1.85 +{
    1.86 +	return defrng.generate_float();
    1.87 +}
    1.88 +
    1.89 +
    1.90 +#ifndef USE_STD_RAND
    1.91 +/**
    1.92 + * @file tinymt32.h
    1.93 + *
    1.94 + * @brief Tiny Mersenne Twister only 127 bit internal state
    1.95 + *
    1.96 + * @author Mutsuo Saito (Hiroshima University)
    1.97 + * @author Makoto Matsumoto (University of Tokyo)
    1.98 + *
    1.99 + * Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto,
   1.100 + * Hiroshima University and The University of Tokyo.
   1.101 + * All rights reserved.
   1.102 + *
   1.103 + * The 3-clause BSD License is applied to this software, see
   1.104 + * LICENSE.txt
   1.105 + */
   1.106 +#define TINYMT32_MEXP 127
   1.107 +#define TINYMT32_SH0 1
   1.108 +#define TINYMT32_SH1 10
   1.109 +#define TINYMT32_SH8 8
   1.110 +#define TINYMT32_MASK UINT32_C(0x7fffffff)
   1.111 +#define TINYMT32_MUL (1.0f / 4294967296.0f)
   1.112 +
   1.113 +/**
   1.114 + * This function changes internal state of tinymt32.
   1.115 + * Users should not call this function directly.
   1.116 + * @param random tinymt internal status
   1.117 + */
   1.118 +inline static void tinymt32_next_state(tinymt32_t * random) {
   1.119 +	uint32_t x;
   1.120 +	uint32_t y;
   1.121 +
   1.122 +	y = random->status[3];
   1.123 +	x = (random->status[0] & TINYMT32_MASK)
   1.124 +		^ random->status[1]
   1.125 +		^ random->status[2];
   1.126 +	x ^= (x << TINYMT32_SH0);
   1.127 +	y ^= (y >> TINYMT32_SH0) ^ x;
   1.128 +	random->status[0] = random->status[1];
   1.129 +	random->status[1] = random->status[2];
   1.130 +	random->status[2] = x ^ (y << TINYMT32_SH1);
   1.131 +	random->status[3] = y;
   1.132 +	random->status[1] ^= -((int32_t)(y & 1)) & random->mat1;
   1.133 +	random->status[2] ^= -((int32_t)(y & 1)) & random->mat2;
   1.134 +}
   1.135 +
   1.136 +/**
   1.137 + * This function outputs 32-bit unsigned integer from internal state.
   1.138 + * Users should not call this function directly.
   1.139 + * @param random tinymt internal status
   1.140 + * @return 32-bit unsigned pseudorandom number
   1.141 + */
   1.142 +inline static uint32_t tinymt32_temper(tinymt32_t * random) {
   1.143 +	uint32_t t0, t1;
   1.144 +	t0 = random->status[3];
   1.145 +#if defined(LINEARITY_CHECK)
   1.146 +	t1 = random->status[0]
   1.147 +		^ (random->status[2] >> TINYMT32_SH8);
   1.148 +#else
   1.149 +	t1 = random->status[0]
   1.150 +		+ (random->status[2] >> TINYMT32_SH8);
   1.151 +#endif
   1.152 +	t0 ^= t1;
   1.153 +	t0 ^= -((int32_t)(t1 & 1)) & random->tmat;
   1.154 +	return t0;
   1.155 +}
   1.156 +
   1.157 +/**
   1.158 + * This function outputs 32-bit unsigned integer from internal state.
   1.159 + * @param random tinymt internal status
   1.160 + * @return 32-bit unsigned integer r (0 <= r < 2^32)
   1.161 + */
   1.162 +inline static uint32_t tinymt32_generate_uint32(tinymt32_t * random) {
   1.163 +	tinymt32_next_state(random);
   1.164 +	return tinymt32_temper(random);
   1.165 +}
   1.166 +
   1.167 +/**
   1.168 + * This function outputs floating point number from internal state.
   1.169 + * This function is implemented using multiplying by 1 / 2^32.
   1.170 + * floating point multiplication is faster than using union trick in
   1.171 + * my Intel CPU.
   1.172 + * @param random tinymt internal status
   1.173 + * @return floating point number r (0.0 <= r < 1.0)
   1.174 + */
   1.175 +inline static float tinymt32_generate_float(tinymt32_t * random) {
   1.176 +	tinymt32_next_state(random);
   1.177 +	return tinymt32_temper(random) * TINYMT32_MUL;
   1.178 +}
   1.179 +
   1.180 +#define MIN_LOOP 8
   1.181 +#define PRE_LOOP 8
   1.182 +
   1.183 +/**
   1.184 + * This function certificate the period of 2^127-1.
   1.185 + * @param random tinymt state vector.
   1.186 + */
   1.187 +static void period_certification(tinymt32_t * random) {
   1.188 +	if ((random->status[0] & TINYMT32_MASK) == 0 &&
   1.189 +			random->status[1] == 0 &&
   1.190 +			random->status[2] == 0 &&
   1.191 +			random->status[3] == 0) {
   1.192 +		random->status[0] = 'T';
   1.193 +		random->status[1] = 'I';
   1.194 +		random->status[2] = 'N';
   1.195 +		random->status[3] = 'Y';
   1.196 +	}
   1.197 +}
   1.198 +
   1.199 +/**
   1.200 + * This function initializes the internal state array with a 32-bit
   1.201 + * unsigned integer seed.
   1.202 + * @param random tinymt state vector.
   1.203 + * @param seed a 32-bit unsigned integer used as a seed.
   1.204 + */
   1.205 +static void tinymt32_init(tinymt32_t * random, uint32_t seed) {
   1.206 +	random->status[0] = seed;
   1.207 +	random->status[1] = random->mat1;
   1.208 +	random->status[2] = random->mat2;
   1.209 +	random->status[3] = random->tmat;
   1.210 +	for (int i = 1; i < MIN_LOOP; i++) {
   1.211 +		random->status[i & 3] ^= i + UINT32_C(1812433253)
   1.212 +			* (random->status[(i - 1) & 3]
   1.213 +					^ (random->status[(i - 1) & 3] >> 30));
   1.214 +	}
   1.215 +	period_certification(random);
   1.216 +	for (int i = 0; i < PRE_LOOP; i++) {
   1.217 +		tinymt32_next_state(random);
   1.218 +	}
   1.219 +}
   1.220 +#endif	// !defined(USE_STD_RAND)