star-sp

Random number generators and distributions
git clone git://git.meso-star.fr/star-sp.git
Log | Files | Refs | README | LICENSE

commit 69921a28f54332b506b651a1c39f8fec5dcdf763
parent 3a77feae140e281aeccfc67cf0e1f87b4da59f96
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 12 Apr 2016 11:27:08 +0200

Add and test the uniform_float and canonical_float distributions

Remove the uniform distributions from the ssp_type data structure. They
are defined generically through the "get, get_min, get_max" ssp_type
functors.

Diffstat:
Msrc/ssp.h | 17+++++++++++------
Msrc/ssp_rng.c | 132++++++++++++++++++++++++-------------------------------------------------------
Msrc/ssp_rng_proxy.c | 34----------------------------------
Msrc/test_ssp_rng.c | 30+++++++++++++++++++++++++-----
4 files changed, 76 insertions(+), 137 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -70,9 +70,6 @@ struct ssp_rng_type { uint64_t (*get)(void* state); res_T(*discard)(void* state, uint64_t n); - uint64_t (*uniform_uint64)(void* state, const uint64_t min, const uint64_t max); - double (*uniform_double)(void* state, const double min, const double max); - double (*canonical)(void* state); res_T (*read)(void* state, FILE* file); res_T (*write)(const void* state, FILE* file); double (*entropy)(const void* state); @@ -91,9 +88,6 @@ ssp_rng_type_eq(const struct ssp_rng_type* t0, const struct ssp_rng_type* t1) && t0->set == t1->set && t0->get == t1->get && t0->discard == t1->discard - && t0->uniform_uint64 == t1->uniform_uint64 - && t0->uniform_double == t1->uniform_double - && t0->canonical == t1->canonical && t0->read == t1->read && t0->write == t1->write && t0->entropy == t1->entropy @@ -177,11 +171,22 @@ ssp_rng_uniform_double const double lower, const double upper); +SSP_API float +ssp_rng_uniform_float + (struct ssp_rng* rng, + const float lower, + const float upper); + /* Uniform random floating point distribution in [0, 1) */ SSP_API double ssp_rng_canonical (struct ssp_rng* rng); +/* Uniform random single precision floating point distribution in [0, 1) */ +SSP_API float +ssp_rng_canonical_float + (struct ssp_rng* rng); + SSP_API uint64_t ssp_rng_min (struct ssp_rng* rng); diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -83,6 +83,20 @@ #define SQRT_2_PI 2.50662827463100050240 +class rng_cxx /* Wrap a SSP random generator into a CXX object */ +{ +public: + FINLINE rng_cxx(struct ssp_rng& rng) : rng(&rng) {} + FINLINE uint64_t operator()() { return ssp_rng_get(rng); } + FINLINE uint64_t min() const { return ssp_rng_min(rng); } + FINLINE uint64_t max() const { return ssp_rng_max(rng); } + + typedef uint64_t result_type; + +private: + ssp_rng* rng; +}; + /******************************************************************************* * KISS PRNG ******************************************************************************/ @@ -122,30 +136,6 @@ rng_kiss_get(void* data) return (uint32_t)(kiss->x + kiss->y + kiss->z); } -static uint64_t -rng_kiss_uniform_uint64(void* data, const uint64_t lower, const uint64_t upper) -{ - ASSERT(lower <= upper); - return (uint64_t) - ( (double)rng_kiss_get(data)/(double)UINT32_MAX - * (double)(upper - lower) + (double)lower); -} - -static double -rng_kiss_uniform_double(void* data, const double lower, const double upper) -{ - ASSERT(lower <= upper); - ASSERT(lower <= upper); - return (double)rng_kiss_get(data)/(double)UINT32_MAX * (upper-lower) + lower; -} - - -static double -rng_kiss_canonical(void* data) -{ - return (double)rng_kiss_get(data) / ((double)UINT32_MAX + 1); -} - static res_T rng_kiss_read(void* data, FILE* file) { @@ -224,9 +214,6 @@ const struct ssp_rng_type ssp_rng_kiss = { rng_kiss_set, rng_kiss_get, rng_kiss_discard, - rng_kiss_uniform_uint64, - rng_kiss_uniform_double, - rng_kiss_canonical, rng_kiss_read, rng_kiss_write, rng_kiss_entropy, @@ -266,35 +253,6 @@ rng_cxx_get(void* data) } template<typename RNG> -static uint64_t -rng_cxx_uniform_uint64 - (void* data, const uint64_t lower, const uint64_t upper) -{ - RNG* rng = (RNG*)data; - ASSERT(rng && lower <= upper); - return RAN_NAMESPACE::uniform_int_distribution<uint64_t>(lower, upper)(*rng); -} - -template<typename RNG> -static double -rng_cxx_uniform_double - (void* data, const double lower, const double upper) -{ - RNG* rng = (RNG*)data; - ASSERT(rng && lower <= upper); - return RAN_NAMESPACE::uniform_real_distribution<>(lower, upper)(*rng); -} - -template<typename RNG> -static double -rng_cxx_canonical(void* data) -{ - RNG* rng = (RNG*)data; - ASSERT(rng); - return RAN_NAMESPACE::generate_canonical<double, 48>(*rng); -} - -template<typename RNG> static res_T rng_cxx_write(const void* data, FILE* file) { @@ -403,9 +361,6 @@ const struct ssp_rng_type ssp_rng_mt19937_64 = { rng_cxx_set<RAN_NAMESPACE::mt19937_64>, rng_cxx_get<RAN_NAMESPACE::mt19937_64>, rng_cxx_discard<RAN_NAMESPACE::mt19937_64>, - rng_cxx_uniform_uint64<RAN_NAMESPACE::mt19937_64>, - rng_cxx_uniform_double<RAN_NAMESPACE::mt19937_64>, - rng_cxx_canonical<RAN_NAMESPACE::mt19937_64>, rng_cxx_read<RAN_NAMESPACE::mt19937_64>, rng_cxx_write<RAN_NAMESPACE::mt19937_64>, rng_cxx_entropy<RAN_NAMESPACE::mt19937_64>, @@ -421,9 +376,6 @@ const struct ssp_rng_type ssp_rng_ranlux48 = { rng_cxx_set<RAN_NAMESPACE::ranlux48>, rng_cxx_get<RAN_NAMESPACE::ranlux48>, rng_cxx_discard<RAN_NAMESPACE::ranlux48>, - rng_cxx_uniform_uint64<RAN_NAMESPACE::ranlux48>, - rng_cxx_uniform_double<RAN_NAMESPACE::ranlux48>, - rng_cxx_canonical<RAN_NAMESPACE::ranlux48>, rng_cxx_read<RAN_NAMESPACE::ranlux48>, rng_cxx_write<RAN_NAMESPACE::ranlux48>, rng_cxx_entropy<RAN_NAMESPACE::ranlux48>, @@ -439,9 +391,6 @@ const struct ssp_rng_type ssp_rng_random_device = { rng_cxx_set<RAN_NAMESPACE::random_device>, rng_cxx_get<RAN_NAMESPACE::random_device>, rng_cxx_discard<RAN_NAMESPACE::random_device>, - rng_cxx_uniform_uint64<RAN_NAMESPACE::random_device>, - rng_cxx_uniform_double<RAN_NAMESPACE::random_device>, - rng_cxx_canonical<RAN_NAMESPACE::random_device>, rng_cxx_read<RAN_NAMESPACE::random_device>, rng_cxx_write<RAN_NAMESPACE::random_device>, rng_cxx_entropy<RAN_NAMESPACE::random_device>, @@ -480,9 +429,6 @@ const struct ssp_rng_type ssp_rng_threefry = { rng_cxx_set<threefry_T>, rng_cxx_get<threefry_T>, rng_cxx_discard<threefry_T>, - rng_cxx_uniform_uint64<threefry_T>, - rng_cxx_uniform_double<threefry_T>, - rng_cxx_canonical<threefry_T>, rng_cxx_read<threefry_T>, rng_cxx_write<threefry_T>, rng_cxx_entropy<threefry_T>, @@ -499,9 +445,6 @@ const struct ssp_rng_type ssp_rng_aes = { rng_cxx_set<aes_T>, rng_cxx_get<aes_T>, rng_cxx_discard<aes_T>, - rng_cxx_uniform_uint64<aes_T>, - rng_cxx_uniform_double<aes_T>, - rng_cxx_canonical<aes_T>, rng_cxx_read<aes_T>, rng_cxx_write<aes_T>, rng_cxx_entropy<aes_T>, @@ -522,9 +465,6 @@ check_type(const struct ssp_rng_type* type) && NULL != type->release && NULL != type->set && NULL != type->get - && NULL != type->uniform_uint64 - && NULL != type->uniform_double - && NULL != type->canonical && NULL != type->read && NULL != type->write && NULL != type->entropy @@ -632,22 +572,44 @@ ssp_rng_uniform_uint64 (struct ssp_rng* rng, const uint64_t lower, const uint64_t upper) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - return rng->type.uniform_uint64(rng->state, lower, upper); + rng_cxx rng_cxx(*rng); + return RAN_NAMESPACE::uniform_int_distribution<uint64_t>(lower, upper)(rng_cxx); } double ssp_rng_uniform_double - (struct ssp_rng* rng, double lower, double upper) + (struct ssp_rng* rng, const double lower, const double upper) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - return rng->type.uniform_double(rng->state, lower, upper); + rng_cxx rng_cxx(*rng); + return RAN_NAMESPACE::uniform_real_distribution<double>(lower, upper)(rng_cxx); +} + +float +ssp_rng_uniform_float + (struct ssp_rng* rng, const float lower, const float upper) +{ + if(!rng) FATAL("The Random Number Generator is NULL\n"); + rng_cxx rng_cxx(*rng); + return RAN_NAMESPACE::uniform_real_distribution<float>(lower, upper)(rng_cxx); } double ssp_rng_canonical(struct ssp_rng* rng) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - return rng->type.canonical(rng->state); + rng_cxx rng_cxx(*rng); + return RAN_NAMESPACE::generate_canonical + <double, std::numeric_limits<double>::digits>(rng_cxx); +} + +float +ssp_rng_canonical_float(struct ssp_rng* rng) +{ + if(!rng) FATAL("The Random Number Generator is NULL\n"); + rng_cxx rng_cxx(*rng); + return RAN_NAMESPACE::generate_canonical + <float, std::numeric_limits<float>::digits>(rng_cxx); } uint64_t @@ -702,20 +664,6 @@ ssp_rng_discard(struct ssp_rng* rng, uint64_t n) /******************************************************************************* * Exported distributions ******************************************************************************/ -class rng_cxx /* Wrap a SSP random generator into a CXX object */ -{ -public: - FINLINE rng_cxx(struct ssp_rng& rng) : rng(&rng) {} - FINLINE uint64_t operator()() { return ssp_rng_get(rng); } - FINLINE uint64_t min() const { return ssp_rng_min(rng); } - FINLINE uint64_t max() const { return ssp_rng_max(rng); } - - typedef uint64_t result_type; - -private: - ssp_rng* rng; -}; - double ssp_ran_exp(struct ssp_rng* rng, const double mu) { diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -188,37 +188,6 @@ rng_bucket_get(void* data) return ssp_rng_get(rng->pool); } -static uint64_t -rng_bucket_uniform_uint64 - (void* data, const uint64_t lower, const uint64_t upper) -{ - struct rng_bucket* rng = (struct rng_bucket*)data; - ASSERT(data); - if(!rng->count) rng_bucket_next_ran_pool(rng); - --rng->count; - return ssp_rng_uniform_uint64(rng->pool, lower, upper); -} - -static double -rng_bucket_uniform_double(void* data, const double lower, const double upper) -{ - struct rng_bucket* rng = (struct rng_bucket*)data; - ASSERT(data); - if(!rng->count) rng_bucket_next_ran_pool(rng); - --rng->count; - return ssp_rng_uniform_double(rng->pool, lower, upper); -} - -static double -rng_bucket_canonical(void* data) -{ - struct rng_bucket* rng = (struct rng_bucket*)data; - ASSERT(data); - if(!rng->count) rng_bucket_next_ran_pool(rng); - --rng->count; - return ssp_rng_canonical(rng->pool); -} - static res_T rng_bucket_read(void* data, FILE* file) { @@ -281,9 +250,6 @@ static const struct ssp_rng_type RNG_BUCKET_NULL = { rng_bucket_set, rng_bucket_get, rng_bucket_discard, - rng_bucket_uniform_uint64, - rng_bucket_uniform_double, - rng_bucket_canonical, rng_bucket_read, rng_bucket_write, rng_bucket_entropy, diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -49,7 +49,8 @@ test_rng(const struct ssp_rng_type* type) struct time t0, t1; uint64_t datai0[NRAND]; uint64_t datai1[NRAND]; - double dataf[NRAND]; + double datad[NRAND]; + float dataf[NRAND]; char buf[512]; int i, j; res_T r; @@ -133,9 +134,19 @@ test_rng(const struct ssp_rng_type* type) } FOR_EACH(i, 0, NRAND) { - dataf[i] = ssp_rng_uniform_double(rng, -5.0, 11.3); - CHECK(dataf[i] >= -5.0, 1); - CHECK(dataf[i] <= 11.3, 1); + datad[i] = ssp_rng_uniform_double(rng, -5.0, 11.3); + CHECK(datad[i] >= -5.0, 1); + CHECK(datad[i] <= 11.3, 1); + } + FOR_EACH(i, 0, NRAND) { + FOR_EACH(j, 0, NRAND) if(datad[i] != datad[j]) break; + NCHECK(j, NRAND); + } + + FOR_EACH(i, 0, NRAND) { + dataf[i] = ssp_rng_uniform_float(rng, -1.0, 12.5); + CHECK(dataf[i] >= -1.0, 1); + CHECK(dataf[i] <= 12.5, 1); } FOR_EACH(i, 0, NRAND) { FOR_EACH(j, 0, NRAND) if(dataf[i] != dataf[j]) break; @@ -143,7 +154,16 @@ test_rng(const struct ssp_rng_type* type) } FOR_EACH(i, 0, NRAND) { - dataf[i] = ssp_rng_canonical(rng); + datad[i] = ssp_rng_canonical(rng); + CHECK(datad[i] >= 0.0, 1); + CHECK(datad[i] < 1.0, 1); + FOR_EACH(j, 0, i) { + NCHECK(datad[i], datad[j]); + } + } + + FOR_EACH(i, 0, NRAND) { + dataf[i] = ssp_rng_canonical_float(rng); CHECK(dataf[i] >= 0.0, 1); CHECK(dataf[i] < 1.0, 1); FOR_EACH(j, 0, i) {