commit 7ed7da09762e6a32f60d635a71e2d8b7952a3c1e
parent 6c7fa93fd5e0a6de489c8c27b391f70e5fe69892
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Mon, 1 Jun 2015 18:26:41 +0200
Add random_device generator from boost or C++11 standard lib.
This generator can be hardware based.
See std::random_device for reference documentation.
Diffstat:
4 files changed, 87 insertions(+), 13 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -48,7 +48,7 @@ include(rcmake_runtime)
if(MSVC)
# Currently, the C++11 random library on MSVC is bugged and consequently we
# use the Boost library instead
- find_package(Boost 1.58 REQUIRED)
+ find_package(Boost 1.58 REQUIRED COMPONENTS random)
include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
else()
include_directories(${RSys_INCLUDE_DIR})
@@ -84,7 +84,11 @@ set_target_properties(ssp PROPERTIES
SOVERSION ${VERSION_MAJOR})
target_link_libraries(ssp RSys)
-if(CMAKE_COMPILER_IS_GNUCXX)
+if(MSVC)
+ target_link_libraries(ssp ${Boost_LIBRARIES})
+ # disable autolink
+ set_target_properties(ssp PROPERTIES COMPILE_FLAGS "/DBOOST_ALL_NO_LIB")
+elseif(CMAKE_COMPILER_IS_GNUCXX)
set_target_properties(ssp PROPERTIES COMPILE_FLAGS "-std=c++11")
endif()
@@ -125,6 +129,7 @@ if(NOT NO_TEST)
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)
+ register_test(test_ssp_rng_random_device test_ssp_rng random_device)
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
@@ -89,6 +89,16 @@ SSP_API const struct ssp_rng_type ssp_rng_kiss;
SSP_API const struct ssp_rng_type ssp_rng_mt19937_64;
/* 48-bits RANLUX builtin PRNG type of Lusher and James, 1994 */
SSP_API const struct ssp_rng_type ssp_rng_ranlux48;
+/*
+random_device generator from Boost / C++11
+std::random_device is a uniformly-distributed integer random number generator
+that produces non-deterministic random numbers.
+std::random_device may be implemented in terms of an implementation-defined
+pseudo-random number engine if a non-deterministic source (e.g. a hardware device)
+is not available to the implementation.
+In this case each std::random_device object may generate the same number sequence.
+*/
+SSP_API const struct ssp_rng_type ssp_rng_random_device;
/*******************************************************************************
* Random Number Generator API
diff --git a/src/ssp_rng.c b/src/ssp_rng.c
@@ -37,6 +37,7 @@
#ifdef COMPILER_CL
/* The random C++11 library is bugged on MSVC 12. Use the boost version */
#include <boost/random.hpp>
+ #include <boost/random/random_device.hpp>
#define RAN_NAMESPACE boost::random
#pragma warning(push)
@@ -181,6 +182,14 @@ rng_cxx_set(void* data, const uint64_t seed)
return RES_OK;
}
+template<>
+res_T
+rng_cxx_set<RAN_NAMESPACE::random_device>(void* data, const uint64_t seed)
+{
+ (void) data; (void) seed;
+ return RES_BAD_OP;
+}
+
template<typename RNG>
static uint64_t
rng_cxx_get(void* data)
@@ -233,6 +242,14 @@ rng_cxx_write(const void* data, FILE* file)
return i == stream.str().size() ? RES_OK : RES_IO_ERR;
}
+template<>
+res_T
+rng_cxx_write<RAN_NAMESPACE::random_device>(const void* data, FILE* file)
+{
+ (void) data; (void) file;
+ return RES_BAD_OP;
+}
+
template<typename RNG>
static res_T
rng_cxx_read(void* data, FILE* file)
@@ -250,6 +267,14 @@ rng_cxx_read(void* data, FILE* file)
return stream.fail() ? RES_IO_ERR : RES_OK;
}
+template<>
+res_T
+rng_cxx_read<RAN_NAMESPACE::random_device>(void* data, FILE* file)
+{
+ (void) data; (void) file;
+ return RES_BAD_OP;
+}
+
template<typename RNG>
static res_T
rng_cxx_init(struct mem_allocator* allocator, void* data)
@@ -278,6 +303,15 @@ rng_cxx_entropy(const void* data)
return 0;
}
+template<>
+double
+rng_cxx_entropy<RAN_NAMESPACE::random_device>(const void* data)
+{
+ const RAN_NAMESPACE::random_device* rng = (const RAN_NAMESPACE::random_device*)data;
+ ASSERT(rng);
+ return rng->entropy();
+}
+
/* 64-bits Mersenne Twister PRNG */
const struct ssp_rng_type ssp_rng_mt19937_64 = {
rng_cxx_init<RAN_NAMESPACE::mt19937_64>,
@@ -312,6 +346,23 @@ const struct ssp_rng_type ssp_rng_ranlux48 = {
sizeof(RAN_NAMESPACE::ranlux48)
};
+/* random_device generator */
+const struct ssp_rng_type ssp_rng_random_device = {
+ rng_cxx_init<RAN_NAMESPACE::random_device>,
+ rng_cxx_release<RAN_NAMESPACE::random_device>,
+ rng_cxx_set<RAN_NAMESPACE::random_device>,
+ rng_cxx_get<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>,
+ RAN_NAMESPACE::random_device::min(),
+ RAN_NAMESPACE::random_device::max(),
+ sizeof(RAN_NAMESPACE::random_device)
+};
+
/*******************************************************************************
* Helper functions
******************************************************************************/
diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c
@@ -49,6 +49,9 @@ test_rng(const struct ssp_rng_type* type)
double dataf[NRAND];
char buf[512];
int i, j;
+ const char can_set = (type != &ssp_rng_random_device);
+ const char can_rw = (type != &ssp_rng_random_device);
+ const char can_have_entropy = (type == &ssp_rng_random_device);
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -69,7 +72,7 @@ test_rng(const struct ssp_rng_type* type)
CHECK(ssp_rng_create(&allocator, type, &rng), RES_OK);
CHECK(ssp_rng_set(NULL, 0), RES_BAD_ARG);
- CHECK(ssp_rng_set(rng, 0), RES_OK);
+ CHECK(ssp_rng_set(rng, 0), can_set ? RES_OK : RES_BAD_OP);
FOR_EACH(i, 0, NRAND) {
datai0[i] = ssp_rng_get(rng);
@@ -80,7 +83,7 @@ test_rng(const struct ssp_rng_type* type)
}
}
- CHECK(ssp_rng_set(rng, 0xDECAFBAD), RES_OK);
+ CHECK(ssp_rng_set(rng, 0xDECAFBAD), can_set ? RES_OK : RES_BAD_OP);
FOR_EACH(i, 0, NRAND) {
datai1[i] = ssp_rng_get(rng);
NCHECK(datai1[i], datai0[i]);
@@ -129,13 +132,16 @@ test_rng(const 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);
+ if (can_have_entropy) {
+ printf("Entropy for this implementation and system: %lf\n", ssp_rng_entropy(rng));
+ }
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);
+ CHECK(ssp_rng_write(rng, stream), can_rw ? RES_OK : RES_BAD_OP);
FOR_EACH(i, 0, NRAND)
datai0[i] = ssp_rng_get(rng);
@@ -143,15 +149,15 @@ 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
+ CHECK(ssp_rng_read(rng, stream), can_rw ? RES_IO_ERR : RES_BAD_OP);
rewind(stream);
- CHECK(ssp_rng_read(rng, stream), RES_OK);
+ CHECK(ssp_rng_read(rng, stream), can_rw ? RES_OK : RES_BAD_OP);
- FOR_EACH(i, 0, NRAND) {
- uint64_t r = ssp_rng_get(rng);
- CHECK(r, datai0[i]);
+ if (can_rw) {
+ FOR_EACH(i, 0, NRAND) {
+ uint64_t r = ssp_rng_get(rng);
+ CHECK(r, datai0[i]);
+ }
}
fclose(stream);
@@ -164,7 +170,7 @@ int
main(int argc, char** argv)
{
if(argc <= 1) {
- fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48>\n", argv[0]);
+ fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device>\n", argv[0]);
exit(0);
}
if(!strcmp(argv[1], "kiss")) {
@@ -173,6 +179,8 @@ main(int argc, char** argv)
test_rng(&ssp_rng_mt19937_64);
} else if(!strcmp(argv[1], "ranlux48")) {
test_rng(&ssp_rng_ranlux48);
+ } else if(!strcmp(argv[1], "random_device")) {
+ test_rng(&ssp_rng_random_device);
} else {
fprintf(stderr, "Unknown RNG `%s'\n", argv[1]);
ASSERT(0);