MeasureCalc: Added "UniqueRandom" option. When "1", random numbers are only used once within the range {LowBound, HighBound}.

Also updated the URNG (Uniform Random Number Generator) engine to the C++11 library <random>.
This commit is contained in:
Brian Ferguson 2013-08-15 18:12:36 -06:00
parent 61bcb92dee
commit f414b5feba
2 changed files with 84 additions and 18 deletions

View File

@ -21,7 +21,8 @@
#include "MeasureCalc.h" #include "MeasureCalc.h"
#include "Rainmeter.h" #include "Rainmeter.h"
bool MeasureCalc::c_RandSeeded = false; #define DEFAULT_LOWER_BOUND 0
#define DEFAULT_UPPER_BOUND 100
/* /*
** The constructor ** The constructor
@ -29,17 +30,15 @@ bool MeasureCalc::c_RandSeeded = false;
*/ */
MeasureCalc::MeasureCalc(MeterWindow* meterWindow, const WCHAR* name) : Measure(meterWindow, name), MeasureCalc::MeasureCalc(MeterWindow* meterWindow, const WCHAR* name) : Measure(meterWindow, name),
m_ParseError(false), m_ParseError(false),
m_LowBound(), m_LowBound(DEFAULT_LOWER_BOUND),
m_HighBound(100), m_HighBound(DEFAULT_UPPER_BOUND),
m_UpdateRandom(false) m_UpdateRandom(false),
m_UniqueRandom(false),
m_Engine(),
m_Distrubtion()
{ {
if (!c_RandSeeded) std::random_device device;
{ m_Engine.seed(device());
c_RandSeeded = true;
srand((unsigned)time(0));
}
rand();
} }
/* /*
@ -83,20 +82,49 @@ void MeasureCalc::ReadOptions(ConfigParser& parser, const WCHAR* section)
int oldLowBound = m_LowBound; int oldLowBound = m_LowBound;
int oldHighBound = m_HighBound; int oldHighBound = m_HighBound;
bool oldUpdateRandom = m_UpdateRandom; bool oldUpdateRandom = m_UpdateRandom;
bool oldUniqueRandom = m_UniqueRandom;
std::wstring oldFormula = m_Formula; std::wstring oldFormula = m_Formula;
m_Formula = parser.ReadString(section, L"Formula", L""); m_Formula = parser.ReadString(section, L"Formula", L"");
m_LowBound = parser.ReadInt(section, L"LowBound", 0); m_LowBound = parser.ReadInt(section, L"LowBound", DEFAULT_LOWER_BOUND);
m_HighBound = parser.ReadInt(section, L"HighBound", 100); m_HighBound = parser.ReadInt(section, L"HighBound", DEFAULT_UPPER_BOUND);
m_UpdateRandom = parser.ReadBool(section, L"UpdateRandom", false); m_UpdateRandom = parser.ReadBool(section, L"UpdateRandom", false);
m_UniqueRandom = parser.ReadBool(section, L"UniqueRandom", false);
if (!m_UniqueRandom)
{
m_UniqueNumbers.clear();
}
if (!m_Initialized || if (!m_Initialized ||
wcscmp(m_Formula.c_str(), oldFormula.c_str()) != 0 || wcscmp(m_Formula.c_str(), oldFormula.c_str()) != 0 ||
oldLowBound != m_LowBound || oldLowBound != m_LowBound ||
oldHighBound != m_HighBound || oldHighBound != m_HighBound ||
oldUpdateRandom != m_UpdateRandom) oldUpdateRandom != m_UpdateRandom ||
oldUniqueRandom != m_UniqueRandom)
{ {
// Reset bounds if |m_LowBound| is greater than or equal to |m_HighBound|
if (m_LowBound >= m_HighBound)
{
LogErrorF(this, L"\"LowBound\" (%i) must be less then \"HighBound\" (%i)", m_LowBound, m_HighBound);
m_LowBound = DEFAULT_LOWER_BOUND;
m_HighBound = DEFAULT_UPPER_BOUND;
// Change the option as well to avoid reset in ReadOptions().
parser.SetValue(section, L"LowBound", std::to_wstring(m_LowBound));
parser.SetValue(section, L"HighBound", std::to_wstring(m_HighBound));
}
// Reset the list if the bounds are changed
if (m_UniqueRandom && (
oldLowBound != m_LowBound ||
oldHighBound != m_HighBound))
{
UpdateUniqueNumberList();
}
if (!m_UpdateRandom) if (!m_UpdateRandom)
{ {
FormulaReplace(); FormulaReplace();
@ -177,7 +205,38 @@ bool MeasureCalc::GetMeasureValue(const WCHAR* str, int len, double* value, void
int MeasureCalc::GetRandom() int MeasureCalc::GetRandom()
{ {
double range = (m_HighBound - m_LowBound) + 1; int value = 0;
srand((unsigned)rand());
return m_LowBound + (int)(range * rand() / (RAND_MAX + 1.0)); if (m_UniqueRandom)
{
if (m_UniqueNumbers.empty())
{
UpdateUniqueNumberList();
}
value = m_UniqueNumbers.back();
m_UniqueNumbers.pop_back();
}
else
{
std::uniform_int_distribution<int>::param_type params(m_LowBound, m_HighBound);
m_Distrubtion.param(params);
m_Distrubtion.reset();
value = m_Distrubtion(m_Engine);
}
return value;
}
void MeasureCalc::UpdateUniqueNumberList()
{
m_UniqueNumbers.clear();
for (int i = m_LowBound; i <= m_HighBound; ++i)
{
m_UniqueNumbers.push_back(i);
}
std::shuffle(m_UniqueNumbers.begin(), m_UniqueNumbers.end(), m_Engine);
m_UniqueNumbers.shrink_to_fit();
} }

View File

@ -20,6 +20,7 @@
#define __MEASURECALC_H__ #define __MEASURECALC_H__
#include "Measure.h" #include "Measure.h"
#include <random>
class MeasureCalc : public Measure class MeasureCalc : public Measure
{ {
@ -46,8 +47,14 @@ private:
int m_HighBound; int m_HighBound;
bool m_UpdateRandom; bool m_UpdateRandom;
bool m_UniqueRandom;
static bool c_RandSeeded; std::vector<int> m_UniqueNumbers;
void UpdateUniqueNumberList();
// Uniform Random Number Generator
std::default_random_engine m_Engine;
std::uniform_int_distribution<int> m_Distrubtion;
}; };
#endif #endif