Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#define KNUTH_MULTIPLIER 1812433253UL
#define KNUTH_SHIFT 30
#define MT_UTNLEN 624
#define MT_MAGICN 397
#define MT_MATRIX 0x9908b0dfUL
#define MT_SHIFTA 11
#define MT_SHIFTB 7
#define MT_SHIFTC 15
#define MT_SHIFTD 18
#define MT_MAGICMASKA 0x9d2c5680UL
#define MT_MAGICMASKB 0xefc60000UL
#define MT_BIT31 0x80000000UL
#define MT_BITS0TO30 0x7FFFFFFFUL
#define MT_MASK32 0xFFFFFFFFUL
#if ULONG_MAX >> 32
# define MASKRESULT(d,s) ( (d) = (s) & MT_MASK32 )
#else
# define MASKRESULT(d,s) (void)(0)
#endif
#define RAND_MT_MAX 0xffffffff
struct mt {
unsigned long utn[MT_UTNLEN];
int idx;
};
/* "Handle" for Mersenne Twister object */
typedef struct mt RAND_MT;
inline static void mt_gen_(struct mt *mt);
inline static unsigned long
knuth_prng(unsigned long pn, unsigned long n)
{
unsigned nrn = KNUTH_MULTIPLIER * (pn ^ (pn >> KNUTH_SHIFT)) + n;
MASKRESULT(nrn, nrn);
return nrn;
}
inline static void
mt_init_(struct mt *mt, unsigned long seed)
{
int i;
unsigned long *utn = mt->utn;
utn[0] = seed & MT_MASK32;
for (i = 1; i < MT_UTNLEN; i++)
utn[i] = knuth_prng(utn[i-1], i);
/* Set mt->idx to i (MT_UTNLEN) so that the first call to mt_rand_()
* triggers a call to mt_gen_()
*/
mt->idx = i;
}
inline static unsigned long
mt_combinebits_(unsigned long a, unsigned long b)
{
return (a & MT_BIT31) | (b & MT_BITS0TO30);
}
inline static unsigned long
mt_matrixmultiply_(unsigned long a, unsigned long b)
{
static unsigned long magic[2] = {0UL, MT_MATRIX};
return a ^ (b >> 1) ^ magic[b & 0x01];
}
inline static void
mt_gen_(struct mt *mt)
{
int i;
unsigned long *utn = mt->utn, y;
for (i = 0; i < MT_UTNLEN - MT_MAGICN; i++) {
y = mt_combinebits_(utn[i], utn[i + 1]);
utn[i] = mt_matrixmultiply_(utn[i + MT_MAGICN], y);
}
for (; i < MT_UTNLEN - 1; i++) {
y = mt_combinebits_(utn[i], utn[i + 1]);
utn[i] = mt_matrixmultiply_(utn[i + MT_MAGICN - MT_UTNLEN], y);
}
y = mt_combinebits_(utn[i], utn[0]);
utn[i] = mt_matrixmultiply_(utn[MT_MAGICN - 1], y);
mt->idx = 0;
}
inline static unsigned long
mt_rand_(struct mt *mt)
{
unsigned long y;
if (mt->idx >= MT_UTNLEN)
mt_gen_(mt);
y = mt->utn[mt->idx++];
y ^= (y >> MT_SHIFTA);
y ^= (y << MT_SHIFTB) & MT_MAGICMASKA;
y ^= (y << MT_SHIFTC) & MT_MAGICMASKB;
y ^= (y >> MT_SHIFTD);
return y;
}
RAND_MT *
mtrand_new(unsigned long seed)
{
RAND_MT *mt;
if ((mt = malloc(sizeof *mt)) != NULL)
mt_init_(mt, seed);
return mt;
}
void
mtrand_dispose(RAND_MT *mt)
{
free(mt);
}
unsigned long
mtrand_get(RAND_MT *mt)
{
return mt_rand_(mt);
}
static RAND_MT *rng;
int
tielaces(void)
{
return mtrand_get(rng) & 0;
}
int
usevelcro(void)
{
return mtrand_get(rng) | 1;
}
int main(void)
{
if((rng = mtrand_new(time(NULL)))==NULL) {
fputs("Could not initialise RNG. Aborting", stderr);
return 1;
}
if (tielaces())
puts("Hodor tied laces. Hodor!");
else if (usevelcro())
puts("Hodor secured shoes! Hodor, Hodor, Hodor! (stomps feet)");
else
puts("Hodor failed. Hodor.");
mtrand_dispose(rng);
return 0;
}