GY-63_MS5611/libraries/randomHelpers/randomHelpers.cpp
2023-11-16 20:20:16 +01:00

305 lines
5.2 KiB
C++

//
// FILE: randomHelpers.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.7
// PURPOSE: Arduino library with helper function for faster random bits
// URL: https://github.com/RobTillaart/randomHelpers
#include "randomHelpers.h"
// the idea is to have one buffer ( __randomBuffer) which holds 32 random bits.
// Every call fetches bits from that buffer and if it does not hold enough
// bits any more it fills the buffer first. This way the relative expensive
// calls to random() which produces a 32 bit number are minimized in an
// efficient way.
//
// TBD: put it in a class ?
uint32_t __randomBuffer = 0;
uint8_t __randomIdx = 0;
///////////////////////////////////////////////////////////////////////////
//
// An example of a simple pseudo-random number generator is the
// Multiply-with-carry method invented by George Marsaglia.
// it has two initializers (not zero) which can be changed
// to seed the generator.
//
uint32_t m_w = 1;
uint32_t m_z = 2;
uint32_t Marsaglia()
{
m_z = 36969L * (m_z & 65535L) + (m_z >> 16);
m_w = 18000L * (m_w & 65535L) + (m_w >> 16);
return (m_z << 16) + m_w; /* 32-bit result */
}
bool seedMarsaglia(uint32_t a, uint32_t b)
{
if (a == 0 || b == 0)
{
// fill a and b with built-in generator?
return false;
}
m_w = a;
m_z = b;
return true;
}
//////////////////////////////////////////////////////////
//
// GETTERS
//
bool getRandom1()
{
if (__randomIdx < 1)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
bool rv = __randomBuffer & 0x01;
__randomBuffer >>= 1;
__randomIdx--;
return rv;
}
uint8_t getRandom2()
{
if (__randomIdx < 2)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint8_t rv = __randomBuffer & 0x03;
__randomBuffer >>= 2;
__randomIdx -= 2;
return rv;
}
uint8_t getRandom3()
{
if (__randomIdx < 3)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint8_t rv = __randomBuffer & 0x07;
__randomBuffer >>= 3;
__randomIdx -= 3;
return rv;
}
uint8_t getRandom4()
{
if (__randomIdx < 4)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint8_t rv = __randomBuffer & 0x0F;
__randomBuffer >>= 4;
__randomIdx -= 4;
return rv;
}
uint8_t getRandom5()
{
if (__randomIdx < 5)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint8_t rv = __randomBuffer & 0x1F;
__randomBuffer >>= 5;
__randomIdx -= 5;
return rv;
}
uint8_t getRandom6()
{
if (__randomIdx < 6)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint8_t rv = __randomBuffer & 0x3F;
__randomBuffer >>= 6;
__randomIdx -= 6;
return rv;
}
uint8_t getRandom7()
{
if (__randomIdx < 7)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint8_t rv = __randomBuffer & 0x7F;
__randomBuffer >>= 7;
__randomIdx -= 7;
return rv;
}
uint8_t getRandom8()
{
if (__randomIdx < 8)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint8_t rv = __randomBuffer & 0xFF;
__randomBuffer >>= 8;
__randomIdx -= 8;
return rv;
}
uint16_t getRandom16()
{
if (__randomIdx < 16)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint16_t rv = __randomBuffer & 0xFFFF;
__randomBuffer >>= 16;
__randomIdx -= 16;
return rv;
}
uint32_t getRandom24()
{
return getRandom32() & 0xFFFFFF;
}
uint32_t getRandom32()
{
// return random(0xFFFFFFFF); // use the built in
return Marsaglia();
}
uint64_t getRandom64()
{
uint64_t rv = getRandom32();
rv <<= 32;
rv |= getRandom32();
return rv;
}
/////////////////////////////////////////////////
//
// TYPICAL USES
//
bool inline flipCoin()
{
return getRandom1();
}
// div3() derived from divmod3() from fast_math.h
//
uint32_t div3(uint32_t in)
{
uint32_t q = (in >> 1) + (in >> 3);
q = q + (q >> 4);
q = q + (q >> 8);
q = q + (q >> 16);
q = q >> 1;
uint32_t r = in - q * 3;
q = q + (r * 86 >> 8);
return q;
}
uint8_t throwDice()
{
if (__randomIdx < 16)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint32_t tmp = div3(__randomBuffer) >> 1; // divide by 6
uint8_t rv = __randomBuffer - tmp * 6 + 1; // remainder + 1
__randomBuffer >>= 3;
__randomIdx -= 3;
return rv;
// previous.
// uint8_t rv = __randomBuffer % 6 + 1; // remainder + 1
// __randomBuffer >>= 3;
// __randomIdx -= 3;
// return rv;
}
/*
// works well for 1..16; but above it is worse
uint32_t getRandomBits(uint8_t n)
{
if (__randomIdx < n)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint32_t rv = __randomBuffer & ((1UL << n) - 1);
__randomBuffer >>= n;
__randomIdx -= n;
return rv;
}
*/
// n = 1..31
// TODO: performance gain too low for n > 16
uint32_t getRandomBits(uint8_t n)
{
uint32_t rv = 0;
// for large values of n the more straightforward approach is faster (UNO).
if (n > 32) n = 32;
if (n >= 20) return getRandom32() >> (32 - n);
if (n >= __randomIdx)
{
if (__randomIdx > 0)
{
n -= __randomIdx;
rv = __randomBuffer << n;
}
__randomBuffer = getRandom32();
__randomIdx = 32;
}
if (n > 0) // more bits needed?
{
rv |= __randomBuffer & ((1UL << n) - 1);
__randomBuffer >>= n;
__randomIdx -= n;
}
return rv;
}
// -- END OF FILE --