Files
picovga-RGsB/_picovga/util/rand.cpp
2021-06-10 19:07:49 +02:00

466 lines
12 KiB
C++

// ****************************************************************************
//
// Random number generator
//
// ****************************************************************************
#include "include.h"
// global random generator
cRandom Rand;
// global Gaussian random float number generator
cGaussFRandom GaussFRand;
// global Gaussian random double number generator
cGaussDRandom GaussDRand;
// ============================================================================
// Set random seed from ROSC counter
// ============================================================================
void cRandom::InitSeed()
{
int i;
for (i = 64; i > 0; i--) m_Seed = (m_Seed << 1) | (rosc_hw->randombit & 1);
i = (this->U8() & 0x1f) + 5;
for (; i > 0; i--) this->Shift();
}
// ============================================================================
// generate random number in full range of BYTE
// ============================================================================
u8 cRandom::U8()
{
this->Shift();
return (u8)(m_Seed >> (64-8));
}
// ============================================================================
// generate random number in full range of WORD
// ============================================================================
u16 cRandom::U16()
{
this->Shift();
return (u16)(m_Seed >> (64-16));
}
// ============================================================================
// generate random number in full range of DWORD
// ============================================================================
u32 cRandom::U32()
{
this->Shift();
return (u32)(m_Seed >> (64-32));
}
// ============================================================================
// generate random number in full range of QWORD
// ============================================================================
u64 cRandom::U64()
{
this->Shift();
u32 k = m_Seed >> 32;
this->Shift();
return ((u64)k << 32) | (m_Seed >> 32);
}
// ============================================================================
// generate float random number in range 0 (including) to 1 (excluding)
// ============================================================================
float cRandom::Float()
{
this->Shift();
return (float)(m_Seed >> (64-24))*(1.0f/0x1000000);
}
// ============================================================================
// generate double random number in range 0 (including) to 1 (excluding)
// ============================================================================
double cRandom::Double()
{
this->Shift();
return (double)(m_Seed >> (64-52))*(1.0/0x10000000000000ULL);
}
// ============================================================================
// generate BYTE random number in range 0 to MAX (including)
// ============================================================================
u8 cRandom::U8Max(u8 max)
{
u8 res;
u8 mask;
// zero maximal value
if (max == 0) return 0;
// prepare mask
res = 0xff;
do {
mask = res;
res >>= 1;
} while (res >= max);
// generate random number
do {
res = this->U8() & mask;
} while (res > max);
return res;
}
// ============================================================================
// generate WORD random number in range 0 to MAX (including)
// ============================================================================
u16 cRandom::U16Max(u16 max)
{
u16 res;
u16 mask;
// zero maximal value
if (max == 0) return 0;
// prepare mask
res = 0xffff;
do {
mask = res;
res >>= 1;
} while (res >= max);
// generate random number
do {
res = this->U16() & mask;
} while (res > max);
return res;
}
// ============================================================================
// generate DWORD random number in range 0 to MAX (including)
// ============================================================================
u32 cRandom::U32Max(u32 max)
{
u32 res;
u32 mask;
// zero maximal value
if (max == 0) return 0;
// prepare mask
res = 0xffffffff;
do {
mask = res;
res >>= 1;
} while (res >= max);
// generate random number
do {
res = this->U32() & mask;
} while (res > max);
return res;
}
// ============================================================================
// generate QWORD random number in range 0 to MAX (including)
// ============================================================================
u64 cRandom::U64Max(u64 max)
{
u64 res;
u64 mask;
// DWORD value
if (max <= 0xffffffff) return this->U32Max(max);
// prepare mask
res = 0xffffffffffffffffULL;
do {
mask = res;
res >>= 1;
} while (res >= max);
// generate random number
do {
res = this->U64() & mask;
} while (res > max);
return res;
}
// ============================================================================
// generate CHAR random number in range 0 to MAX (including, can be negative)
// ============================================================================
s8 cRandom::S8Max(s8 max)
{
if (max >= 0)
return (s8)this->U8Max((u8)max);
else
return -(s8)this->U8Max((u8)-max);
}
// ============================================================================
// generate SHORT random number in range 0 to MAX (including, can be negative)
// ============================================================================
s16 cRandom::S16Max(s16 max)
{
if (max >= 0)
return (s16)this->U16Max((u16)max);
else
return -(s16)this->U16Max((u16)-max);
}
// ============================================================================
// generate LONG random number in range 0 to MAX (including, can be negative)
// ============================================================================
s32 cRandom::S32Max(s32 max)
{
if (max >= 0)
return (s32)this->U32Max((u32)max);
else
return -(s32)this->U32Max((u32)-max);
}
// ============================================================================
// generate INT64 random number in range 0 to MAX (including, can be negative)
// ============================================================================
s64 cRandom::S64Max(s64 max)
{
if (max >= 0)
return (s64)this->U64Max((u64)max);
else
return -(s64)this->U64Max((u64)-max);
}
// ============================================================================
// generate float random number in range 0 (including) to MAX (excluding)
// ============================================================================
float cRandom::FloatMax(float max) { return this->Float() * max; }
// ============================================================================
// generate double random number in range 0 (including) to MAX (excluding)
// ============================================================================
double cRandom::DoubleMax(double max) { return this->Double() * max; }
// ============================================================================
// generate random number in range MIN to MAX (including)
// ============================================================================
// If MIN > MAX, then number is generated out of interval.
u8 cRandom::U8MinMax(u8 min, u8 max)
{
return this->U8Max(max - min) + min;
}
u16 cRandom::U16MinMax(u16 min, u16 max)
{
return this->U16Max(max - min) + min;
}
u32 cRandom::U32MinMax(u32 min, u32 max)
{
return this->U32Max(max - min) + min;
}
u64 cRandom::U64MinMax(u64 min, u64 max)
{
return this->U64Max(max - min) + min;
}
s8 cRandom::S8MinMax(s8 min, s8 max)
{
return (s8)this->U8Max(max - min) + min;
}
s16 cRandom::S16MinMax(s16 min, s16 max)
{
return (s16)this->U16Max(max - min) + min;
}
s32 cRandom::S32MinMax(s32 min, s32 max)
{
return (s32)this->U32Max(max - min) + min;
}
s64 cRandom::S64MinMax(s64 min, s64 max)
{
return (s64)this->U64Max(max - min) + min;
}
float cRandom::FloatMinMax(float min, float max)
{
return this->FloatMax(max - min) + min;
}
double cRandom::DoubleMinMax(double min, double max)
{
return this->DoubleMax(max - min) + min;
}
// ============================================================================
// generate Gaussian random number (mean = center, sigma = width)
// ============================================================================
float cGaussFRandom::Gauss(float mean /* = 0 */, float sigma /* = 1 */)
{
float x, y, r;
Bool cache = m_CacheOK;
m_CacheOK = !cache;
if (cache)
return m_Cache*sigma + mean;
else
{
do {
x = this->m_Rand.Float()*2 - 1;
y = this->m_Rand.Float()*2 - 1;
r = x*x + y*y;
} while ((r == 0) || (r > 1));
r = sqrtf(-2*logf(r)/r);
m_Cache = y*r;
return x*r*sigma + mean;
}
}
double cGaussDRandom::Gauss(double mean /* = 0 */, double sigma /* = 1 */)
{
double x, y, r;
Bool cache = m_CacheOK;
m_CacheOK = !cache;
if (cache)
return m_Cache*sigma + mean;
else
{
do {
x = this->m_Rand.Double()*2 - 1;
y = this->m_Rand.Double()*2 - 1;
r = x*x + y*y;
} while ((r == 0) || (r > 1));
r = sqrt(-2*log(r)/r);
m_Cache = y*r;
return x*r*sigma + mean;
}
}
// ============================================================================
// 1D coordinate noise generator (output -1..+1)
// ============================================================================
float Noise1D(int x, int seed)
{
int n = x + seed*1327;
n = (n << 13) ^ n;
return 1 - (float)(int)((n*(n*n*15731 + 789221) + 1376312589) & 0x7fffffff)/0x40000000;
}
// ============================================================================
// 2D coordinate noise generator (output -1..+1)
// ============================================================================
float Noise2D(int x, int y, int seed)
{
int n = x + y*321 + seed*1327;
n = (n << 13) ^ n;
return 1 - (float)(int)((n*(n*n*15731 + 789221) + 1376312589) & 0x7fffffff)/0x40000000;
}
// ============================================================================
// 3D coordinate noise generator (output -1..+1)
// ============================================================================
float Noise3D(int x, int y, int z, int seed)
{
int n = x + y*321 + z*51327 + seed*1327;
n = (n << 13) ^ n;
return 1 - (float)(int)((n*(n*n*15731 + 789221) + 1376312589) & 0x7fffffff)/0x40000000;
}
// ============================================================================
// interpolated 1D noise (output -1..+1, scale = 1...)
// ============================================================================
float SmoothNoise1D(float x, int scale, int seed)
{
// scale coordinates
x *= scale;
// remainder
int x1 = (int)floor(x);
x -= x1;
// coordinates
x1 = x1 % scale;
if (x1 < 0) x1 += scale;
int x0 = (x1 + scale - 1) % scale;
int x2 = (x1 + 1) % scale;
int x3 = (x2 + 1) % scale;
// noise in points
float k0 = Noise1D(x0, seed);
float k1 = Noise1D(x1, seed);
float k2 = Noise1D(x2, seed);
float k3 = Noise1D(x3, seed);
// cubic interpolate noise
float p = (k3 - k2) - (k0 - k1);
float q = (k0 - k1) - p;
float r = k2 - k0;
float s = k1;
return (((p*x + q)*x + r)*x + s)*(float)0.92;
}
// ============================================================================
// interpolated 2D noise (output -1..+1, scale = 1...)
// ============================================================================
float SmoothNoise2D(float x, float y, int scale, int seed)
{
// scale coordinates
x *= scale;
y *= scale;
// remainder
int x1 = (int)floor(x);
x -= x1;
int y1 = (int)floor(y);
y -= y1;
// coordinates
x1 = x1 % scale;
if (x1 < 0) x1 += scale;
int x2 = (x1 + 1) % scale;
y1 = y1 % scale;
if (y1 < 0) y1 += scale;
int y2 = (y1 + 1) % scale;
// noise in points
float k11 = Noise2D(x1, y1, seed);
float k21 = Noise2D(x2, y1, seed);
float k12 = Noise2D(x1, y2, seed);
float k22 = Noise2D(x2, y2, seed);
// interpolate noise
float k1 = k11*(1-x) + k21*x;
float k2 = k12*(1-x) + k22*x;
return k1*(1-y) + k2*y;
}