Make DqnRnd a class, make array memapi aware

This commit is contained in:
Doyle Thai 2017-11-08 21:32:06 +11:00
parent 25098ca74c
commit 2f6624fad7
2 changed files with 43 additions and 44 deletions

71
dqn.h
View File

@ -540,6 +540,7 @@ template <typename T>
bool DqnArray<T>::Resize(i64 newMax) bool DqnArray<T>::Resize(i64 newMax)
{ {
if (!this->data) return false; if (!this->data) return false;
if (!this->memAPI.callback) return false;
i64 oldSize = this->max * sizeof(T); i64 oldSize = this->max * sizeof(T);
i64 newSize = newMax * sizeof(T); i64 newSize = newMax * sizeof(T);
@ -1468,22 +1469,18 @@ DQN_FILE_SCOPE i32 Dqn_I32ToWStr(i32 value, wchar_t *buf, i32 bufSize);
// #DqnRnd Public API - Random Number Generator // #DqnRnd Public API - Random Number Generator
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// PCG (Permuted Congruential Generator) Random Number Generator // PCG (Permuted Congruential Generator) Random Number Generator
typedef struct DqnRandPCGState class DqnRndPCG
{ {
public:
u64 state[2]; u64 state[2];
} DqnRandPCGState;
// pcg: Pass in a pointer to a zero-cleared DqnRandPCGState void Init (); // Uses rdstc to create a seed
DQN_FILE_SCOPE void DqnRnd_PCGInitWithSeed(DqnRandPCGState *pcg, u32 seed); void InitWithSeed(u32 seed);
// Uses __rdtsc() to create a seed. TODO(doyle): This requires the platform layer.
DQN_FILE_SCOPE void DqnRnd_PCGInit(DqnRandPCGState *pcg);
// return: A random number N between [0, 0xFFFFFFFF] u32 Next (); // return: A random number N between [0, 0xFFFFFFFF]
DQN_FILE_SCOPE u32 DqnRnd_PCGNext (DqnRandPCGState *pcg); f32 Nextf(); // return: A random float N between [0.0, 1.0f]
// return: A random float N between [0.0, 1.0f] i32 Range(i32 min, i32 max); // return: A random integer N between [min, max]
DQN_FILE_SCOPE f32 DqnRnd_PCGNextf(DqnRandPCGState *pcg); };
// return: A random integer N between [min, max]
DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// #Dqn_* Public API // #Dqn_* Public API
@ -1525,11 +1522,10 @@ DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const i32 size,
} }
#endif #endif
DqnRandPCGState state = {}; DqnRndPCG state; state.Init();
DqnRnd_PCGInit(&state);
i32 lastIndex = size - 1; i32 lastIndex = size - 1;
i32 pivotIndex = DqnRnd_PCGRange(&state, 0, lastIndex); i32 pivotIndex = state.Range(0, lastIndex);
i32 partitionIndex = 0; i32 partitionIndex = 0;
i32 startIndex = 0; i32 startIndex = 0;
@ -5169,7 +5165,7 @@ union DqnRndInternal_U32F32
f32 float32; f32 float32;
}; };
FILE_SCOPE f32 DqnRnd_F32NormalizedFromU32Internal(u32 value) FILE_SCOPE f32 DqnRndInternal_F32NormalizedFromU32(u32 value)
{ {
u32 exponent = 127; u32 exponent = 127;
u32 mantissa = value >> 9; u32 mantissa = value >> 9;
@ -5179,7 +5175,7 @@ FILE_SCOPE f32 DqnRnd_F32NormalizedFromU32Internal(u32 value)
return uf.float32 - 1.0f; return uf.float32 - 1.0f;
} }
FILE_SCOPE u64 DqnRnd_Murmur3Avalanche64Internal(u64 h) FILE_SCOPE u64 DqnRndInternal_Murmur3Avalanche64(u64 h)
{ {
h ^= h >> 33; h ^= h >> 33;
h *= 0xff51afd7ed558ccd; h *= 0xff51afd7ed558ccd;
@ -5193,7 +5189,7 @@ FILE_SCOPE u64 DqnRnd_Murmur3Avalanche64Internal(u64 h)
#include <x86intrin.h> // __rdtsc #include <x86intrin.h> // __rdtsc
#endif #endif
FILE_SCOPE u32 DqnRnd_MakeSeedInternal() FILE_SCOPE u32 DqnRndInternal_MakeSeed()
{ {
#if defined(DQN_WIN32_PLATFORM) || defined(DQN_UNIX_PLATFORM) #if defined(DQN_WIN32_PLATFORM) || defined(DQN_UNIX_PLATFORM)
i64 numClockCycles = __rdtsc(); i64 numClockCycles = __rdtsc();
@ -5207,43 +5203,46 @@ FILE_SCOPE u32 DqnRnd_MakeSeedInternal()
#endif #endif
} }
DQN_FILE_SCOPE void DqnRnd_PCGInitWithSeed(DqnRandPCGState *pcg, u32 seed) void DqnRndPCG::InitWithSeed(u32 seed)
{ {
u64 value = (((u64)seed) << 1ULL) | 1ULL; u64 value = (((u64)seed) << 1ULL) | 1ULL;
value = DqnRnd_Murmur3Avalanche64Internal(value); value = DqnRndInternal_Murmur3Avalanche64(value);
pcg->state[0] = 0U; this->state[0] = 0U;
pcg->state[1] = (value << 1ULL) | 1ULL; this->state[1] = (value << 1ULL) | 1ULL;
DqnRnd_PCGNext(pcg); this->Next();
pcg->state[0] += DqnRnd_Murmur3Avalanche64Internal(value); this->state[0] += DqnRndInternal_Murmur3Avalanche64(value);
DqnRnd_PCGNext(pcg); this->Next();
} }
DQN_FILE_SCOPE void DqnRnd_PCGInit(DqnRandPCGState *pcg) void DqnRndPCG::Init()
{ {
u32 seed = DqnRnd_MakeSeedInternal(); u32 seed = DqnRndInternal_MakeSeed();
DqnRnd_PCGInitWithSeed(pcg, seed); this->InitWithSeed(seed);
} }
DQN_FILE_SCOPE u32 DqnRnd_PCGNext(DqnRandPCGState *pcg) u32 DqnRndPCG::Next()
{ {
u64 oldstate = pcg->state[0]; u64 oldstate = this->state[0];
pcg->state[0] = oldstate * 0x5851f42d4c957f2dULL + pcg->state[1]; this->state[0] = oldstate * 0x5851f42d4c957f2dULL + this->state[1];
u32 xorshifted = (u32)(((oldstate >> 18ULL) ^ oldstate) >> 27ULL); u32 xorshifted = (u32)(((oldstate >> 18ULL) ^ oldstate) >> 27ULL);
u32 rot = (u32)(oldstate >> 59ULL); u32 rot = (u32)(oldstate >> 59ULL);
return (xorshifted >> rot) | (xorshifted << ((-(i32)rot) & 31)); return (xorshifted >> rot) | (xorshifted << ((-(i32)rot) & 31));
} }
DQN_FILE_SCOPE f32 DqnRnd_PCGNextf(DqnRandPCGState *pcg) f32 DqnRndPCG::Nextf()
{ {
return DqnRnd_F32NormalizedFromU32Internal(DqnRnd_PCGNext(pcg)); f32 result = DqnRndInternal_F32NormalizedFromU32(this->Next());
return result;
} }
DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max) i32 DqnRndPCG::Range(i32 min, i32 max)
{ {
i32 const range = (max - min) + 1; i32 const range = (max - min) + 1;
if (range <= 0) return min; if (range <= 0) return min;
i32 const value = (i32)(DqnRnd_PCGNextf(pcg) * range);
return min + value; i32 const value = (i32)(this->Nextf() * range);
i32 result = min + value;
return result;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -641,18 +641,19 @@ void DqnTimer_Test()
void DqnRnd_Test() void DqnRnd_Test()
{ {
LogHeader("Random Number Generator Test"); LogHeader("Random Number Generator Test");
DqnRandPCGState pcg;
DqnRnd_PCGInit(&pcg); DqnRndPCG pcg; pcg.Init();
for (i32 i = 0; i < 1000000; i++) for (i32 i = 0; i < 1000000; i++)
{ {
i32 min = -100; i32 min = -100;
i32 max = 1000000000; i32 max = 1000000000;
i32 result = DqnRnd_PCGRange(&pcg, min, max); i32 result = pcg.Range(min, max);
DQN_ASSERT(result >= min && result <= max); DQN_ASSERT(result >= min && result <= max);
f32 randF32 = DqnRnd_PCGNextf(&pcg); f32 randF32 = pcg.Nextf();
DQN_ASSERT(randF32 >= 0.0f && randF32 <= 1.0f); DQN_ASSERT(randF32 >= 0.0f && randF32 <= 1.0f);
} }
printf("RandomTest(): RndPCG: Completed successfully\n"); printf("RandomTest(): RndPCG: Completed successfully\n");
printf("RandomTest(): Completed successfully\n"); printf("RandomTest(): Completed successfully\n");
} }
@ -1992,8 +1993,7 @@ FILE_SCOPE void DqnJobQueue_Test()
void DqnQuickSort_Test() void DqnQuickSort_Test()
{ {
LogHeader("DqnSort vs std::Sort"); LogHeader("DqnSort vs std::Sort");
DqnRandPCGState state = {}; DqnRndPCG state; state.Init();
DqnRnd_PCGInit(&state);
if (1) if (1)
{ {
DqnMemStack stack = {}; DqnMemStack stack = {};
@ -2017,7 +2017,7 @@ void DqnQuickSort_Test()
// Populate with random numbers // Populate with random numbers
for (u32 i = 0; i < numInts; i++) for (u32 i = 0; i < numInts; i++)
{ {
dqnCPPArray[i] = DqnRnd_PCGNext(&state); dqnCPPArray[i] = state.Next();
stdArray[i] = dqnCPPArray[i]; stdArray[i] = dqnCPPArray[i];
} }