68 lines
1.3 KiB
C#
68 lines
1.3 KiB
C#
using System.Runtime.CompilerServices;
|
|
using ILGPU;
|
|
|
|
namespace PerfectNumbers.Core.Gpu;
|
|
|
|
public static class ThreadStaticDeterministicRandomGpu
|
|
{
|
|
[ThreadStatic]
|
|
private static DeterministicRandomGpu? _exclusive;
|
|
internal static DeterministicRandomGpu Exclusive => _exclusive ?? new DeterministicRandomGpu();
|
|
}
|
|
|
|
internal struct DeterministicRandomGpu
|
|
{
|
|
private static long s_seedCounter;
|
|
|
|
public ulong State;
|
|
|
|
public DeterministicRandomGpu()
|
|
{
|
|
State = CreateThreadState();
|
|
}
|
|
|
|
public DeterministicRandomGpu(ulong initialState)
|
|
{
|
|
State = initialState;
|
|
}
|
|
|
|
public ulong NextUInt64()
|
|
{
|
|
ulong state = State;
|
|
state ^= state >> 12;
|
|
state ^= state << 25;
|
|
state ^= state >> 27;
|
|
State = state;
|
|
return state * 2685821657736338717UL;
|
|
}
|
|
|
|
public GpuUInt128 NextUInt128()
|
|
{
|
|
GpuUInt128 high = (GpuUInt128)NextUInt64();
|
|
ReadOnlyGpuUInt128 low = (ReadOnlyGpuUInt128)NextUInt64();
|
|
high.ShiftLeft(64);
|
|
high.Add(low);
|
|
return high;
|
|
}
|
|
|
|
public void SetState(ulong state)
|
|
{
|
|
State = state;
|
|
}
|
|
|
|
private static ulong CreateThreadState()
|
|
{
|
|
ulong seed = (ulong)Atomic.Add(ref s_seedCounter, 1);
|
|
seed += 0x9E3779B97F4A7C15UL;
|
|
seed = (seed ^ (seed >> 30)) * 0xBF58476D1CE4E5B9UL;
|
|
seed = (seed ^ (seed >> 27)) * 0x94D049BB133111EBUL;
|
|
seed ^= seed >> 31;
|
|
if (seed == 0UL)
|
|
{
|
|
seed = 0x9E3779B97F4A7C15UL;
|
|
}
|
|
|
|
return seed;
|
|
}
|
|
}
|