Struct Xoroshiro128Plus
A lightweight, fast RNG using the xoroshiro128+ algorithm. Ideal for memory-constrained scenarios or when many independent RNG streams are needed.
Implements
Inherited Members
Namespace: Scylla.Core.Util.Random
Assembly: ScyllaCore.dll
Syntax
[Serializable]
public struct Xoroshiro128Plus : IRandomSource
Remarks
xoroshiro128+ (Vigna/Blackman) is a high-quality 64-bit PRNG with:
- 128-bit internal state (two 64-bit words) - half the size of xoshiro256**
- Period of 2^128 - 1
- Very fast generation: rotate, XOR, and shift only
- Good statistical quality; note that the lowest 1-3 bits have a slight linear bias and should be avoided for applications requiring extremely uniform low-bit distribution (e.g., do not use the raw lowest bit as a coin flip)
Best suited for:
- Memory-constrained scenarios where state footprint matters
- Spawning many independent RNG streams (e.g., one per game entity)
- Applications that consume values primarily through upper-bit extraction, such as floating-point numbers or bounded ranges
For best quality with no low-bit caveats, prefer Xoshiro256StarStar. For multi-stream deterministic systems, see PCG32.
The generator is a value type (struct) with a 16-byte footprint.
Be aware that assigning a Xoroshiro128Plus value copies its state;
two copies seeded identically will produce the same sequence. Use Fork(ulong)
to derive independent child streams without duplicating sequences.
State can be captured and restored with GetState() and SetState(Xoroshiro128State), enabling deterministic replay and save/load functionality.
Methods
Fork(ulong)
Creates a new independent child Xoroshiro128Plus RNG derived from this instance's current state and the provided stream ID. The parent generator's state is not advanced by this call.
Declaration
public Xoroshiro128Plus Fork(ulong streamID)
Parameters
| Type | Name | Description |
|---|---|---|
| ulong | streamID | A 64-bit identifier that distinguishes the forked stream from other forks of the same parent. Different stream IDs produce statistically independent child generators. Passing the same stream ID from the same parent state always produces the same child. |
Returns
| Type | Description |
|---|---|
| Xoroshiro128Plus | A new Xoroshiro128Plus instance with an independent state derived
from the parent state and |
Remarks
The fork mixes a rotated summary of the current 128-bit state with the stream ID (multiplied by the golden-ratio constant) via the SplitMix64 mixing function, then seeds a fresh generator from the result. This approach ensures:
- The same parent + stream ID pair always yields the same child generator.
- Forked generators are statistically independent of the parent and of each other when using different stream IDs.
- The parent generator continues from its current state unaffected.
Typical use: allocate one root generator per seed and fork one stream per entity, subsystem, or procedural layer to keep all sub-systems deterministic and independent.
FromSeed(int)
Creates a Xoroshiro128+ RNG from the specified 32-bit signed seed value.
Declaration
public static Xoroshiro128Plus FromSeed(int seed)
Parameters
| Type | Name | Description |
|---|---|---|
| int | seed | The 32-bit signed seed. It is reinterpreted as a 32-bit unsigned integer, then widened to 64 bits before being expanded via SplitMix64. |
Returns
| Type | Description |
|---|---|
| Xoroshiro128Plus | A fully initialized Xoroshiro128Plus instance. |
FromSeed(long)
Creates a Xoroshiro128+ RNG from the specified 64-bit signed seed value.
Declaration
public static Xoroshiro128Plus FromSeed(long seed)
Parameters
| Type | Name | Description |
|---|---|---|
| long | seed | The 64-bit signed seed. It is reinterpreted bit-for-bit as a |
Returns
| Type | Description |
|---|---|
| Xoroshiro128Plus | A fully initialized Xoroshiro128Plus instance. |
FromSeed(uint)
Creates a Xoroshiro128+ RNG from the specified 32-bit unsigned seed value.
Declaration
public static Xoroshiro128Plus FromSeed(uint seed)
Parameters
| Type | Name | Description |
|---|---|---|
| uint | seed | The 32-bit unsigned seed. It is widened to 64 bits before being expanded via SplitMix64. |
Returns
| Type | Description |
|---|---|
| Xoroshiro128Plus | A fully initialized Xoroshiro128Plus instance. |
FromSeed(ulong)
Creates a Xoroshiro128+ RNG using the specified 64-bit unsigned seed value. The seed is expanded via SplitMix64 into two 64-bit state words, and the resulting state is guaranteed non-zero.
Declaration
public static Xoroshiro128Plus FromSeed(ulong seed)
Parameters
| Type | Name | Description |
|---|---|---|
| ulong | seed | The seed value used to initialize the RNG state. Two distinct SplitMix64 outputs are generated from the seed to populate the two state words. All seed values, including zero, produce valid non-degenerate states. |
Returns
| Type | Description |
|---|---|
| Xoroshiro128Plus | A fully initialized Xoroshiro128Plus instance. |
FromString(string)
Creates a Xoroshiro128+ RNG from a stable hash of the given string. The string is hashed using FNV-1a to produce a reproducible 64-bit seed, making this useful for named procedural seeds (e.g., level names, world IDs).
Declaration
public static Xoroshiro128Plus FromString(string seed)
Parameters
| Type | Name | Description |
|---|---|---|
| string | seed | The string used to generate a stable, cross-platform seed hash. The same string always produces the same RNG sequence on any platform. |
Returns
| Type | Description |
|---|---|
| Xoroshiro128Plus | A fully initialized Xoroshiro128Plus instance. |
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown if |
GetState()
Retrieves the current internal state of the RNG for serialization or checkpointing.
Declaration
public Xoroshiro128State GetState()
Returns
| Type | Description |
|---|---|
| Xoroshiro128State | An Xoroshiro128State struct containing the current values of both 64-bit state words. Restoring this snapshot via SetState(Xoroshiro128State) will reproduce the exact same sequence of values from this point forward. |
NextBytes(byte[], int, int)
Fills a specified portion of a byte array with random bytes generated by the xoroshiro128+ algorithm.
Declaration
public void NextBytes(byte[] buffer, int offset = 0, int count = -1)
Parameters
| Type | Name | Description |
|---|---|---|
| byte[] | buffer | The byte array to populate. Must not be |
| int | offset | The zero-based index in |
| int | count | The number of bytes to write starting at |
Remarks
Each call to NextUInt64() produces 8 bytes written in little-endian order (least-significant byte first). Any unused bytes from the final 64-bit draw are discarded.
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
| ArgumentOutOfRangeException | Thrown when |
NextUInt32()
Returns an unsigned 32-bit random value derived from the upper 32 bits of a full 64-bit xoroshiro128+ output.
Declaration
public uint NextUInt32()
Returns
| Type | Description |
|---|---|
| uint | A uniformly distributed unsigned 32-bit integer in the range
[ |
Remarks
Calls NextUInt64() and discards the lower 32 bits. Using the upper bits avoids the slight low-bit linear bias present in xoroshiro128+. One full 64-bit state step is consumed per call regardless.
NextUInt64()
Returns an unsigned 64-bit random value using the xoroshiro128+ algorithm.
Declaration
public ulong NextUInt64()
Returns
| Type | Description |
|---|---|
| ulong | A uniformly distributed unsigned 64-bit integer in the range
[ |
Remarks
The output is computed as s0 + s1 before the state is advanced.
The state update applies:
s1 ^= s0s0 = rotl(s0, 24) ^ s1 ^ (s1 << 16)s1 = rotl(s1, 37)
The rotation constants (24, 37) and the shift (16) are the reference parameters from the xoroshiro128+ specification. The addition output function provides excellent high-bit quality while the total cost is just three bitwise operations and two rotations.
SetState(Xoroshiro128State)
Restores the RNG to a previously saved state, enabling deterministic replay from a known checkpoint.
Declaration
public void SetState(Xoroshiro128State state)
Parameters
| Type | Name | Description |
|---|---|---|
| Xoroshiro128State | state | The state snapshot to restore. If both S0 and
S1 are zero (an invalid all-zero state),
|
Remarks
The xoroshiro128+ algorithm must never have an all-zero state. If a zero state is detected after restoration, the implementation corrects it automatically rather than throwing an exception, allowing graceful recovery from corrupt saves.