psyclpc/src/random.c

121 lines
4.1 KiB
C

/*------------------------------------------------------------------
* Wrapper for the 'SIMD oriented Fast Mersenne Twister.
*
* SFMT was developed by Mutsuo Saito and Makoto Matsumoto,
* Hiroshima University,
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html)
* SFMT was integrated to LDMud by Zesstra@MorgenGrauen (http://mg.mud.de)
*------------------------------------------------------------------
*/
#include "driver.h"
#include "random.h"
#include "backend.h"
/* This is included on purpose so that the compiler may inline some functions.
* They are anyway never used anywhere else, all other parts of the driver use
* only the wrapper functions in this file.
*/
#include "random/SFMT.c"
const unsigned int INIT_ARRAY_SIZE = 156U; // 4*156 == 624 bytes
// Name of the device/file to seed the PRNG from
char * prng_device_name = NULL;
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Driver interface functions */
/*-------------------------------------------------------------------------*/
/* random_number() is in random.h to be inlined. */
/* Return a random number in the range 0..n-1.
*
* The MT FAQ suggests:
* If the application is not sensitive to the rounding off error, then please
* multiply N to [0,1)-real uniform random numbers and take the integer part
* (this is sufficient for most applications).
* I use the appropriate functions from the SFMT to generate random numbers on
* the [0,1) interval and multiply with N.
*/
#if SIZEOF_LONG == SIZEOF_CHAR_P
uint64_t random_number(uint64_t n) {
return genrand_res53() * n;
}
#elif SIZEOF_INT == SIZEOF_CHAR_P
uint32_t random_number(uint32 n) {
return genrand_real2() * n;
}
#else
#error We currently do not yet support a 128 bit integer type used as \
svalue number type.
#endif
void seed_random_from_int (uint32_t seed)
/* Initialize the generator */
{
#ifdef USE_LDMUD_COMPATIBILITY
# ifdef VERBOSE
printf("%s Seeding PRNG with: 0x%lx\n"
, time_stamp(), (unsigned long)seed);
# endif
debug_message("%s Seeding PRNG with: 0x%lx\n"
, time_stamp(), (unsigned long)seed);
#endif
init_gen_rand(seed);
} /* seed_random_from_int() */
/*-------------------------------------------------------------------------*/
void
seed_random(const char *filename)
/* Opens the file given by filename and reads 156 uint32_t (624
* bytes) from it (most often the file is probably /dev/urandom or
* /dev/random). If successful the random number generator will be seeded
* by an array of 624 bytes. Otherwise the driver clock will be used as
* fallback.
*/
{
FILE *seedsrc = NULL; // Filepointer
// If we got a NULL pointer or an empty string, don't try to open some
// device/file.
if (filename != NULL && strlen(filename))
seedsrc = fopen(filename,"rb");
// if we have a file descriptor try to get a suitable amount of 32-bit
// values from a file (right now 156 uint32_t / 624 bytes)
if (seedsrc) {
uint32_t seeddata[INIT_ARRAY_SIZE];
size_t count = fread( seeddata, sizeof(uint32), INIT_ARRAY_SIZE,
seedsrc );
fclose(seedsrc);
if( count == INIT_ARRAY_SIZE ) {
init_by_array(seeddata, INIT_ARRAY_SIZE ); // seed PRNG
#ifdef USE_LDMUD_COMPATIBILITY
# ifdef VERBOSE
printf("%s Seeding PRNG from %s.\n", time_stamp(),
filename);
# endif
debug_message("%s Seeding PRNG from %s.\n", time_stamp(),
filename);
#endif
return;
} // if (count == INIT_ARRAY_SIZE)
} // if (seedsrc)
// Fall-back: driver clock
#ifdef USE_LDMUD_COMPATIBILITY
# ifdef VERBOSE
printf("%s Seeding PRNG with current driver time\n"
, time_stamp());
# endif
debug_message("%s Seeding PRNG with current driver time\n"
, time_stamp());
#endif
seed_random_from_int((uint32_t)current_time);
} /* seed_random() */
/***************************************************************************/