From df842eacec2b6f9a2ca218de43704f9a4756d812 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 22 Sep 2018 13:37:25 +0100 Subject: [PATCH] Merge remote-tracking branch 'origin/development' # Conflicts: # include/etl/version.h # support/Release notes.txt --- include/etl/random.h | 23 +++++++++++++++ include/etl/version.h | 10 +++---- src/random.cpp | 61 +++++++++++++++++++++++++++++++++++++++ support/Release notes.txt | 4 +++ test/test_random.cpp | 57 ++++++++++++++++++++++++++++++++++-- test/vs2017/.gitignore | 1 + 6 files changed, 149 insertions(+), 7 deletions(-) diff --git a/include/etl/random.h b/include/etl/random.h index f94774f2..63ee1603 100644 --- a/include/etl/random.h +++ b/include/etl/random.h @@ -162,6 +162,29 @@ namespace etl uint32_t value1; uint32_t value2; }; + + //*************************************************************************** + /// A 32 bit random number generator. + /// Uses a permuted congruential generator calculation. + /// https://en.wikipedia.org/wiki/Permuted_congruential_generator + //*************************************************************************** + class random_pcg : public random + { + public: + + random_pcg(); + explicit random_pcg(uint32_t seed); + void initialise(uint32_t seed); + uint32_t operator()(); + uint32_t range(uint32_t low, uint32_t high); + + private: + + static const uint64_t multiplier = 6364136223846793005ULL; + static const uint64_t increment = 1ULL; + + uint64_t value; + }; } #endif diff --git a/include/etl/version.h b/include/etl/version.h index 12c1c595..365eebfd 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -37,12 +37,12 @@ SOFTWARE. /// Definitions of the ETL version ///\ingroup utilities -#define ETL_VERSION "12.0.1" -#define ETL_VERSION_W L"12.0.1" -#define ETL_VERSION_U16 u"12.0.1" -#define ETL_VERSION_U32 U"12.0.1" +#define ETL_VERSION "12.1.1" +#define ETL_VERSION_W L"12.1.1" +#define ETL_VERSION_U16 u"12.1.1" +#define ETL_VERSION_U32 U"12.1.1" #define ETL_VERSION_MAJOR 12 -#define ETL_VERSION_MINOR 0 +#define ETL_VERSION_MINOR 1 #define ETL_VERSION_PATCH 1 #define ETL_VERSION_VALUE ((ETL_VERSION_MAJOR * 10000) + (ETL_VERSION_MINOR * 100) + ETL_VERSION_PATCH) diff --git a/src/random.cpp b/src/random.cpp index ba1b0ba9..d754cf79 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -30,6 +30,7 @@ SOFTWARE. #include "etl/platform.h" #include "etl/random.h" +#include "etl/binary.h" namespace etl { @@ -349,4 +350,64 @@ namespace etl return n; } + + //*************************************************************************** + // Permuted congruential generator. + //*************************************************************************** + + //*************************************************************************** + /// Default constructor. + /// Attempts to come up with a unique non-zero seed. + //*************************************************************************** + random_pcg::random_pcg() + { + // An attempt to come up with a unique non-zero seed, + // based on the address of the instance. + uintptr_t n = reinterpret_cast(this); + value = static_cast(n); + } + + //*************************************************************************** + /// Constructor with seed value. + ///\param seed The new seed value. + //*************************************************************************** + random_pcg::random_pcg(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void random_pcg::initialise(uint32_t seed) + { + value = uint64_t(seed) | (uint64_t(seed) << 32); + } + + //*************************************************************************** + /// Get the next random_lsfr number. + //*************************************************************************** + uint32_t random_pcg::operator()() + { + uint64_t x = value; + unsigned count = (unsigned)(value >> 59); + + value = (x * multiplier) + increment; + x ^= x >> 18; + return etl::rotate_right((uint32_t)(x >> 27), count); + } + + //*************************************************************************** + /// Get the next random_lsfr number in a specified inclusive range. + //*************************************************************************** + uint32_t random_pcg::range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } } diff --git a/support/Release notes.txt b/support/Release notes.txt index 7e8d147c..4be3e53c 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +12.1.1 +Added random_pcg Permuted Congruential Generator + =============================================================================== 12.0.1 Modified state_chart to accept recursive events. diff --git a/test/test_random.cpp b/test/test_random.cpp index 4c77912b..4166c184 100644 --- a/test/test_random.cpp +++ b/test/test_random.cpp @@ -253,7 +253,7 @@ namespace } //========================================================================= - TEST(test_random_fast_sequence) + TEST(test_random_mwc_sequence) { std::vector out1(10000); etl::random_mwc r; @@ -289,7 +289,7 @@ namespace } //========================================================================= - TEST(test_random_fast_range) + TEST(test_random_mwc_range) { etl::random_mwc r; @@ -304,5 +304,58 @@ namespace CHECK(n <= high); } } + + //========================================================================= + TEST(test_random_pcg_sequence) + { + std::vector out1(10000); + etl::random_pcg r; + + struct generator + { + generator(etl::random& r_) + : r(r_) + { + } + + uint32_t operator()() + { + return r(); + } + + etl::random& r; + }; + + std::generate(out1.begin(), out1.end(), generator(r)); + + std::ofstream file("random_pcg.csv"); + + if (!file.fail()) + { + for (size_t i = 0; i < out1.size(); i += 2) + { + file << out1[i] << "," << out1[i + 1] << "\n"; + } + } + + file.close(); + } + + //========================================================================= + TEST(test_random_pcg_range) + { + etl::random_pcg r; + + uint32_t low = 1234; + uint32_t high = 9876; + + for (int i = 0; i < 100000; ++i) + { + uint32_t n = r.range(low, high); + + CHECK(n >= low); + CHECK(n <= high); + } + } }; } diff --git a/test/vs2017/.gitignore b/test/vs2017/.gitignore index c1a708db..ba0b1b50 100644 --- a/test/vs2017/.gitignore +++ b/test/vs2017/.gitignore @@ -3,3 +3,4 @@ /random_lsfr.csv /random_mwc.csv /random_xorshift.csv +/random_pcg.csv