Class RandomStream
One stream of the MRG32k3a generator: a virtual random number generator occupying its own block of 2^127 values, itself divided into 2^51 substreams of 2^76 values.
public sealed class RandomStream
- Inheritance
-
RandomStream
- Inherited Members
Remarks
Streams are handed out by a RandomStreamFactory, or rebuilt from a snapshot with FromState(RandomStreamState, string?). Each new stream starts 2^127 values beyond the previous one, so streams taken from the same factory never overlap in any practical run.
A stream is not thread safe. The intended pattern is one stream per worker.
Internally the recurrence runs on 64 bit integers with no conditional branches, rather than on the exact double-precision arithmetic of L'Ecuyer (1999), Figure 1. The observable sequence is identical and does not depend on the floating point behaviour of the host, so results match across x64 and ARM64 and across every target framework of this library.
Properties
Antithetic
Gets or sets whether this stream returns antithetic variates, that is one minus the value it would otherwise return.
public bool Antithetic { get; set; }
Property Value
Remarks
The flag does not change how far a draw advances the state, so a stream and its antithetic twin stay synchronised. Turning the flag off restores the plain sequence.
In high-precision mode the reflection is applied to each of the two underlying draws rather than to the value they combine into. The two differ in the last bits.
CurrentState
Gets the current state of this stream.
public Mrg32k3aState CurrentState { get; }
Property Value
HighPrecision
Gets or sets whether NextDouble() returns roughly 53 bits of precision instead of 32, at the cost of advancing the state by two steps instead of one.
public bool HighPrecision { get; set; }
Property Value
Remarks
The high-precision value is the first draw plus the second draw weighted by 2^-24, reduced modulo one. When Antithetic is also set, both draws are reflected first and the weighted term carries an offset of minus one. Switching the flag changes how fast a stream is consumed, so it should be set before a stream is used rather than part way through.
Name
Gets or sets the label carried by this stream.
[AllowNull]
public string Name { get; set; }
Property Value
Remarks
Setting null stores an empty label, as everywhere else a name is accepted.
StreamStartState
Gets the initial state of this stream.
public Mrg32k3aState StreamStartState { get; }
Property Value
SubstreamIndex
Gets the zero-based index of the substream this stream is currently inside.
public long SubstreamIndex { get; }
Property Value
Remarks
A stream holds 2^51 substreams, so the index runs from zero to 2^51 - 1. It is part of the stream's state: it is carried by Clone() and by SaveState(), and it is what lets SkipSubstreams(long) tell whether a move would leave this stream's block. Only the substream operations change it; drawing values and Advance(long) do not.
SubstreamStartState
Gets the state at the start of the substream this stream is currently inside.
public Mrg32k3aState SubstreamStartState { get; }
Property Value
Methods
Advance(long)
Moves the current position of this stream by an arbitrary signed number of steps, leaving its initial state and its substream start untouched.
public void Advance(long steps)
Parameters
stepslongSteps to move; negative values move backwards.
Remarks
To move 2^e + c steps, call AdvanceByPowerOfTwo(int) (or RetreatByPowerOfTwo(int))
with exponent e and then Advance(long) with c. Both are escape hatches. Ordinary use is served by the
reset methods and by taking more streams from the factory.
Unlike the substream operations, this one does not refuse to leave the stream's own block. A position inside a substream can be 2^76 steps from its start, which no long can express, so there is no offset to check a move against. Enough steps here will walk into a neighbouring stream, which is the price of the escape hatch.
AdvanceByPowerOfTwo(int)
Moves the current position of this stream forwards by 2^exponent steps,
leaving its initial state and its substream start untouched.
public void AdvanceByPowerOfTwo(int exponent)
Parameters
exponentintA base-two exponent between 0 and 255 inclusive.
Exceptions
- ArgumentOutOfRangeException
exponentis outside the supported range.
AsRandom()
Presents this stream as a Random, for APIs and libraries that ask for the framework type.
public StreamBackedRandom AsRandom()
Returns
- StreamBackedRandom
A new adapter that draws from this stream, so draws through either one advance the same state.
Clone()
Creates an independent copy of this stream at its present position.
public RandomStream Clone()
Returns
- RandomStream
A stream that will produce the same values as this one from now on.
FromState(RandomStreamState, string?)
Rebuilds a stream from a snapshot taken by SaveState().
public static RandomStream FromState(RandomStreamState state, string? name = null)
Parameters
stateRandomStreamStateThe snapshot to restore.
namestringAn optional label overriding the one in the snapshot.
Returns
- RandomStream
A stream positioned exactly where the snapshot was taken.
Exceptions
- ArgumentNullException
stateis null.- ArgumentException
The snapshot is of an unknown version or holds an invalid state.
LoadState(RandomStreamState)
Restores this stream from a snapshot, discarding its present position.
public void LoadState(RandomStreamState state)
Parameters
stateRandomStreamStateThe snapshot to restore.
Remarks
The anchors of a snapshot have to agree: SubstreamStart must be the start of substream
SubstreamIndex of StreamStart, the relation every stream this library produces
satisfies. Checking it costs one modular matrix exponentiation and is what keeps a restored
stream inside its own block, since the substream operations trust the index to say where the
stream is.
Exceptions
- ArgumentNullException
stateis null.- ArgumentException
The snapshot is of an unknown version or holds an invalid state.
Next(int)
Draws an integer uniform over a half-open range starting at zero, following the .NET convention.
public int Next(int maxExclusive)
Parameters
maxExclusiveintOne past the largest value that can be returned.
Returns
- int
A value at least zero and below
maxExclusive, or zero whenmaxExclusiveis zero.
Exceptions
- ArgumentOutOfRangeException
maxExclusiveis negative.
Next(int, int)
Draws an integer uniform over a half-open range, following the .NET convention.
public int Next(int minInclusive, int maxExclusive)
Parameters
minInclusiveintSmallest value that can be returned.
maxExclusiveintOne past the largest value that can be returned.
Returns
- int
A value at least
minInclusiveand belowmaxExclusive, orminInclusivewhen the two bounds are equal.
Exceptions
- ArgumentOutOfRangeException
maxExclusiveis belowminInclusive.
NextDouble()
Draws the next value, uniform on the open interval from zero to one.
public double NextDouble()
Returns
- double
A value strictly between zero and one.
Remarks
Honours both Antithetic and HighPrecision. With high precision off the result is always an exact multiple of 1 / (2^32 - 208).
NextDoubleHighPrecision()
Draws the next value with roughly 53 bits of precision, advancing the state by two steps, whatever HighPrecision is set to.
public double NextDoubleHighPrecision()
Returns
- double
A value strictly between zero and one.
NextDoubles(double[])
Fills an array with values uniform on the open interval from zero to one.
public void NextDoubles(double[] buffer)
Parameters
bufferdouble[]The array to fill.
Exceptions
- ArgumentNullException
bufferis null.
NextDoubles(double[], int, int)
Fills part of an array with values uniform on the open interval from zero to one.
public void NextDoubles(double[] buffer, int offset, int count)
Parameters
bufferdouble[]The array to write into.
offsetintIndex of the first element to write.
countintNumber of elements to write.
Exceptions
- ArgumentNullException
bufferis null.- ArgumentOutOfRangeException
The range lies outside
buffer.
NextDoubles(Span<double>)
Fills a span with values uniform on the open interval from zero to one.
public void NextDoubles(Span<double> destination)
Parameters
NextInt32Inclusive(int, int)
Draws an integer uniform over a closed range.
public int NextInt32Inclusive(int min, int max)
Parameters
minintSmallest value that can be returned.
maxintLargest value that can be returned, included in the range.
Returns
- int
A value between
minandmaxinclusive.
Exceptions
- ArgumentOutOfRangeException
maxis belowmin.
NextInt32sInclusive(int, int, int[], int, int)
Fills part of an array with integers uniform over a closed range.
public void NextInt32sInclusive(int min, int max, int[] buffer, int offset, int count)
Parameters
minintSmallest value that can be produced.
maxintLargest value that can be produced, included in the range.
bufferint[]The array to write into.
offsetintIndex of the first element to write.
countintNumber of elements to write.
Exceptions
- ArgumentNullException
bufferis null.- ArgumentOutOfRangeException
The range lies outside
buffer, ormaxis belowmin.
NextInt32sInclusive(int, int, Span<int>)
Fills a span with integers uniform over a closed range.
public void NextInt32sInclusive(int min, int max, Span<int> destination)
Parameters
minintSmallest value that can be produced.
maxintLargest value that can be produced, included in the range.
destinationSpan<int>The span to fill.
Exceptions
- ArgumentOutOfRangeException
maxis belowmin.
NextInt64(long)
Draws an integer uniform over a half-open range starting at zero, following the .NET convention.
public long NextInt64(long maxExclusive)
Parameters
maxExclusivelongOne past the largest value that can be returned.
Returns
- long
A value at least zero and below
maxExclusive, or zero whenmaxExclusiveis zero.
Remarks
See NextInt64Inclusive(long, long) for how many distinct values a wide range can yield.
Exceptions
- ArgumentOutOfRangeException
maxExclusiveis negative.
NextInt64(long, long)
Draws an integer uniform over a half-open range, following the .NET convention.
public long NextInt64(long minInclusive, long maxExclusive)
Parameters
minInclusivelongSmallest value that can be returned.
maxExclusivelongOne past the largest value that can be returned.
Returns
- long
A value at least
minInclusiveand belowmaxExclusive, orminInclusivewhen the two bounds are equal.
Remarks
See NextInt64Inclusive(long, long) for how many distinct values a wide range can yield.
Exceptions
- ArgumentOutOfRangeException
maxExclusiveis belowminInclusive, or the range holds more than MaxValue values.
NextInt64Inclusive(long, long)
Draws an integer uniform over a closed range.
public long NextInt64Inclusive(long min, long max)
Parameters
minlongSmallest value that can be returned.
maxlongLargest value that can be returned, included in the range.
Returns
- long
A value between
minandmaxinclusive.
Remarks
This makes one call to NextDouble() and scales the result over the closed range. A single draw carries about 2^32 distinct values, or about 2^53 in high-precision mode, so over a range wider than that most values in the range can never be returned.
Exceptions
- ArgumentOutOfRangeException
maxis belowmin, or the range holds more than MaxValue values.
RetreatByPowerOfTwo(int)
Moves the current position of this stream backwards by 2^exponent steps,
leaving its initial state and its substream start untouched.
public void RetreatByPowerOfTwo(int exponent)
Parameters
exponentintA base-two exponent between 0 and 255 inclusive.
Exceptions
- ArgumentOutOfRangeException
exponentis outside the supported range.
RewindStream()
Returns this stream to its initial state, at the start of its first substream.
public void RewindStream()
RewindSubstream()
Returns this stream to the start of the substream it is currently inside.
public void RewindSubstream()
SaveState()
Captures everything needed to resume this stream later or elsewhere.
public RandomStreamState SaveState()
Returns
- RandomStreamState
A fresh snapshot, safe to serialize.
SkipSubstreams(long)
Moves this stream by a signed number of substreams, to the start of the substream it lands on.
public void SkipSubstreams(long count)
Parameters
countlongSubstreams to move; negative values move back towards the stream start.
Remarks
The cost grows with the logarithm of count rather than with
count itself, because the move is one modular matrix exponentiation per
component and not a run of substream jumps. Skipping a million substreams costs about as
much as skipping twenty.
A count of zero does nothing at all, and in particular does not return to the start of the current substream; RewindSubstream() does that.
Exceptions
- ArgumentOutOfRangeException
The move would leave this stream's own block, that is it would land before substream zero or at or beyond substream 2^51.
SkipToNextSubstream()
Moves this stream to the start of its next substream, 2^76 values further on.
public void SkipToNextSubstream()
Remarks
The exception is a guard on the partitioning rather than a case to program around: reaching it takes 2^51 calls. Use SkipSubstreams(long) to move by more than one substream at a time.
Exceptions
- InvalidOperationException
This stream is already on the last of its substreams, so a further one would lie outside its own block.
SkipToSubstream(long)
Moves this stream to the start of the substream at the given index of this stream.
public void SkipToSubstream(long index)
Parameters
indexlongA zero-based substream index below 2^51.
Remarks
The index is counted from the start of this stream, not from where it happens to be, so the
call lands in the same place however the stream was used beforehand. It is the operation to
use to resume a run at a known replication, or to give worker i substream i
without walking there. Its cost grows with the logarithm of index.
Exceptions
- ArgumentOutOfRangeException
indexis negative, or at or beyond the 2^51 substreams this stream holds.
ToDetailedString()
Returns the name of this stream, its three state vectors, its substream index, and its flags.
public string ToDetailedString()
Returns
- string
Several lines of text.
ToString()
Returns the name of this stream together with its current state.
public override string ToString()
Returns
- string
A single line of text.