Mercurial > forge
changeset 1607:ad54875a7c04 octave-forge
move array generators from rand.cc; more extensive docs; undo set_state
damage; reorganize code to separate randmt from uniform from zig.
author | pkienzle |
---|---|
date | Fri, 30 Jul 2004 22:34:41 +0000 |
parents | ee44b2a9cdc9 |
children | d538d48f7880 |
files | FIXES/randmtzig.c |
diffstat | 1 files changed, 169 insertions(+), 79 deletions(-) [+] |
line wrap: on
line diff
--- a/FIXES/randmtzig.c Fri Jul 30 22:30:51 2004 +0000 +++ b/FIXES/randmtzig.c Fri Jul 30 22:34:41 2004 +0000 @@ -6,9 +6,6 @@ David Bateman added normal and exponential distributions following Marsaglia and Tang's Ziggurat algorithm. - Before using, initialize the state by using init_by_int(seed) - or init_by_array(init_key, key_length). - Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, Copyright (C) 2004, David Bateman All rights reserved. @@ -60,32 +57,73 @@ * 2004-07-28 Paul Kienzle & David Bateman * * add -DALLBITS flag for 32 vs. 53 bits of randomness in mantissa * * make the naming scheme more uniform - * * add -DCPU_X86_32 for faster support of 53 bit mantissa on x86 arch. + * * add -DHAVE_X86 for faster support of 53 bit mantissa on x86 arch. */ -/* Provides: +/* + === Build instructions === + + Simple instructions: + + cc randmtzig.c -DTEST -lm -o rand + ./rand + + You should be able to #include <randmtzig.c> in C or C++ code, or + you can compile it as a library or as a standalone program. + + Compile with -DEXPORT if you wish to build a library. You may also + need this if your compiler does not accept the inline keyword. Note + that this may make the array generators slower, so if you only need + the array generators you don't need the -DEXPORT flag. + + Compile with -DTEST to generate a standalone program. E.g., + + Compile with -DHAVE_GETTIMEOFDAY if the gettimeofday function is + available. This is not necessary if your architecture has + /dev/urandom defined. + + Compile with -DALLBITS for 53-bit random numbers. This is about + 50% slower than using 32-bit random numbers. + + Uses implicit -Di386 to determine if CPU=x86. You can force X86 + behaviour with -DHAVE_X86=1, or suppress it with -DHAVE_X86=0. You + should also consider -march=i686 or similar for extra performance. + + If you want to replace the Mersenne Twister with another + generator then redefine randi32 appropriately. + + === Usage instructions === + Before using any of the generators, initialize the state with one of + init_by_int, init_by_array or init_by_entropy. + + All generators share the same state vector. + + === Mersenne Twister === void init_by_int(uint32_t s) 32-bit initial state void init_by_array(uint32_t k[],int m) m*32-bit initial state void init_by_entropy(void) random initial state void get_state(uint32_t save[MT_N+1]) saves state in array void set_state(uint32_t save[MT_N+1]) restores state from array - uint32_t randi32(void) returns 32-bit unsigned int - uint64_t randi64(void) returns 64-bit unsigned int - - double randu32(void) returns 32-bit uniform in (0,1) - double randu53(void) returns 53-bit uniform in (0,1) - double randu (void) returns M-bit uniform in (0,1) - double randn (void) returns M-bit standard normal - double rande (void) returns N-bit standard exponential + uint32_t randmt(void) returns 32-bit unsigned int - You should be able to #include <randmtzig.c> in C or C++ code. - Compile with -Dinline= if you wish to export all symbols. - Compile with -DHAVE_GETTIMEOFDAY if the gettimeofday function is available. - Compile with -DALLBITS for M=53 bit random numbers - Compile with -DCPU_X86_32 for faster 53-bit support on x86 arch - Compile with -DTEST to generate a small main() test program + === inline generators === + uint32_t randi32(void) returns 32-bit unsigned int + uint64_t randi53(void) returns 53-bit unsigned int + uint64_t randi54(void) returns 54-bit unsigned int + uint64_t randi64(void) returns 64-bit unsigned int + double randu32(void) returns 32-bit uniform in (0,1) + double randu53(void) returns 53-bit uniform in (0,1) + double randu(void) returns M-bit uniform in (0,1) + double randn(void) returns M-bit standard normal + double rande(void) returns N-bit standard exponential - cc randmtzig.c -DTEST -lm + === Array generators === + void fill_randi32(size_t, uint32_t []) + void fill_randi64(size_t, uint64_t []) + void fill_randu(size_t, double []) + void fill_randn(size_t, double []) + void fill_rande(size_t, double []) + */ #ifdef __cplusplus @@ -103,14 +141,25 @@ # include <sys/time.h> #endif -/* Determine default mantissa for uniform double */ -#ifdef ALLBITS -#define randu randu53 -#else -#define randu randu32 +/* XXX FIXME XXX may want to suppress X86 if sizeof(long)>4 */ +#if !defined(HAVE_X86) +# if defined(i386) +# define HAVE_X86 1 +# else +# define HAVE_X86 0 +# endif #endif -/* Mersenne Twister parameters */ +#if defined(EXPORT) +# define USE_INLINE +#else +# define USE_INLINE inline +#endif + + + +/* ===== Mersenne Twister 32-bit generator ===== */ + #define MT_N 624 #define MT_M 397 #define MATRIX_A 0x9908b0dfUL /* constant vector a */ @@ -125,43 +174,6 @@ static int initf = 0; static int initt = 1; -/* Ziggurat parameters */ -#ifdef ALLBITS -# define ZIGINT uint64_t -# define EMANTISSA 9007199254740992.0 /* 53 bit mantissa */ -# define ERANDI randi53() /* 53 bits for mantissa */ -#if 1 -# define NMANTISSA EMANTISSA -# define NRANDI randi54() /* 53 bits for mantissa + 1 bit sign */ -#else -# define NMANTISSA 4503599627370496.0 -# define NRANDI randi53() -#endif -# define RANDU randu53() -#else -# define ZIGINT uint32_t -# define EMANTISSA 4294967296.0 /* 32 bit mantissa */ -# define ERANDI randi32() /* 32 bits for mantissa */ -# define NMANTISSA 2147483648.0 /* 31 bit mantissa */ -# define NRANDI randi32() /* 31 bits for mantissa + 1 bit sign */ -# define RANDU randu32() -#endif - -#define ZIGGURAT_TABLE_SIZE 256 - -#define ZIGGURAT_NOR_R 3.6541528853610088 -#define ZIGGURAT_NOR_INV_R 0.27366123732975828 -#define NOR_SECTION_AREA 0.00492867323399 - -#define ZIGGURAT_EXP_R 7.69711747013104972 -#define ZIGGURAT_EXP_INV_R 0.129918765548341586 -#define EXP_SECTION_AREA 0.0039496598225815571993 - -static ZIGINT ki[ZIGGURAT_TABLE_SIZE]; -static double wi[ZIGGURAT_TABLE_SIZE], fi[ZIGGURAT_TABLE_SIZE]; -static ZIGINT ke[ZIGGURAT_TABLE_SIZE]; -static double we[ZIGGURAT_TABLE_SIZE], fe[ZIGGURAT_TABLE_SIZE]; - /* initializes state[MT_N] with a seed */ void init_by_int(uint32_t s) { @@ -246,8 +258,9 @@ void set_state(uint32_t save[]) { int i; - for (i=0; i < MT_N; i++) save[i] = state[i]; - save[MT_N] = left; + for (i=0; i < MT_N; i++) state[i] = save[i]; + left = save[MT_N]; + next = state + (MT_N-left+1); } void get_state(uint32_t save[]) @@ -281,7 +294,7 @@ } /* generates a random number on [0,0xffffffff]-interval */ -inline uint32_t randi32(void) +USE_INLINE uint32_t randmt(void) { register uint32_t y; @@ -295,11 +308,25 @@ return (y ^ (y >> 18)); } -inline uint64_t randi53(void) + + +/* ===== Uniform generators ===== */ + +/* Determine mantissa for uniform doubles */ +#ifdef ALLBITS +#define randu randu53 +#else +#define randu randu32 +#endif + +/* Select which 32 bit generator to use */ +#define randi32 randmt + +USE_INLINE uint64_t randi53(void) { const uint32_t lo = randi32(); const uint32_t hi = randi32()&0x1FFFFF; -#if defined(CPU_X86_32) +#if defined(HAVE_X86) uint64_t u; uint32_t *p = (uint32_t *)&u; p[0] = lo; @@ -310,11 +337,11 @@ #endif } -inline uint64_t randi54(void) +USE_INLINE uint64_t randi54(void) { const uint32_t lo = randi32(); const uint32_t hi = randi32()&0x3FFFFF; -#if defined(CPU_X86_32) +#if defined(HAVE_X86) uint64_t u; uint32_t *p = (uint32_t *)&u; p[0] = lo; @@ -325,11 +352,11 @@ #endif } -inline uint64_t randi64(void) +USE_INLINE uint64_t randi64(void) { const uint32_t lo = randi32(); const uint32_t hi = randi32(); -#if defined(CPU_X86_32) +#if defined(HAVE_X86) uint64_t u; uint32_t *p = (uint32_t *)&u; p[0] = lo; @@ -341,14 +368,14 @@ } /* generates a random number on (0,1)-real-interval */ -inline double randu32(void) +USE_INLINE double randu32(void) { return ((double)randi32() + 0.5) * (1.0/4294967296.0); /* divided by 2^32 */ } /* generates a random number on (0,1) with 53-bit resolution */ -inline double randu53(void) +USE_INLINE double randu53(void) { const uint32_t a=randi32()>>5; const uint32_t b=randi32()>>6; @@ -356,6 +383,38 @@ } +/* ===== Ziggurat normal and exponential generators ===== */ +#ifdef ALLBITS +# define ZIGINT uint64_t +# define EMANTISSA 9007199254740992.0 /* 53 bit mantissa */ +# define ERANDI randi53() /* 53 bits for mantissa */ +# define NMANTISSA EMANTISSA +# define NRANDI randi54() /* 53 bits for mantissa + 1 bit sign */ +# define RANDU randu53() +#else +# define ZIGINT uint32_t +# define EMANTISSA 4294967296.0 /* 32 bit mantissa */ +# define ERANDI randi32() /* 32 bits for mantissa */ +# define NMANTISSA 2147483648.0 /* 31 bit mantissa */ +# define NRANDI randi32() /* 31 bits for mantissa + 1 bit sign */ +# define RANDU randu32() +#endif + +#define ZIGGURAT_TABLE_SIZE 256 + +#define ZIGGURAT_NOR_R 3.6541528853610088 +#define ZIGGURAT_NOR_INV_R 0.27366123732975828 +#define NOR_SECTION_AREA 0.00492867323399 + +#define ZIGGURAT_EXP_R 7.69711747013104972 +#define ZIGGURAT_EXP_INV_R 0.129918765548341586 +#define EXP_SECTION_AREA 0.0039496598225815571993 + +static ZIGINT ki[ZIGGURAT_TABLE_SIZE]; +static double wi[ZIGGURAT_TABLE_SIZE], fi[ZIGGURAT_TABLE_SIZE]; +static ZIGINT ke[ZIGGURAT_TABLE_SIZE]; +static double we[ZIGGURAT_TABLE_SIZE], fe[ZIGGURAT_TABLE_SIZE]; + /* This code is based on the paper Marsaglia and Tsang, "The ziggurat method for generating random variables", Journ. Statistical Software. Code was @@ -470,7 +529,7 @@ * Where f is the functional form of the distribution, which for a normal * distribution is exp(-0.5*x*x) */ -inline double randn (void) +USE_INLINE double randn (void) { if (initt) create_ziggurat_tables(); while (1) @@ -484,7 +543,7 @@ * have something to do with this. */ #if defined(ALLBITS) -# ifdef CPU_X86_32 +# if defined(HAVE_X86) /* 53-bit mantissa, 1-bit sign, x86 32-bit architecture */ double x; int si,idx; @@ -498,13 +557,13 @@ p[0] = lo; p[1] = hi&0x1FFFFF; x = ( si ? -rabs : rabs ) * wi[idx]; -# else /* !CPU_X86_32 */ +# else /* !HAVE_X86 */ /* arbitrary mantissa (selected by NRANDI, with 1 bit for sign) */ const uint64_t r = NRANDI; const int64_t rabs=r>>1; const int idx = (int)(rabs&0xFF); const double x = ( r&1 ? -rabs : rabs) * wi[idx]; -# endif /* !CPU_X86_32 */ +# endif /* !HAVE_X86 */ #else /* !ALLBITS */ /* 32-bit mantissa */ const uint32_t r = randi32(); @@ -540,7 +599,7 @@ } } -inline double rande (void) +USE_INLINE double rande (void) { if (initt) create_ziggurat_tables(); while (1) @@ -564,6 +623,37 @@ } } +/* Array generators */ +void fill_randi32(size_t n, uint32_t *p) +{ + size_t i; + for (i=0; i < n; i++) p[i] = randi32(); +} + +void fill_randi64(size_t n, uint64_t *p) +{ + size_t i; + for (i=0; i < n; i++) p[i] = randi64(); +} + +void fill_randu(size_t n, double *p) +{ + size_t i; + for (i=0; i < n; i++) p[i] = randu(); +} + +void fill_randn(size_t n, double *p) +{ + size_t i; + for (i=0; i < n; i++) p[i] = randn(); +} + +void fill_rande(size_t n, double *p) +{ + size_t i; + for (i=0; i < n; i++) p[i] = rande(); +} + #ifdef TEST #ifdef __cplusplus