[*] (AuRandom) Resolve bad floating point distribution
This commit is contained in:
parent
741c7228d3
commit
cab8627ffd
@ -22,9 +22,9 @@ namespace Aurora::RNG
|
||||
virtual AuUInt32 NextU32() = 0;
|
||||
virtual AuUInt32 NextU32(AuUInt32 uMin, AuUInt32 uMax) = 0;
|
||||
virtual AuUInt64 NextU64() = 0;
|
||||
virtual AuInt32 NextInt(AuInt32 uMin, AuInt32 uMax) = 0;
|
||||
virtual AuInt32 NextInt(AuInt32 iMin, AuInt32 iMax) = 0;
|
||||
virtual double NextDecimal() = 0;
|
||||
virtual float NextNumber(float min, float max) = 0;
|
||||
virtual double NextNumber(double dMin, double dMax) = 0;
|
||||
virtual AuUInt32 NextIndex(AuUInt32 uCount /* = max + 1*/) = 0;
|
||||
|
||||
virtual Memory::MemoryViewRead ToSeed() = 0;
|
||||
|
@ -202,9 +202,87 @@ namespace Aurora::RNG
|
||||
return uMin + uNext;
|
||||
}
|
||||
|
||||
// Source: https://stackoverflow.com/a/5016867
|
||||
bool RandomDevice::DecGeometric(int x)
|
||||
{
|
||||
if (x <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto r = this->NextByte();
|
||||
|
||||
if (x < 8)
|
||||
{
|
||||
return (r & ((1 << x) - 1)) == 0;
|
||||
}
|
||||
else if (r != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
x -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Source: https://stackoverflow.com/a/5016867
|
||||
double RandomDevice::UniformFloatInRange(double udMin, double udMax)
|
||||
{
|
||||
#if defined(AURNG_USE_GARBAGE_DECIMALS)
|
||||
return (double(this->NextU32()) * (double(1.0) / double(AuNumericLimits<AuUInt32>::max()))) * udMax;
|
||||
#else
|
||||
union
|
||||
{
|
||||
double f;
|
||||
AuUInt64 u;
|
||||
} convert;
|
||||
|
||||
convert.f = udMin;
|
||||
auto uABits = convert.u;
|
||||
convert.f = udMax;
|
||||
auto uBBits = convert.u;
|
||||
|
||||
auto uMask = uBBits - uABits;
|
||||
uMask |= uMask >> 1;
|
||||
uMask |= uMask >> 2;
|
||||
uMask |= uMask >> 4;
|
||||
uMask |= uMask >> 8;
|
||||
uMask |= uMask >> 16;
|
||||
uMask |= uMask >> 32;
|
||||
|
||||
int bExp {};
|
||||
frexp(udMax, &bExp);
|
||||
|
||||
while (true)
|
||||
{
|
||||
int iXExp {};
|
||||
double x;
|
||||
|
||||
auto uXBits = this->NextU64();
|
||||
uXBits &= uMask;
|
||||
uXBits += uABits;
|
||||
if (uXBits >= uBBits)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
convert.u = uXBits;
|
||||
x = convert.f;
|
||||
frexp(x, &iXExp);
|
||||
|
||||
if (DecGeometric(bExp - iXExp))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
double RandomDevice::NextDecimal()
|
||||
{
|
||||
return double(NextU32()) * (double(1.0) / double(AuNumericLimits<AuUInt32>::max()));
|
||||
return this->UniformFloatInRange(0.0, 1.0);
|
||||
}
|
||||
|
||||
AuUInt32 RandomDevice::NextIndex(AuUInt32 uCount /* = max + 1*/)
|
||||
@ -218,11 +296,11 @@ namespace Aurora::RNG
|
||||
}
|
||||
return uNext;
|
||||
}
|
||||
|
||||
float RandomDevice::NextNumber(float fMin, float fMax)
|
||||
|
||||
double RandomDevice::NextNumber(double dMin, double dMax)
|
||||
{
|
||||
auto fRange = fMax - fMin;
|
||||
return NextDecimal() * fRange + fMin;
|
||||
auto dRange = dMin - dMin;
|
||||
return this->UniformFloatInRange(0.0, dRange) + dMin;
|
||||
}
|
||||
|
||||
AuMemoryViewRead RandomDevice::ToSeed()
|
||||
|
@ -24,10 +24,10 @@ namespace Aurora::RNG
|
||||
bool NextBoolean() override;
|
||||
AuUInt32 NextU32() override;
|
||||
AuUInt64 NextU64() override;
|
||||
AuInt32 NextInt(AuInt32 uMin, AuInt32 uMax) override;
|
||||
AuInt32 NextInt(AuInt32 iMin, AuInt32 iMax) override;
|
||||
AuUInt32 NextU32(AuUInt32 uMin, AuUInt32 uMax) override;
|
||||
double NextDecimal() override;
|
||||
float NextNumber(float min, float max) override;
|
||||
double NextNumber(double dMin, double dMax) override;
|
||||
AuUInt32 NextIndex(AuUInt32 uCount /* = max + 1*/) override;
|
||||
|
||||
AuMemoryViewRead ToSeed() override;
|
||||
@ -37,5 +37,8 @@ namespace Aurora::RNG
|
||||
private:
|
||||
RandomDef def_;
|
||||
WELLRand fast_;
|
||||
|
||||
bool DecGeometric(int x);
|
||||
double UniformFloatInRange(double udMin, double udMax);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user