From 703edb676ca79a1eecabcb6bc78b7a8a9ccca976 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Tue, 8 Dec 2015 17:48:53 +0100 Subject: [PATCH] facility to inject a non-random random generator This should be handy for writing tests that make use of randomization. --- src/tests.c | 3 +++ src/util/rand.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ src/util/rand.h | 9 +++++++ src/util/rng.h | 4 ++-- 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/tests.c b/src/tests.c index 9fc810afe..eb03820a8 100644 --- a/src/tests.c +++ b/src/tests.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -103,6 +104,8 @@ void test_cleanup(void) errno = 0; log_error("errno: %d", error); } + + random_source_reset(); } terrain_type * diff --git a/src/util/rand.c b/src/util/rand.c index 4e600b1a5..1825340fe 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "rng.h" #include +#include #include #include #include @@ -65,3 +66,66 @@ bool chance(double x) return true; return rng_double() < x; } + +extern double genrand_real2(void); + + +typedef struct random_source { + double (*double_source) (void); +} random_source; + +random_source *r_source = 0; + +double rng_injectable_double(void) { + if (r_source) + return r_source->double_source(); + return genrand_real2(); +} + +static double constant_value; + +static double constant_source (void) { + return constant_value; +} + +struct random_source constant_provider = { + constant_source +}; + +void random_source_inject_constant(double value) { + constant_value = value; + r_source = &constant_provider; +} + +static int i = 0; +static double *values; +static int value_size = 0; + +static double array_source (void) { + assert(i 0); + value_size = size; + if (values) + free(values); + values = malloc(sizeof(double) * size); + for (i=0; i < size; ++i) { + values[i] = inject[i]; + } + i = 0; + r_source = &array_provider; +} + +void random_source_reset(void) { + if (values) + free(values); + values = NULL; + r_source = NULL; +} diff --git a/src/util/rand.h b/src/util/rand.h index b161f31cf..e9e5d19ee 100644 --- a/src/util/rand.h +++ b/src/util/rand.h @@ -31,6 +31,15 @@ extern "C" { extern int ntimespprob(int n, double p, double mod); extern bool chance(double x); + /* a random source that generates numbers in [0, 1). + By calling the random_source_inject... functions you can set a special random source, + which is handy for testing */ + double rng_injectable_double(void); + + void random_source_inject_constant(double value); + void random_source_inject_array(double inject[], int size); + void random_source_reset(void); + #ifdef __cplusplus } #endif diff --git a/src/util/rng.h b/src/util/rng.h index 1cc95d094..1bc3e48ed 100644 --- a/src/util/rng.h +++ b/src/util/rng.h @@ -23,7 +23,7 @@ extern "C" { extern unsigned long genrand_int32(void); /* generates a random number on [0,1)-real-interval */ - extern double genrand_real2(void); + extern double rng_injectable_double(void); /* generates a random number on [0,0x7fffffff]-interval */ long genrand_int31(void); @@ -31,7 +31,7 @@ extern "C" { # define rng_init(seed) init_genrand(seed) # define rng_int (int)genrand_int31 # define rng_uint (unsigned int)genrand_int32 -# define rng_double genrand_real2 +# define rng_double rng_injectable_double # define RNG_RAND_MAX 0x7fffffff #else # include