GY-63_MS5611/libraries/randomHelpers/randomHelpers.cpp
2022-11-23 13:56:17 +01:00

229 lines
4.0 KiB
C++

#pragma once
//
// FILE: randomHelpers.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.5
// 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) return false;
m_w = a;
m_z = b;
return true;
}
uint32_t getRandom32()
{
// return random(0xFFFFFFFF); // use the built in
return Marsaglia();
}
bool getRandom1()
{
if (__randomIdx < 1)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
bool rv = __randomBuffer & 0x01;
__randomBuffer >>= 1;
__randomIdx--;
return rv;
}
// typical use
bool inline flipCoin()
{
return getRandom1();
};
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;
}
// typical use
uint8_t throwDice()
{
if (__randomIdx < 16)
{
__randomBuffer = getRandom32();
__randomIdx = 32;
}
uint16_t rv = __randomBuffer % 6 + 1;
__randomBuffer >>= 3;
__randomIdx -= 3;
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;
}
uint64_t getRandom64()
{
uint64_t rv = getRandom32();
rv <<= 32;
rv |= getRandom32();
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 --