Table of Contents

XorShiftRandom Class

Definition

Namespace
Bodu
Assembly
Bodu.Core.dll
Package
Bodu.Core 1.0.1
Source
XorShiftRandom.cs

Represents a high-performance, non-cryptographic pseudo-random number generator based on Marsaglia's xorshift128 algorithm.

public sealed class XorShiftRandom : Random, IRandomGenerator
Inheritance
XorShiftRandom
Implements
Inherited Members
Extension Methods

Examples

// Reproducible shuffle and sample in a test.
var rng = new XorShiftRandom(seed: 1234);
int    roll  = rng.Next(6) + 1;           // value in [1, 6]
double angle = rng.NextDouble() * Math.Tau;

var bag = new[] { "A", "B", "C", "D" };
ShuffleHelpers.Shuffle(bag, rng);

Remarks

XorShiftRandom derives each output by combining four 32-bit state words through three xor-and-shift operations - a generator class introduced by George Marsaglia in 2003. The cost per draw is a handful of register operations with no branching, no division, and no memory allocation, making it materially faster than Random in tight inner loops on every supported runtime.

The type subclasses Random so it can be passed anywhere Random is accepted, and it also implements IRandomGenerator for use with the library's shuffle and sampling helpers. The default constructor seeds from TickCount; the seeded constructors are the preferred choice in tests and reproducible benchmarks.

Instances are not thread-safe - state updates are non-atomic and concurrent draws will corrupt the internal state. Use a per-thread instance, an external lock, or a thread-local pool when sharing across threads is required.

The algorithm produces a uniform distribution over the 32-bit output range and has a period of 2^128 − 1. It is not suitable for cryptographic use, secret material, or any context where an attacker can observe outputs and recover state. Use System.Security.Cryptography.RandomNumberGenerator for those cases.

Constructors

XorShiftRandom()

Initializes a new instance of the XorShiftRandom class using a system-generated seed.

public XorShiftRandom()

Remarks

The default seed is derived from TickCount at the time of construction.

TickCount has finite resolution (commonly ~15.6 ms on Windows, finer on Linux), so two XorShiftRandom instances created back-to-back within the same tick will observe the same seed and therefore yield identical sequences. This is a deliberate trade-off for the cheapest possible default seeding on a non-cryptographic PRNG. Callers that require either guarantee should use a different constructor:

  • For reproducibility (tests, benchmarks, replayable simulations) use XorShiftRandom(int) or XorShiftRandom(uint) with an explicit seed.
  • For distinct sequences across many instances derive the seed from Shared (e.g. new XorShiftRandom(Random.Shared.Next())) or, when stronger entropy is required, from System.Security.Cryptography.RandomNumberGenerator.

XorShiftRandom(int)

Initializes a new instance of the XorShiftRandom class with a 32-bit signed integer seed.

public XorShiftRandom(int seed)

Parameters

seed int

The seed used to initialize the random generator.

XorShiftRandom(uint)

Initializes a new instance of the XorShiftRandom class with a 32-bit unsigned seed.

public XorShiftRandom(uint seed)

Parameters

seed uint

The seed used to initialize the random generator.

Methods

Next()

Returns a non-negative random integer.

public override int Next()

Returns

int

A 32-bit signed integer that is greater than or equal to 0 and less than Int32.MaxValue.

Next(int)

Returns a non-negative random integer that is strictly less than the specified exclusive upper bound.

public override int Next(int maxValue)

Parameters

maxValue int

The exclusive upper bound of the random number to be generated.

Returns

int

A 32-bit signed integer in the half-open interval [0, maxValue).

Remarks

Matches the contract of Next(int). Draws are produced through Lemire-style rejection rather than modulo, eliminating the modulo-bias that would otherwise skew small bounds.

Exceptions

ArgumentOutOfRangeException

maxValue is less than or equal to zero.

Next(int, int)

Returns a random integer in the half-open interval [minValue, maxValue).

public override int Next(int minValue, int maxValue)

Parameters

minValue int

The inclusive lower bound of the random number to be generated.

maxValue int

The exclusive upper bound of the random number to be generated.

Returns

int

A 32-bit signed integer greater than or equal to minValue and strictly less than maxValue; or minValue when the two bounds are equal.

Remarks

Matches the contract of Next(int, int), including its handling of an empty range: when minValue equals maxValue the method returns minValue without throwing. Only a strictly inverted range (minValue > maxValue) raises ArgumentException.

The full int span Next(int.MinValue, int.MaxValue) is supported - the range is computed in 64-bit space so the subtraction never overflows, and bounded generation uses Lemire-style rejection rather than modulo to avoid modulo-bias.

Exceptions

ArgumentException

minValue is strictly greater than maxValue.

NextBytes(byte[])

Fills the elements of a specified array of bytes with random numbers.

public override void NextBytes(byte[] buffer)

Parameters

buffer byte[]

The array to be filled with random numbers.

Exceptions

ArgumentNullException

buffer is null.

NextBytes(Span<byte>)

Fills the elements of a specified span of bytes with random numbers.

public override void NextBytes(Span<byte> buffer)

Parameters

buffer Span<byte>

The array to be filled with random numbers.

Remarks

The span is filled from consecutive 32-bit draws, four bytes per draw in little-endian order, with a trailing partial chunk taking the low-order bytes of one final draw. The packing is identical to NextBytes(byte[]), so for the same seed and length both overloads produce the same bytes.

NextDouble()

Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0.

public override double NextDouble()

Returns

double

A double-precision floating point number that is greater than or equal to 0.0, and less than 1.0.

Remarks

The result is derived from a single 32-bit draw, so it has 32-bit granularity: only 2^32 distinct values are possible, spaced 2^-32 apart, rather than the 2^53 values a full-precision double in [0, 1) could represent. This is sufficient for shuffling, sampling, and similar non-cryptographic uses; callers needing finer-grained doubles should compose them from two draws.

NextInt64()

Returns a non-negative random integer.

public override long NextInt64()

Returns

long

A 64-bit signed integer that is greater than or equal to 0 and less than Int64.MaxValue.

Remarks

The result is composed from two consecutive 32-bit draws of the generator stream - the first draw supplies the high word, the second the low word - reduced to 63 bits; a draw equal to MaxValue is rejected and redrawn so the contractual range [0, long.MaxValue) is preserved without bias.

NextSingle()

Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0.

public override float NextSingle()

Returns

float

A single-precision floating point number that is greater than or equal to 0.0, and less than 1.0.

Remarks

The result takes the high-order 24 bits of a single 32-bit draw of the generator stream and scales them by 2^-24, yielding a uniformly distributed float in [0.0f, 1.0f) whose granularity matches the 24-bit float significand exactly.

Applies to

ProductVersions
.NET8, 10