Lephisto/src/rng.c

113 lines
2.2 KiB
C

#include <stdint.h>
#include <math.h>
#include <unistd.h>
#include <time.h>
#ifdef LINUX
#include <sys/time.h>
#include <fcntl.h>
#endif
#include <SDL.h>
#include "rng.h"
#include "log.h"
// Mersenne twister state.
static uint32_t MT[624];
static uint32_t mt_y;
static int mt_pos = 0; // Current number.
static uint32_t rng_timeEntropy(void);
// Mersenne twister.
static void mt_initArray(uint32_t seed);
static void mt_genArray(void);
static uint32_t mt_getInt(void);
void rng_init(void) {
uint32_t i;
#ifdef LINUX
int fd; char buf[4];
fd = open("/dev/random", O_RDONLY);
if(fd != -1) {
if(read(fd, buf, 4) < 4)
memcpy(&i, buf, 4);
else
i = rng_timeEntropy();
close(fd);
} else
i = rng_timeEntropy();
#else
i = rng_timeEntropy();
#endif
mt_initArray(i);
for(i = 0; i < 10; i++)
// Generate numbers to get away from poor initial values.
mt_genArray();
}
// Use the time as source of entropy.
static uint32_t rng_timeEntropy(void) {
int i;
#ifdef WIN32
struct _timeb tb;
_ftime(&tb);
i = tb.time * 1000 + tb.millitm;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
i = tv.tv_sec * 1000000 + tv.tv_usec;
#endif
return i;
}
// Generates the initial mersenne twister based on seed.
static void mt_initArray(uint32_t seed) {
int i;
MT[0] = seed;
for(i = 1; i < 624; i++)
MT[i] = 1812433253 * (MT[i-1] ^ (((MT[i-1])) + i) >> 30);
mt_pos = 0;
}
// Generate an array of numbers.
static void mt_genArray(void) {
int i;
for(i = 0; i < 624; i++) {
mt_y = (MT[i] & 0x80000000) + ((MT[i] % 624) & 0x7FFFFFFF);
if(mt_y % 2)
// Odd.
MT[i] = (MT[(i+397) % 624] ^ (mt_y >> 1)) ^ 2567483615;
else
// Even.
MT[i] = MT[(i+397) % 624] ^ (mt_y >> 1);
}
mt_pos = 0;
}
// Get the next int.
static uint32_t mt_getInt(void) {
if(mt_pos >= 624) mt_genArray();
mt_y = MT[mt_pos++];
mt_y ^= mt_y >> 11;
mt_y ^= (mt_y << 7) & 2636928640;
mt_y ^= (mt_y << 15) & 4022730752;
mt_y ^= (mt_y >> 18);
return mt_y;
}
// Return a random int.
unsigned int randint(void) {
return mt_getInt();
}
// Return a random double.
static double m_div = (double)(0xFFFFFFFF) + 1.;
double randfp(void) {
double m = (double)mt_getInt();
return m / m_div;
}