star-sp

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

commit 4ccbc1cabae78a3e7d2710d17d0a23f9fd872032
parent ca4d6c590e23e3bce47d357a363e4284ebb0f65a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 14 Apr 2015 10:35:51 +0200

Add and test the read/write RNG functions

Diffstat:
Msrc/ssp.h | 12++++++++++++
Msrc/ssp_rng.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/test_ssp_rng.c | 25+++++++++++++++++++++++++
3 files changed, 115 insertions(+), 8 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -71,6 +71,8 @@ struct ssp_rng_type { (void* state, const unsigned long min, const unsigned long 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); unsigned long min; unsigned long max; @@ -141,6 +143,16 @@ SSP_API unsigned long ssp_rng_max (struct ssp_rng* rng); +SSP_API res_T +ssp_rng_write + (const struct ssp_rng* rng, + FILE* stream); + +SSP_API res_T +ssp_rng_read + (struct ssp_rng* rng, + FILE* stream); + /******************************************************************************* * Hemisphere distribution ******************************************************************************/ diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -35,6 +35,7 @@ #include <rsys/ref_count.h> #include <random> +#include <sstream> struct ssp_rng { struct ssp_rng_type type; @@ -103,6 +104,26 @@ 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) +{ + struct rng_kiss* rng = (struct rng_kiss*)data; + int res; + ASSERT(data && file); + res = fscanf(file, "%u %u %u %u", &rng->x, &rng->y, &rng->z, &rng->c); + return res == EOF ? RES_IO_ERR : RES_OK; +} + +static res_T +rng_kiss_write(const void* data, FILE* file) +{ + const struct rng_kiss* rng = (const struct rng_kiss*)data; + int res; + ASSERT(data && file); + res = fprintf(file, "%u %u %u %u", rng->x, rng->y, rng->z, rng->c); + return res < 0 ? RES_IO_ERR : RES_OK; +} + static void rng_kiss_init(struct mem_allocator* allocator, void* data) { @@ -125,6 +146,8 @@ struct ssp_rng_type ssp_rng_kiss = { rng_kiss_uniform_int, rng_kiss_uniform_double, rng_kiss_canonical, + rng_kiss_read, + rng_kiss_write, 0, UINT32_MAX, sizeof(struct rng_kiss) @@ -181,6 +204,34 @@ rng_cxx_canonical(void* data) } template<typename RNG> +static res_T +rng_cxx_write(const void* data, FILE* file) +{ + size_t i; + std::stringstream stream; + RNG* rng = (RNG*)data; + ASSERT(rng); + stream << *rng; + i = fwrite(stream.str().c_str(), 1, stream.str().size(), file); + return i == stream.str().size() ? RES_OK : RES_IO_ERR; +} + +template<typename RNG> +static res_T +rng_cxx_read(void* data, FILE* file) +{ + std::stringstream stream; + char buf[512]; + char* s; + RNG* rng = (RNG*)data; + ASSERT(rng); + while((s = fgets(buf, sizeof(buf), file))) + stream << std::string(s); + stream >> *rng; + return stream.fail() ? RES_IO_ERR : RES_OK; +} + +template<typename RNG> static void rng_cxx_init(struct mem_allocator* allocator, void* data) { @@ -189,7 +240,6 @@ rng_cxx_init(struct mem_allocator* allocator, void* data) new (data) RNG; } - template<typename RNG> static void rng_cxx_release(void* data) @@ -208,6 +258,8 @@ struct ssp_rng_type ssp_rng_mt19937_64 = { rng_cxx_uniform_int<std::mt19937_64>, rng_cxx_uniform_double<std::mt19937_64>, rng_cxx_canonical<std::mt19937_64>, + rng_cxx_read<std::mt19937_64>, + rng_cxx_write<std::mt19937_64>, std::mt19937_64::min(), std::mt19937_64::max(), sizeof(std::mt19937_64) @@ -222,6 +274,8 @@ struct ssp_rng_type ssp_rng_ranlux48 = { rng_cxx_uniform_int<std::ranlux48>, rng_cxx_uniform_double<std::ranlux48>, rng_cxx_canonical<std::ranlux48>, + rng_cxx_read<std::ranlux48>, + rng_cxx_write<std::ranlux48>, std::ranlux48::min(), std::ranlux48::max(), sizeof(std::ranlux48) @@ -234,13 +288,15 @@ static char check_type(const struct ssp_rng_type* type) { ASSERT(type); - return type->init != NULL - && type->release != NULL - && type->set != NULL - && type->get != NULL - && type->uniform_int != NULL - && type->uniform_double != NULL - && type->canonical != NULL + return NULL != type->init + && NULL != type->release + && NULL != type->set + && NULL != type->get + && NULL != type->uniform_int + && NULL != type->uniform_double + && NULL != type->canonical + && NULL != type->read + && NULL != type->write && type->min <= type->max; } @@ -371,3 +427,17 @@ ssp_rng_set(struct ssp_rng* rng, const unsigned long seed) return RES_OK; } +res_T +ssp_rng_read(struct ssp_rng* rng, FILE* stream) +{ + if(!rng || !stream) return RES_BAD_ARG; + return rng->type.read(rng->state, stream); +} + +res_T +ssp_rng_write(const struct ssp_rng* rng, FILE* stream) +{ + if(!rng || !stream) return RES_BAD_ARG; + return rng->type.write(rng->state, stream); +} + diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -40,6 +40,7 @@ static void /* Really basic test */ test_rng(struct ssp_rng_type* type) { + FILE* stream; struct ssp_rng* rng; struct mem_allocator allocator; struct time t0, t1; @@ -128,6 +129,30 @@ test_rng(struct ssp_rng_type* type) time_dump(&t0, TIME_SEC|TIME_MSEC|TIME_USEC, NULL, buf, sizeof(buf)); printf("1,000,000 random numbers in %s\n", buf); + + stream = tmpfile(); + NCHECK(stream, NULL); + CHECK(ssp_rng_write(NULL, NULL), RES_BAD_ARG); + CHECK(ssp_rng_write(rng, NULL), RES_BAD_ARG); + CHECK(ssp_rng_write(NULL, stream), RES_BAD_ARG); + CHECK(ssp_rng_write(rng, stream), RES_OK); + + FOR_EACH(i, 0, NRAND) + datai0[i] = ssp_rng_get(rng); + + CHECK(ssp_rng_read(NULL, NULL), RES_BAD_ARG); + CHECK(ssp_rng_read(rng, NULL), RES_BAD_ARG); + CHECK(ssp_rng_read(NULL, stream), RES_BAD_ARG); + CHECK(ssp_rng_read(rng, stream), RES_IO_ERR); + rewind(stream); + CHECK(ssp_rng_read(rng, stream), RES_OK); + + FOR_EACH(i, 0, NRAND) { + unsigned long r = ssp_rng_get(rng); + CHECK(r, datai0[i]); + } + fclose(stream); + CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator);