diff --git a/include/etl/random.h b/include/etl/random.h index c1523620..cffeb4cc 100644 --- a/include/etl/random.h +++ b/include/etl/random.h @@ -1,4 +1,4 @@ -///\file +///\file /****************************************************************************** The MIT License(MIT) @@ -289,6 +289,7 @@ namespace etl //*************************************************************************** /// A 32 bit random number generator. /// Uses a linear shift feedback register. + /// Polynomial 0x80200003 /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register //*************************************************************************** class random_lsfr : public random @@ -499,6 +500,73 @@ namespace etl uint64_t value; }; + +#if ETL_8BIT_SUPPORT + //*************************************************************************** + /// A 32 bit random number generator. + /// Applies a user supplied 32bit hash to a counter. + /// The hash must implement 'void add(uint8_t)' and 'uint8_t value()' member functions. + //*************************************************************************** + template + class random_hash : public random + { + public: + + random_hash() + { + // 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_hash(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void initialise(uint32_t seed) + { + value = seed; + } + + //*************************************************************************** + /// Get the next random_lsfr number. + //*************************************************************************** + uint32_t operator()() + { + ++value; + hash.add(value); + return hash.value(); + } + + //*************************************************************************** + /// Get the next random_lsfr number in a specified inclusive range. + //*************************************************************************** + uint32_t range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } + + private: + + THash hash; + uint8_t value; + }; +#endif } #endif diff --git a/include/etl/version.h b/include/etl/version.h index 7b486694..58924e6b 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -38,7 +38,7 @@ SOFTWARE. ///\ingroup utilities #define ETL_VERSION_MAJOR 14 -#define ETL_VERSION_MINOR 0 +#define ETL_VERSION_MINOR 1 #define ETL_VERSION_PATCH 0 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) ETL_STRINGIFY(ETL_VERSION_MINOR) ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/support/Release notes.txt b/support/Release notes.txt index 1005e51b..d611ac55 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +14.1.0 +Added hash based random number generator + =============================================================================== 14.0.0 The ETL is now 'all header'. diff --git a/test/test_random.cpp b/test/test_random.cpp index 4166c184..66409a78 100644 --- a/test/test_random.cpp +++ b/test/test_random.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include #include "etl/random.h" +#include "etl/crc32.h" #include #include @@ -357,5 +358,59 @@ namespace CHECK(n <= high); } } + + //========================================================================= + TEST(test_random_hash_sequence) + { + std::vector out1(10000); + etl::random_hash 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_hash.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_hash_range) + { + etl::random_hash 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 ba0b1b50..e3cb4a54 100644 --- a/test/vs2017/.gitignore +++ b/test/vs2017/.gitignore @@ -4,3 +4,4 @@ /random_mwc.csv /random_xorshift.csv /random_pcg.csv +/random_hash.csv