Added multipy with carry random number generator.

This commit is contained in:
John Wellbelove 2017-08-08 18:41:00 +01:00
parent 04ac745454
commit e660e5b949
3 changed files with 134 additions and 3 deletions

View File

@ -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<uintptr_t>(this);
uint32_t seed = static_cast<uint32_t>(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;
}
}

View File

@ -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

View File

@ -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<uint32_t> 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);
}
}
};
}