[*] (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() = 0;
|
||||||
virtual AuUInt32 NextU32(AuUInt32 uMin, AuUInt32 uMax) = 0;
|
virtual AuUInt32 NextU32(AuUInt32 uMin, AuUInt32 uMax) = 0;
|
||||||
virtual AuUInt64 NextU64() = 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 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 AuUInt32 NextIndex(AuUInt32 uCount /* = max + 1*/) = 0;
|
||||||
|
|
||||||
virtual Memory::MemoryViewRead ToSeed() = 0;
|
virtual Memory::MemoryViewRead ToSeed() = 0;
|
||||||
|
@ -202,9 +202,87 @@ namespace Aurora::RNG
|
|||||||
return uMin + uNext;
|
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()
|
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*/)
|
AuUInt32 RandomDevice::NextIndex(AuUInt32 uCount /* = max + 1*/)
|
||||||
@ -218,11 +296,11 @@ namespace Aurora::RNG
|
|||||||
}
|
}
|
||||||
return uNext;
|
return uNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
float RandomDevice::NextNumber(float fMin, float fMax)
|
double RandomDevice::NextNumber(double dMin, double dMax)
|
||||||
{
|
{
|
||||||
auto fRange = fMax - fMin;
|
auto dRange = dMin - dMin;
|
||||||
return NextDecimal() * fRange + fMin;
|
return this->UniformFloatInRange(0.0, dRange) + dMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuMemoryViewRead RandomDevice::ToSeed()
|
AuMemoryViewRead RandomDevice::ToSeed()
|
||||||
|
@ -24,10 +24,10 @@ namespace Aurora::RNG
|
|||||||
bool NextBoolean() override;
|
bool NextBoolean() override;
|
||||||
AuUInt32 NextU32() override;
|
AuUInt32 NextU32() override;
|
||||||
AuUInt64 NextU64() 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;
|
AuUInt32 NextU32(AuUInt32 uMin, AuUInt32 uMax) override;
|
||||||
double NextDecimal() 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;
|
AuUInt32 NextIndex(AuUInt32 uCount /* = max + 1*/) override;
|
||||||
|
|
||||||
AuMemoryViewRead ToSeed() override;
|
AuMemoryViewRead ToSeed() override;
|
||||||
@ -37,5 +37,8 @@ namespace Aurora::RNG
|
|||||||
private:
|
private:
|
||||||
RandomDef def_;
|
RandomDef def_;
|
||||||
WELLRand fast_;
|
WELLRand fast_;
|
||||||
|
|
||||||
|
bool DecGeometric(int x);
|
||||||
|
double UniformFloatInRange(double udMin, double udMax);
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user