From e660e5b949b519ae35e043ce3efca8a653f7582d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 8 Aug 2017 18:41:00 +0100 Subject: [PATCH] Added multipy with carry random number generator. --- src/random.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++ src/random.h | 22 ++++++++++++++-- test/test_random.cpp | 55 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 3 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index c3e5a1c9..7c63d11a 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -288,4 +288,64 @@ namespace etl return n; } + + //*************************************************************************** + // Multiply with carry random number generator. + //*************************************************************************** + + //*************************************************************************** + /// Default constructor. + /// Attempts to come up with a unique non-zero seed. + //*************************************************************************** + random_multiply_with_carry::random_multiply_with_carry() + { + // An attempt to come up with a unique non-zero seed, + // based on the address of the instance. + uintptr_t n = reinterpret_cast(this); + uint32_t seed = static_cast(n); + initialise(seed); + } + + //*************************************************************************** + /// Constructor with seed value. + ///\param seed The new seed value. + //*************************************************************************** + random_multiply_with_carry::random_multiply_with_carry(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void random_multiply_with_carry::initialise(uint32_t seed) + { + value1 = seed; + value2 = seed; + } + + //*************************************************************************** + /// Get the next random_lsfr number. + //*************************************************************************** + uint32_t random_multiply_with_carry::operator()() + { + value1 = 36969 * (value1 & 0xFFFF) + (value1 >> 16); + value2 = 18000 * (value2 & 0xFFFF) + (value2 >> 16); + + return (value1 << 16) + value2; + } + + //*************************************************************************** + /// Get the next random_lsfr number in a specified inclusive range. + //*************************************************************************** + uint32_t random_multiply_with_carry::range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } } \ No newline at end of file diff --git a/src/random.h b/src/random.h index 5221b41c..1b040fcc 100644 --- a/src/random.h +++ b/src/random.h @@ -124,8 +124,6 @@ namespace etl //*************************************************************************** /// A 32 bit random number generator. /// Uses a linear shift feedback register. - /// Set ITERATIONS_ to control the number of times that the lfsr is iterated on each call. - /// Default = 1 /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register //*************************************************************************** class random_lsfr : public random @@ -142,6 +140,26 @@ namespace etl uint32_t value; }; + + //*************************************************************************** + /// A 32 bit random number generator. + /// Uses a multiply with carry calculation. + //*************************************************************************** + class random_multiply_with_carry : public random + { + public: + + random_multiply_with_carry(); + explicit random_multiply_with_carry(uint32_t seed); + void initialise(uint32_t seed); + uint32_t operator()(); + uint32_t range(uint32_t low, uint32_t high); + + private: + + uint32_t value1; + uint32_t value2; + }; } #endif \ No newline at end of file diff --git a/test/test_random.cpp b/test/test_random.cpp index cd0038aa..5518a269 100644 --- a/test/test_random.cpp +++ b/test/test_random.cpp @@ -238,7 +238,7 @@ namespace //========================================================================= TEST(test_random_lfsr_range) { - etl::random_lsfr r(7); + etl::random_lsfr r; uint32_t low = 1234; uint32_t high = 9876; @@ -251,5 +251,58 @@ namespace CHECK(n <= high); } } + + //========================================================================= + TEST(test_random_fast_sequence) + { + std::vector out1(10000); + etl::random_multiply_with_carry 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_multiply_with_carry.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_fast_range) + { + etl::random_multiply_with_carry 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); + } + } }; }