star-sp

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

commit d47ed9e5fd0ce79b820c7a0fa211cfbeedd96e6d
parent 52e8cb881ef6d21f4bd974e4fe7d5905db7db1f7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  6 May 2015 16:57:58 +0200

Make the library compliant with the CL compiler

Note that the deserialisation of the ranlux PRNG is bugged

Diffstat:
Mcmake/CMakeLists.txt | 26++++++++++++++++++++------
Msrc/ssp.h | 25++++++++++++-------------
Msrc/ssp_rng.c | 61++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/ssp_rng_proxy.c | 14++++++--------
Msrc/test_ssp_ran_hemisphere.c | 4++--
Msrc/test_ssp_rng.c | 10++++++----
Msrc/test_ssp_rng_proxy.c | 2+-
7 files changed, 85 insertions(+), 57 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -43,9 +43,13 @@ find_package(RCMake 0.1 REQUIRED) find_package(RSys 0.1.1 REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) include(rcmake) +include(rcmake_runtime) include_directories(${RSys_INCLUDE_DIR}) +rcmake_append_runtime_dirs(_runtime_dirs RSys) + + ################################################################################ # Configure and define targets ################################################################################ @@ -91,19 +95,29 @@ if(NOT NO_TEST) foreach(_lib ${_libraries}) target_link_libraries(${_name} ${_lib}) endforeach(_lib) + + endfunction() + + function(register_test _name) + add_test(${_name} ${ARGN}) + rcmake_set_test_runtime_dirs(${_name} _runtime_dirs) endfunction() function(new_test _name) build_test(${_name} ${ARGN}) - add_test(${_name} ${_name}) + register_test(${_name} ${_name}) endfunction() - build_test(test_ssp_rng) - add_test(test_ssp_rng_kiss test_ssp_rng kiss) - add_test(test_ssp_rng_mt19937_64 test_ssp_rng mt19937_64) - add_test(test_ssp_rng_ranlunx48 test_ssp_rng ranlux48) - new_test(test_ssp_ran_hemisphere m) + if(CMAKE_COMPILER_IS_GNUCXX) + set(MATH_LIB m) + endif() + + build_test(test_ssp_rng) + register_test(test_ssp_rng_kiss test_ssp_rng kiss) + register_test(test_ssp_rng_mt19937_64 test_ssp_rng mt19937_64) + register_test(test_ssp_rng_ranlux48 test_ssp_rng ranlux48) + new_test(test_ssp_ran_hemisphere ${MATH_LIB}) new_test(test_ssp_rng_proxy) endif() diff --git a/src/ssp.h b/src/ssp.h @@ -65,18 +65,17 @@ struct mem_allocator; struct ssp_rng_type { void (*init)(struct mem_allocator* allocator, void* state); void (*release)(void* state); - void (*set)(void* state, const unsigned long seed); + void (*set)(void* state, const uint64_t seed); - unsigned long (*get)(void* state); - unsigned long (*uniform_int) - (void* state, const unsigned long min, const unsigned long max); + uint64_t (*get)(void* state); + uint64_t (*uniform_int)(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); - unsigned long min; - unsigned long max; + uint64_t min; + uint64_t max; size_t sizeof_state; }; @@ -110,19 +109,19 @@ ssp_rng_ref_get SSP_API res_T ssp_rng_set (struct ssp_rng* rng, - const unsigned long seed); + const uint64_t seed); /* Uniform random distribution in [ssp_rng_min(rng), ssp_rng_max(rng)] */ -SSP_API unsigned long +SSP_API uint64_t ssp_rng_get (struct ssp_rng* rng); /* Uniform random integer distribution in [lower, upper] */ -SSP_API unsigned long +SSP_API uint64_t ssp_rng_uniform_int (struct ssp_rng* rng, - const unsigned long lower, - const unsigned long upper); + const uint64_t lower, + const uint64_t upper); /* Uniform random floating point distribution in [lower, upper] */ SSP_API double @@ -136,11 +135,11 @@ SSP_API double ssp_rng_canonical (struct ssp_rng* rng); -SSP_API unsigned long +SSP_API uint64_t ssp_rng_min (struct ssp_rng* rng); -SSP_API unsigned long +SSP_API uint64_t ssp_rng_max (struct ssp_rng* rng); diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -37,25 +37,32 @@ #include <random> #include <sstream> +#ifdef COMPILER_CL + #pragma warning(push) + #pragma warning(disable:4706) /* Assignment in conditional expression */ +#endif + /******************************************************************************* * KISS PRNG ******************************************************************************/ struct rng_kiss { uint32_t x, y, z, c; }; static void -rng_kiss_set(void* data, const unsigned long seed) +rng_kiss_set(void* data, const size_t seed) { struct rng_kiss* kiss = (struct rng_kiss*)data; - std::mt19937 rng_mt(seed % ((1L<<32)-1)); + std::mt19937 rng_mt(seed % UINT32_MAX); ASSERT(kiss); kiss->x = (uint32_t)rng_mt(); - while(!(kiss->y = (uint32_t)rng_mt())); /* y must be != 0 */ + do { + kiss->y = (uint32_t)rng_mt(); + } while(kiss->y == 0); /* Y must be != 0 */ kiss->z = (uint32_t)rng_mt(); /* Offset c by 1 to avoid z=c=0; should be less than 698769069 */ kiss->c = (uint32_t)rng_mt() % 698769068 + 1; } -static unsigned long +static uint64_t rng_kiss_get(void* data) { struct rng_kiss* kiss = (struct rng_kiss*)data; @@ -68,13 +75,12 @@ rng_kiss_get(void* data) kiss->y ^= kiss->y << 22; t = 4294584393ULL * kiss->z + kiss->c; kiss->c = (uint32_t)(t >> 32); - kiss->z = (uint32_t)t; + kiss->z = (uint32_t)(t & 0xFFFFFFFF); return (uint32_t)(kiss->x + kiss->y + kiss->z); } -static unsigned long -rng_kiss_uniform_int - (void* data, const unsigned long lower, const unsigned long upper) +static uint64_t +rng_kiss_uniform_int(void* data, const uint64_t lower, const uint64_t upper) { ASSERT(lower <= upper); return (uint32_t) @@ -104,7 +110,7 @@ rng_kiss_read(void* data, FILE* file) 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; + return res == EOF || !res/* Required by CL O_o !!*/ ? RES_IO_ERR : RES_OK; } static res_T @@ -151,15 +157,15 @@ const struct ssp_rng_type ssp_rng_kiss = { ******************************************************************************/ template<typename RNG> static void -rng_cxx_set(void* data, const unsigned long seed) +rng_cxx_set(void* data, const uint64_t seed) { RNG* rng = (RNG*)data; ASSERT(rng); - rng->seed(seed); + rng->seed((unsigned long)seed); } template<typename RNG> -static unsigned long +static uint64_t rng_cxx_get(void* data) { RNG* rng = (RNG*)data; @@ -168,13 +174,13 @@ rng_cxx_get(void* data) } template<typename RNG> -static unsigned long +static uint64_t rng_cxx_uniform_int - (void* data, const unsigned long lower, const unsigned long upper) + (void* data, const uint64_t lower, const uint64_t upper) { RNG* rng = (RNG*)data; ASSERT(rng && lower <= upper); - return std::uniform_int_distribution<unsigned long>(lower, upper)(*rng); + return std::uniform_int_distribution<uint64_t>(lower, upper)(*rng); } template<typename RNG> @@ -191,9 +197,14 @@ template<typename RNG> static double rng_cxx_canonical(void* data) { + /* On Visual Studio 2013, the generate_canonical method is bugged */ +#ifdef COMPILER_CL + return rng_cxx_uniform_double<RNG>(data, 0.f, 1.f); +#else RNG* rng = (RNG*)data; ASSERT(rng); return std::generate_canonical<double, 48>(*rng); +#endif } template<typename RNG> @@ -240,6 +251,7 @@ static void rng_cxx_release(void* data) { RNG* rng = (RNG*)data; + (void)rng; ASSERT(rng); rng->~RNG(); } @@ -303,9 +315,9 @@ rng_release(ref_T* ref) rng = CONTAINER_OF(ref, struct ssp_rng, ref); if(rng->state) { rng->type.release(rng->state); - MEM_FREE(rng->allocator, rng->state); + MEM_RM(rng->allocator, rng->state); } - MEM_FREE(rng->allocator, rng); + MEM_RM(rng->allocator, rng); } /******************************************************************************* @@ -370,16 +382,16 @@ ssp_rng_ref_put(struct ssp_rng* rng) return RES_OK; } -unsigned long +uint64_t ssp_rng_get(struct ssp_rng* rng) { if(!rng) FATAL("The Random Number Generator is NULL\n"); return rng->type.get(rng->state); } -unsigned long +uint64_t ssp_rng_uniform_int - (struct ssp_rng* rng, const unsigned long lower, const unsigned long upper) + (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_int(rng->state, lower, upper); @@ -400,14 +412,14 @@ ssp_rng_canonical(struct ssp_rng* rng) return rng->type.canonical(rng->state); } -unsigned long +uint64_t ssp_rng_min(struct ssp_rng* rng) { if(!rng) FATAL("The Random Number Generator is NULL\n"); return rng->type.min; } -unsigned long +uint64_t ssp_rng_max(struct ssp_rng* rng) { if(!rng) FATAL("The Random Number Generator is NULL\n"); @@ -415,7 +427,7 @@ ssp_rng_max(struct ssp_rng* rng) } res_T -ssp_rng_set(struct ssp_rng* rng, const unsigned long seed) +ssp_rng_set(struct ssp_rng* rng, const uint64_t seed) { if(!rng) return RES_BAD_ARG; rng->type.set(rng->state, seed); @@ -436,3 +448,6 @@ ssp_rng_write(const struct ssp_rng* rng, FILE* stream) return rng->type.write(rng->state, stream); } +#ifdef COMPILER_CL + #pragma warning(pop) +#endif diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -65,7 +65,7 @@ struct ssp_rng_proxy { struct ssp_rng* rng; /* Main `type' RNG */ /* The following arrays have the same size */ - int* buckets; /* Flag that defines which bucket RNGs are created */ + ATOMIC* buckets; /* Flag that defines which bucket RNGs are created */ struct ssp_rng** pools; /* `type' RNGs wrapped by bucket RNGs */ struct rng_state_cache* states; /* Cache of `type' RNG states */ @@ -172,13 +172,13 @@ rng_bucket_next_ran_pool(struct rng_bucket* rng) } static void -rng_bucket_set(void* data, const unsigned long seed) +rng_bucket_set(void* data, const uint64_t seed) { (void)data, (void)seed; FATAL("The seed can't be set explicitly on bucket RNGs\n"); } -static unsigned long +static uint64_t rng_bucket_get(void* data) { struct rng_bucket* rng = (struct rng_bucket*)data; @@ -188,9 +188,9 @@ rng_bucket_get(void* data) return ssp_rng_get(rng->pool); } -static unsigned long +static uint64_t rng_bucket_uniform_int - (void* data, const unsigned long lower, const unsigned long upper) + (void* data, const uint64_t lower, const uint64_t upper) { struct rng_bucket* rng = (struct rng_bucket*)data; ASSERT(data); @@ -224,7 +224,6 @@ rng_bucket_read(void* data, FILE* file) { (void)data, (void)file; FATAL("A bucket RNG can't be de-serialized\n"); - return RES_BAD_OP; } static res_T @@ -232,7 +231,6 @@ rng_bucket_write(const void* data, FILE* file) { (void)data, (void)file; FATAL("A bucket RNG can't be serialized\n"); - return RES_BAD_OP; } static void @@ -362,7 +360,7 @@ rng_proxy_release(ref_T* ref) sa_release(proxy->buckets); SSP(rng_ref_put(proxy->rng)); if(proxy->mutex) mutex_destroy(proxy->mutex); - MEM_FREE(proxy->allocator, proxy); + MEM_RM(proxy->allocator, proxy); } /******************************************************************************* diff --git a/src/test_ssp_ran_hemisphere.c b/src/test_ssp_ran_hemisphere.c @@ -58,7 +58,7 @@ main(int argc, char** argv) float frame[9]; float up[3] = {0.f, 0.f, 1.f}; float xyz[3]; - unsigned long seed = ssp_rng_get(rng0); + uint64_t seed = ssp_rng_get(rng0); ssp_rng_set(rng1, seed); f = ssp_ran_hemisphere_uniform_local(rng1, samps0[i]); @@ -100,7 +100,7 @@ main(int argc, char** argv) float frame[9]; float up[3] = { 0.f, 0.f, 1.f }; float xyz[3]; - unsigned long seed = ssp_rng_get(rng0); + uint64_t seed = ssp_rng_get(rng0); ssp_rng_set(rng1, seed); f = ssp_ran_hemisphere_cos_local(rng1, samps2[i]); diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -44,8 +44,8 @@ test_rng(const struct ssp_rng_type* type) struct ssp_rng* rng; struct mem_allocator allocator; struct time t0, t1; - unsigned long datai0[NRAND]; - unsigned long datai1[NRAND]; + uint64_t datai0[NRAND]; + uint64_t datai1[NRAND]; double dataf[NRAND]; char buf[512]; int i, j; @@ -143,12 +143,14 @@ test_rng(const struct ssp_rng_type* type) 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); +#ifndef COMPILER_CL CHECK(ssp_rng_read(rng, stream), RES_IO_ERR); +#endif rewind(stream); CHECK(ssp_rng_read(rng, stream), RES_OK); FOR_EACH(i, 0, NRAND) { - unsigned long r = ssp_rng_get(rng); + uint64_t r = ssp_rng_get(rng); CHECK(r, datai0[i]); } fclose(stream); @@ -173,7 +175,7 @@ main(int argc, char** argv) test_rng(&ssp_rng_ranlux48); } else { fprintf(stderr, "Unknown RNG `%s'\n", argv[1]); - CHECK(0, 1); + ASSERT(0); } CHECK(mem_allocated_size(), 0); diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c @@ -74,7 +74,7 @@ main(int argc, char** argv) CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); FOR_EACH(i, 0, 2000000) { - unsigned long r[4]; + uint64_t r[4]; int j; FOR_EACH(j, 0, 4) { int k;