document the Random class

pull/5/head
cosmonaut 2023-10-13 13:18:14 -07:00
parent 35934baec0
commit 3a7c9da309
1 changed files with 55 additions and 10 deletions

View File

@ -3,8 +3,10 @@ using System.Runtime.CompilerServices;
namespace MoonTools.ECS namespace MoonTools.ECS
{ {
// WELLRNG512 /// <summary>
// https://stackoverflow.com/a/1227137 /// This class implements the well equidistributed long-period linear pseudorandom number generator.
/// Code taken from Chris Lomont: http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf
/// </summary>
public class Random public class Random
{ {
public const int STATE_BYTE_COUNT = 68; // 16 state ints + 1 index int public const int STATE_BYTE_COUNT = 68; // 16 state ints + 1 index int
@ -13,11 +15,17 @@ namespace MoonTools.ECS
uint Index = 0; uint Index = 0;
uint Seed; uint Seed;
/// <summary>
/// Initializes the RNG with an arbitrary seed.
/// </summary>
public Random() public Random()
{ {
Init((uint) Environment.TickCount); Init((uint) Environment.TickCount);
} }
/// <summary>
/// Initializes the RNG with a given seed.
/// </summary>
public void Init(uint seed) public void Init(uint seed)
{ {
Seed = seed; Seed = seed;
@ -30,11 +38,17 @@ namespace MoonTools.ECS
Index = 0; Index = 0;
} }
/// <summary>
/// Returns the seed that was used to initialize the RNG.
/// </summary>
public uint GetSeed() public uint GetSeed()
{ {
return Seed; return Seed;
} }
/// <summary>
/// Returns the entire state of the RNG as a string.
/// </summary>
public string PrintState() public string PrintState()
{ {
var s = ""; var s = "";
@ -46,7 +60,11 @@ namespace MoonTools.ECS
return s; return s;
} }
// expects a span of STATE_BYTE_COUNT bytes /// <summary>
/// Saves the entire state of the RNG to a Span.
/// </summary>
/// <param name="bytes">Must be a span of at least STATE_BYTE_COUNT bytes.</param>
/// <exception cref="ArgumentException">Thrown if the byte span is too short.</exception>
public unsafe void SaveState(Span<byte> bytes) public unsafe void SaveState(Span<byte> bytes)
{ {
#if DEBUG #if DEBUG
@ -69,7 +87,11 @@ namespace MoonTools.ECS
} }
} }
// expects a span of STATE_BYTE_COUNT bytes /// <summary>
/// Loads the entire state of the RNG from a Span.
/// </summary>
/// <param name="bytes">Must be a span of at least STATE_BYTE_COUNT bytes.</param>
/// <exception cref="ArgumentException">Thrown if the byte span is too short.</exception>
public unsafe void LoadState(Span<byte> bytes) public unsafe void LoadState(Span<byte> bytes)
{ {
#if DEBUG #if DEBUG
@ -109,17 +131,25 @@ namespace MoonTools.ECS
return State[Index]; return State[Index];
} }
// .NET Random API always returns a non-negative signed int. Fun! /// <summary>
/// Returns a non-negative signed integer.
/// </summary>
public int Next() public int Next()
{ {
return (int) (NextInternal() >>> 1); // unsigned bitshift right to get rid of signed bit return (int) (NextInternal() >>> 1); // unsigned bitshift right to get rid of signed bit
} }
public int Next(int n) /// <summary>
/// Returns a non-negative signed integer less than max.
/// </summary>
public int Next(int max)
{ {
return (int) (((double) Next()) * n / int.MaxValue); return (int) (((double) Next()) * max / int.MaxValue);
} }
/// <summary>
/// Returns a signed integer greater than or equal to min and less than max.
/// </summary>
public int Next(int min, int max) public int Next(int min, int max)
{ {
var diff = max - min; var diff = max - min;
@ -127,6 +157,9 @@ namespace MoonTools.ECS
return min + next; return min + next;
} }
/// <summary>
/// Returns a non-negative signed 64 bit integer.
/// </summary>
public long NextInt64() public long NextInt64()
{ {
long next = NextInternal(); long next = NextInternal();
@ -136,12 +169,18 @@ namespace MoonTools.ECS
return next; return next;
} }
public long NextInt64(long n) /// <summary>
/// Returns a non-negative signed 64 bit integer less than max.
/// </summary>
public long NextInt64(long max)
{ {
var next = NextInt64(); var next = NextInt64();
return (long) (((double) next) * n / long.MaxValue); return (long) (((double) next) * max / long.MaxValue);
} }
/// <summary>
/// Returns a non-negative signed 64 bit integer greater than or equal to min and less than max.
/// </summary>
public long NextInt64(long min, long max) public long NextInt64(long min, long max)
{ {
var diff = max - min; var diff = max - min;
@ -149,12 +188,18 @@ namespace MoonTools.ECS
return min + next; return min + next;
} }
public float NextFloat() /// <summary>
/// Returns a single-precision floating point value between 0 and 1.
/// </summary>
public float NextSingle()
{ {
var n = NextInternal(); var n = NextInternal();
return ((float) n) / uint.MaxValue; return ((float) n) / uint.MaxValue;
} }
/// <summary>
/// Returns a double-precision floating point value between 0 and 1.
/// </summary>
public double NextDouble() public double NextDouble()
{ {
var n = NextInternal(); var n = NextInternal();