Common: Add xorshift-based PRNG class

pull/3374/head
Stenzek 2 weeks ago
parent b57049f1aa
commit 2f5c4d819e
No known key found for this signature in database

@ -67,6 +67,7 @@ add_library(common
timer.cpp
timer.h
types.h
xorshift_prng.h
)
target_include_directories(common PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")

@ -50,6 +50,7 @@
<ClInclude Include="types.h" />
<ClInclude Include="minizip_helpers.h" />
<ClInclude Include="windows_headers.h" />
<ClInclude Include="xorshift_prng.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="assert.cpp" />

@ -53,6 +53,7 @@
<ClInclude Include="sha256_digest.h" />
<ClInclude Include="thirdparty\aes.h" />
<ClInclude Include="task_queue.h" />
<ClInclude Include="xorshift_prng.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="small_string.cpp" />

@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: 2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC0-1.0
#pragma once
#include "types.h"
class XorShift128PlusPlus
{
public:
struct State
{
u64 s0;
u64 s1;
};
static constexpr State GetInitialState(u64 seed)
{
u64 x = seed;
return State{SplitMix64(x), SplitMix64(x)};
}
constexpr XorShift128PlusPlus() : m_state(GetInitialState(0)) {}
constexpr XorShift128PlusPlus(u64 seed) : m_state(GetInitialState(seed)) {}
ALWAYS_INLINE const State& GetState() const { return m_state; }
State* GetMutableStatePtr() { return &m_state; }
void SetState(State& state) { m_state = state; }
void Reset(u64 seed) { m_state = GetInitialState(seed); }
u64 Next()
{
// https://xoroshiro.di.unimi.it/xoroshiro128plusplus.c
u64 s0 = m_state.s0;
u64 s1 = m_state.s1;
u64 result = RotateLeft64(s0 + s1, 17) + s0;
s1 ^= s0;
m_state.s0 = RotateLeft64(s0, 49) ^ s1 ^ (s1 << 21); // a, b
m_state.s1 = RotateLeft64(s1, 28); // c
return result;
}
ALWAYS_INLINE u64 NextRange(u64 n)
{
// This constant should be folded.
const u64 max_allowed_value = (UINT64_C(0xFFFFFFFFFFFFFFFF) / n) * n;
for (;;)
{
const u64 x = Next();
if (x > max_allowed_value)
continue;
return x % n;
}
}
template<typename T>
ALWAYS_INLINE T NextRange(T low, T high)
{
return low + static_cast<T>(NextRange(static_cast<u64>(high - low)));
}
private:
static constexpr u64 SplitMix64(u64& x)
{
// https://xoroshiro.di.unimi.it/splitmix64.c
u64 z = (x += 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
static ALWAYS_INLINE u64 RotateLeft64(const u64 x, int k) { return (x << k) | (x >> (64 - k)); }
State m_state;
};
Loading…
Cancel
Save