Struct PCG32
A PCG32 random number generator (Permuted Congruential Generator). Provides excellent statistical quality with a compact 128-bit state and native support for multiple independent, non-overlapping streams via a configurable increment.
Implements
Inherited Members
Namespace: Scylla.Core.Util.Random
Assembly: ScyllaCore.dll
Syntax
[Serializable]
public struct PCG32 : IRandomSource
Remarks
PCG32 (O'Neill, 2014) is a high-quality 32-bit PRNG with:
- 128-bit internal state (64-bit LCG state + 64-bit odd increment)
- Period of 2^64 per stream
- Excellent statistical quality (passes PractRand and TestU01 BigCrush)
- Native multi-stream support: different stream IDs yield completely independent, non-overlapping sequences from the same seed
Best suited for:
- Multi-stream deterministic systems (e.g., one stream per entity or subsystem)
- Compact serializable save states
- Any scenario requiring excellent quality from a minimal-footprint generator
The generator is a value type (struct) with a 16-byte footprint, making it
efficient to embed in components or pass by reference. Be aware that assigning a
PCG32 value copies its state; two copies seeded identically will
produce the same sequence.
State can be captured and restored with GetState() and SetState(PCG32State), enabling deterministic replay and save/load functionality.
Methods
FromSeed(int, ulong)
Creates a PCG32 RNG from the specified 32-bit signed seed value.
Declaration
public static PCG32 FromSeed(int seed, ulong stream = 0)
Parameters
| Type | Name | Description |
|---|---|---|
| int | seed | The seed value. It is zero-extended to an unsigned 64-bit integer before being passed to the primary FromSeed(ulong, ulong) overload. |
| ulong | stream | An optional stream identifier selecting one of 2^63 independent sequences.
Defaults to |
Returns
| Type | Description |
|---|---|
| PCG32 | A fully initialized PCG32 instance. |
FromSeed(long, ulong)
Creates a PCG32 RNG from the specified 64-bit signed seed value.
Declaration
public static PCG32 FromSeed(long seed, ulong stream = 0)
Parameters
| Type | Name | Description |
|---|---|---|
| long | seed | The seed value. It is reinterpreted as an unsigned 64-bit integer before being passed to the primary FromSeed(ulong, ulong) overload. |
| ulong | stream | An optional stream identifier selecting one of 2^63 independent sequences.
Defaults to |
Returns
| Type | Description |
|---|---|
| PCG32 | A fully initialized PCG32 instance. |
FromSeed(uint, ulong)
Creates a PCG32 RNG from the specified 32-bit unsigned seed value.
Declaration
public static PCG32 FromSeed(uint seed, ulong stream = 0)
Parameters
| Type | Name | Description |
|---|---|---|
| uint | seed | The seed value. It is widened to 64 bits before being passed to the primary FromSeed(ulong, ulong) overload. |
| ulong | stream | An optional stream identifier selecting one of 2^63 independent sequences.
Defaults to |
Returns
| Type | Description |
|---|---|
| PCG32 | A fully initialized PCG32 instance. |
FromSeed(ulong, ulong)
Creates a PCG32 RNG using the specified seed and optional stream ID.
Declaration
public static PCG32 FromSeed(ulong seed, ulong stream = 0)
Parameters
| Type | Name | Description |
|---|---|---|
| ulong | seed | The seed value that determines the starting position within the selected stream. Different seeds on the same stream produce different sequences with no statistical correlation. |
| ulong | stream | An optional stream identifier that selects one of 2^63 independent, non-overlapping
output sequences. Defaults to |
Returns
| Type | Description |
|---|---|
| PCG32 | A fully initialized PCG32 instance ready to generate values. |
Remarks
Initialization follows the reference PCG implementation warm-up procedure:
- State is set to zero and one advance is performed (state becomes the increment).
- The seed is added to the state.
- A second advance is performed to thoroughly mix seed and stream together.
This ensures that generators seeded with different stream values
produce statistically independent sequences even when given the same
seed.
FromString(string, ulong)
Creates a PCG32 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 PCG32 FromString(string seed, ulong stream = 0)
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. |
| ulong | stream | An optional stream identifier selecting one of 2^63 independent sequences.
Defaults to |
Returns
| Type | Description |
|---|---|
| PCG32 | A fully initialized PCG32 instance. |
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown if |
GetState()
Retrieves the current internal state of the RNG for serialization or checkpointing.
Declaration
public PCG32State GetState()
Returns
| Type | Description |
|---|---|
| PCG32State | A PCG32State struct containing the current LCG state and increment. Restoring this snapshot via SetState(PCG32State) will reproduce the exact same sequence of values from this point forward. |
Remarks
The returned struct is a plain value copy. The stream identity (increment) is preserved alongside the state, so the restored generator will behave on the same stream as the original.
NextBytes(byte[], int, int)
Fills a specified portion of a byte array with random bytes generated by the PCG32 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 NextUInt32() produces 4 bytes written in little-endian order (least-significant byte first). Any unused bytes from the final 32-bit draw are discarded.
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
| ArgumentOutOfRangeException | Thrown when |
NextUInt32()
Returns an unsigned 32-bit random value using the PCG-XSH-RR output function.
Declaration
public uint NextUInt32()
Returns
| Type | Description |
|---|---|
| uint | A uniformly distributed unsigned 32-bit integer in the range
[ |
Remarks
Each call advances the 64-bit LCG state via
state = state * PCG_MULTIPLIER + _inc, then applies the
XSH-RR (XOR-Shift-High, Random-Rotate) permutation to produce a 32-bit output:
- XOR the state with itself shifted right by 18 positions, then shift right by 27 to select the high 32 bits after mixing.
- Use the top 5 bits of the old state as a rotation amount and apply a right-rotate to the result.
The rotation step means that all output bits depend on all input state bits, producing excellent avalanche behavior. The output quality is statistically superior to the raw LCG state.
NextUInt64()
Returns an unsigned 64-bit random value by combining two consecutive 32-bit outputs.
Declaration
public ulong NextUInt64()
Returns
| Type | Description |
|---|---|
| ulong | A 64-bit unsigned integer assembled by placing the first NextUInt32() result in the high 32 bits and the second in the low 32 bits. Consumes two LCG steps per call. |
Remarks
Because PCG32 is a 32-bit generator, producing a full 64-bit value requires two sequential NextUInt32() calls. If only 32 bits are needed, prefer calling NextUInt32() directly to avoid consuming an extra state step. For natively 64-bit output, see Xoshiro256StarStar or Xoroshiro128Plus.
SetState(PCG32State)
Restores the RNG to a previously saved state, enabling deterministic replay from a known checkpoint.
Declaration
public void SetState(PCG32State state)
Parameters
| Type | Name | Description |
|---|---|---|
| PCG32State | state | The state snapshot to restore. The increment stored in Inc is forced to be odd if it is even, as the PCG32 algorithm requires an odd increment for a full-period LCG. |
Remarks
If the saved Inc value is even (which would indicate a corrupt or manually constructed state), the least-significant bit is set to restore a valid odd increment before use.