Create and Control Random Number Streams
R2026bCreating your own random number streams is useful for several reasons:
You can generate random values without affecting the state of the global stream.
You can separate sources of randomness in a simulation.
You can specify different random number streams in different MATLAB® sessions and environments.
With a RandStream object,
you can create your own stream, configure the stream by setting its writable properties,
and use the stream to generate random numbers. You control the stream you create the
same way you control the global stream. You can even replace the global stream with the
stream you create.
Compared to the rng function, RandStream gives
you more control over random number generation. For instance, you can choose different
normal transformation algorithms, generate antithetic random values, and use different
substreams when generating random numbers.
Create and Use Random Number Stream
You can create one or more random number streams by using the RandStream object. For example, create a random number stream that
uses the multiplicative lagged Fibonacci generator algorithm. Then use that stream
to generate five random numbers.
myStream = RandStream("multFibonacci");
r = rand(myStream,1,5)r = 1×5
0.6986 0.7413 0.4239 0.6914 0.7255The random number stream myStream acts separately from the
global stream. If you call the rand, randi, randn, and randperm functions with
myStream as the first argument, they draw from the stream you
created without affecting the global stream. If you call rand,
randi, randn, and
randperm without myStream, they draw
from the global stream.
You can make myStream the global stream by using the RandStream.setGlobalStream
function.
RandStream.setGlobalStream(myStream) s = RandStream.getGlobalStream
s =
mlfg6331_64 random stream (current global stream)
Seed: 0
NormalTransform: Ziggurat
Choose a Random Number Generator
When creating a random number stream, you can specify a generator algorithm. This
table summarizes the key properties of the available generator algorithms, and
detailed technical descriptions of the generator algorithms and performance
measurement code follow. To return a table of all the available generator
algorithms, you can also use the RandStream.list function.
| Algorithm | Name | Multiple Stream and Substream Support | Multithreading Support | Description | Approximate Period in Full Precision |
|---|---|---|---|---|---|
| "simdTwister" | No | No | SIMD-oriented fast Mersenne Twister | 219937 – 1 |
| "v4" | No | No | Multiplicative congruential generator | 231 – 2 |
| "multFibonacci" | Yes | Yes | Multiplicative lagged Fibonacci generator | 2124 (251 streams of length 272) |
| "combRecursive" | Yes | Yes | Combined multiple recursive generator | 2191 (263 streams of length 2127) |
| "twister" | No | No | Mersenne Twister | 219937 – 1 |
| "pcg" | Yes | Yes | 64-bit permuted congruential generator with double xor-shift multiply | 2255 (263 streams of length 2192) |
| "philox" | Yes | Yes | Philox 4x32 generator with 10 rounds | 2193 (264 streams of length 2129) |
| "v5normal" | No | No | SHR3 shift-register generator summed with linear congruential generator | 264 |
| "v5uniform" | No | No | Modified subtract-with-borrow generator | 21492 |
| "threefry" | Yes | Yes | Threefry 4x64 generator with 20 rounds | 2514 (2256 streams of length 2258) |
| "xoshiro" | Yes | Yes | Xor-shift-rotate generator with 256-bit state and double addition | 2256 (264 streams of length 2192) |
Note
The mcg16807 (v4), shr3cong (v5normal),
and swb2712 (v5uniform) generators are provided for backward
compatibility with earlier versions of MATLAB. For more information, see Replace Discouraged Syntaxes of rand and randn.
The mt19937ar (twister) and dsfmt19937
(simdTwister) generators are designed primarily for sequential
applications, without multiple stream support. The remaining generators provide
explicit support for parallel random number generation.
Although the generator algorithms in MATLAB are deterministic, they produce sequences of numbers that pass statistical tests of randomness and satisfy the independent and identically distributed (i.i.d.) condition. The generator period, or how many random numbers a generator can produce before the sequence repeats, is rarely a limiting factor because the period is typically large enough for large-scale simulations. For example, the multiplicative lagged Fibonacci generator provides up to 251 independent streams, each of length 272. While 272 is the length of an individual stream rather than the full period (which is approximately 2124), 272 corresponds to about 4.72 × 1021 number before the sequence repeats, which is large enough for many applications.
Technical Descriptions of Generator Algorithms
dsfmt19937The double-precision SIMD-oriented fast Mersenne Twister, as described in [13], is a faster implementation of the Mersenne Twister algorithm. This generator has a period of , and the possible values are multiples of in the interval (0,1). The generator produces double-precision values in [1,2) natively and transforms them to create U(0,1) values, which are values that are uniformly distributed in the interval (0,1). This generator does not support multiple streams or substreams.
-
mcg16807 The 32-bit multiplicative congruential generator, as described in [16], has a multiplier , modulo . This generator has a period of . The generator uses one 32-bit integer to create each U(0,1) value. This generator does not support multiple streams or substreams.
This generator is provided for compatibility reasons and is identical to the one used by both the
randandrandnfunctions beginning in MATLAB Version 4, activated usingrand('seed',s)orrandn('seed',s).mlfg6331_64The 64-bit multiplicative lagged Fibonacci generator, as described in [11], has lags , . This generator is similar to the MLFG implemented in the SPRNG library. It has a period of approximately . It supports up to parallel streams through parameterization and substreams, each of length . The generator uses one 64-bit integer to create each U(0,1) value.
mrg32k3aThe 32-bit combined multiple recursive generator, as described in [3], is similar to the CMRG implemented in the
RngStreamspackage in C. It has a period of and supports up to parallel streams through sequence splitting, each of length . The generator uses two 32-bit integers to create each U(0,1) value.mt19937arThe Mersenne Twister, as described in [12], has a period of . The generator uses two 32-bit integers to create each U(0,1) value. This generator does not support multiple streams or substreams.
This generator is identical to the one used by the
randfunction beginning in MATLAB Version 7, activated usingrand('twister',s). Therngfunction uses this generator as the factory default.pcg64dxsm(since R2026b)The 64-bit permuted congruential generator with double xor-shift multiply is a member of the permuted congruential generator (PCG) family as described in [15]. This generator combines a simple 128-bit linear congruential generator (LCG) state transition with an output permutation to produce 64-bit pseudorandom values. The generator advances a 128-bit internal state using a full-period LCG (mod 2128) and then transforms the state into the output by applying two stages of xor-shift mixing interleaved with a 64-bit multiplier. The generator has a period of 2255. It supports up to 263 parallel streams and 264 substreams, each of length 2128.
philox4x32_10The Philox 4x32 generator with 10 rounds, as described in [17], uses a Feistel network and integer multiplication. The generator is designed for high performance in highly parallel systems, such as GPUs. It has a period of 2193 and supports up to 264 streams, each of length 2129.
shr3congMarsaglia's SHR3 shift-register generator summed with a linear congruential generator has a multiplier , addend , and modulus . SHR3, as described in [8], is a 3-shift-register generator defined as , where is the identity operator, is the left-shift operator, and R is the right-shift operator. The combined generator has a period of approximately . The generator uses one 32-bit integer to create each U(0,1) value. This generator does not support multiple streams or substreams.
This generator is provided for compatibility reasons and is identical to the one used by the
randnfunction beginning in MATLAB Version 5, activated usingrandn('state',s). MATLAB uses the year 2000 version of the generator, as discussed in [8].swb2712The modified subtract-with-borrow generator, as described in [9], is similar to an additive lagged Fibonacci generator with lags 27 and 12, but it is modified to have a much longer period of approximately . The generator works natively in double precision to create U(0,1) values, and all values in the open interval (0,1) are possible.
This generator is provided for compatibility reasons and is identical to the one used by the
randfunction beginning in MATLAB Version 5, activated usingrand('state',s).threefry4x64_20The Threefry 4x64 generator with 20 rounds, as described in [17], is a non-cryptographic adaptation of the Threefish block cipher from the Skein hash function. It has a period of 2514 and supports up to 2256 streams, each of length 2258.
xoshiro256pp(since R2026b)The xor-shift-rotate generator with 256-bit state and double addition is a member of the xor-shift-rotate generator family, as described in [1]. This generator combines a linear engine with a nonlinear "++" scrambler. It maintains a 256-bit internal state (four 64-bit words), which is updated each step using a sequence of shifts, rotations, and XOR combinations. The "++" transformation generates the output by summing two state words, rotating the result, and then adding that result to one of the original words. This generator has a period of 2256. It supports up to 264 independent streams and 264 substreams, each of length 2128.
Measure Performance of Random Number Generators
Often, the choice of random number generator for a simulation depends on its performance when generating arrays of a given size. Performance can depend on many factors, such as your computer platform, hardware configuration, and the size of the generated array.
To measure and compare the performance of different generators on your system when
producing uniformly distributed random numbers, you can use the
compareRand helper function. This function measures the
number of samples generated per second for each generator using
rand. Higher values indicate faster sampling.
function compareRand(sampleSize) T = RandStream.list; times = nan(height(T),1); for k = 1:height(T) rng(T.Name(k)); times(k) = timeit(@() rand(sampleSize,1)); end bar(sampleSize./times) xticklabels(T.Name) ylabel("Samples/sec (higher is faster)") title("rand(" + sampleSize + ",1) Performance") end
Before R2026b: In the compareRand
function, replace the call to the RandStream.list function with
an explicit list of generators to test.
For example, running this helper function to generate one million random numbers
on a Windows® 11, AMD EPYC™ 74F3 24-Core Processor @ 3.19 GHz test system shows that the fastest
generator is xoshiro (since R2026b). These
results might differ when you run compareRand on another platform
with a different hardware configuration.
Choose a Normal Transformation Algorithm
When creating a random number stream with RandStream, you can
specify a normal transformation algorithm. To do so, specify the
NormalTransform name-value argument as:
"Ziggurat", "Polar", or
"Inversion". These algorithms transform values from a uniform
random number generator into normally distributed values, enabling the generation of
normally distributed random numbers using randn. See [18] for details
on the algorithms.
Technical Descriptions of Normal Transformation Algorithms
InversionThe inversion algorithm computes a normal random variate by applying the inverse of the standard normal cumulative distribution function (CDF) to a uniform random variate. The inversion algorithm consumes exactly one uniform value per normal value.
Although this algorithm requires expensive mathematical operations to evaluate the inverse CDF, the algorithm is thread-safe and GPU compatible. It is the only normal transformation algorithm supported on both the CPU and GPU, which is useful when you want to generate identical random number sequences on the CPU and GPU. As a result, this algorithm can be efficient when sampling large arrays using generators that support multithreading or when GPU acceleration is available.
The
RandStreamobject creates a random number stream that you can use to generate random, in-memory MATLAB arrays. To create a random number stream that you can use to generate GPU arrays, useparallel.gpu.RandStream(Parallel Computing Toolbox).PolarThe polar rejection algorithm, as described in [2], generates normally distributed random values in pairs. On average, it uses approximately 2.54 uniform values per two normal values, or 1.27 uniform values per one normal value.
This algorithm is not thread-safe because the number of uniform values required to produce one normal value can fluctuate and is not predictable. It can also introduce alignment issues when switching between uniform and normal sampling, potentially producing different sequences when interleaving calls to
randandrandn. This algorithm is provided for compatibility reasons as the default normal transform used by themcg16807generator, which is the generator used in MATLAB Version 4 byrand('seed',s)andrandn('seed',s).ZigguratThe ziggurat algorithm, as described in [8], consumes approximately 2.02 uniform values per one normal value. It is optimized for fast generation of large batches of random numbers in single-threaded environments. It avoids expensive mathematical operations and has minimal overhead for batch generation.
This algorithm does not support multithreading and is not GPU compatible. Therefore, it is most suited for generators that also do not support multithreading or when GPU acceleration is not required.
Measure Performance of Normal Transformation Algorithms
When you generate random number using randn, performance
can depend not only on the underlying pseudorandom number generator, but also on
the normal transformation algorithm used to produce normally distributed
values.
By default, the normal transformation algorithm depends on the specified generator algorithm:
"Ziggurat"is the default fordsfmt19937,mlfg6331_64,mrg32k3a,mt19937ar,shr3cong, andswb2712."Polar"is the default formcg16807."Inversion"is the default forpcg64dxsm,philox4x32_10,threefry4x64_20, andxoshiro256pp.
However, you can change the normal transformation algorithm used by a
generator algorithm by setting the NormalTransform property
of a RandStream object. The relative performance of these
algorithms can vary depending on the generator, your computer platform and
hardware configuration, and the size of the generated array. In almost all
cases, "Ziggurat" is the fastest transformation algorithm for
generators that do not support multithreading, while
"Inversion" is the fastest transformation algorithm for
generators that support multithreading.
To measure and compare the performance of normal transformation algorithms
across generators on your system, you can use the
compareRandn helper function. This function measures the
number of samples generated per second for each combination of transformation
algorithm and generator using randn. Higher values indicate
faster sampling.
function compareRandn(sampleSize) T = RandStream.list; normalAlgo = ["Ziggurat", "Polar", "Inversion"]; times = nan(height(T),length(normalAlgo)); for k1 = 1:height(T) for k2 = 1:length(normalAlgo) s = RandStream(T.Name(k1),NormalTransform=normalAlgo(k2)); times(k1,k2) = timeit(@() randn(s,sampleSize,1)); end end bar(sampleSize./times) legend(normalAlgo,Location="northeastoutside") xticklabels(T.Name) ylabel("Samples/sec (higher is faster)") title("randn(" + sampleSize + ",1) Performance") end
Before R2026b: In the compareRandn
function, replace the call to the RandStream.list function
with an explicit list of generators to test.
For example, running this helper function to generate one million random
numbers on a Windows 11, AMD EPYC 74F3 24-Core Processor @ 3.19 GHz test system shows that the fastest
normal transformation algorithm is "Inversion" when used with
the xoshiro (since R2026b) generator,
followed by "Inversion" when used with the
threefry generator. These results might differ when you
run compareRandn on another platform with a different
hardware configuration.
Configure Random Number Stream
A random number stream s has properties that control its
behavior. When you create a stream s, you can set its properties
using name-value arguments. After creating s, you can access or
change its property by using the syntaxes p = s.Property and
s.Property = p.
For example, you can specify the normal transformation algorithm that generates
normally distributed random values when you use randn. Generate
five normally distributed random values using the Inversion
transformation algorithm with the Mersenne Twister generator.
s1 = RandStream("twister",NormalTransform="Inversion"); s1.NormalTransform
ans =
'Inversion'r1 = randn(s1,1,5)
r1 = 1×5
0.8954 1.3153 -1.1408 1.3618 0.3381Configure the stream to use the Polar transformation algorithm,
and then generate five more normally distributed random values.
s1.NormalTransform = "Polar"s1 =
mt19937ar random stream
Seed: 0
NormalTransform: Polarr2 = randn(s1,1,5)
r2 = 1×5
-0.5100 -0.2807 0.0589 0.5752 -0.0694When generating random numbers with uniform distribution using
rand, you can also configure the stream to generate
antithetic pseudorandom values. For a uniformly distributed value
u, the corresponding antithetic value is 1 –
u.
For example, create six random numbers with uniform distribution using the Mersenne Twister generator.
s2 = RandStream("twister");
r1 = rand(s2,1,6)r1 =
0.8147 0.9058 0.1270 0.9134 0.6324 0.0975Restore the initial state of the stream. Create another six random numbers with
the Antithetic property set to true. Check that these six random
numbers are equal to the previously generated random numbers subtracted from
1.
reset(s2) s2.Antithetic = true; r2 = rand(s2,1,6)
r2 =
0.1853 0.0942 0.8730 0.0866 0.3676 0.9025tf = isequal(r1,1 - r2)
tf = logical 1
Instead of setting the properties of a stream one by one, you can save and restore
all properties of a stream s by using A =
get(s) and set(s,A), respectively. Using the
get and set functions, you can save and
restore the entire configuration of a stream so that you can reproduce the sequence
of generated random numbers from that stream.
For example, configure stream s2 to have the same properties as
stream s1.
A = get(s1)
A =
Type: 'mt19937ar'
NumStreams: 1
StreamIndex: 1
Substream: 1
Seed: 0
State: [625x1 uint32]
NormalTransform: 'Polar'
Antithetic: 0
FullPrecision: 1set(s2,A) get(s2)
Type: 'mt19937ar'
NumStreams: 1
StreamIndex: 1
Substream: 1
Seed: 0
State: [625x1 uint32]
NormalTransform: 'Polar'
Antithetic: 0
FullPrecision: 1Create and Manage Substreams
You can use substreams of a single random number stream to get statistically independent sequences of random numbers. Substreams are separated by a known spacing in the generator's sequence, which eliminates any chance of overlap between different substreams. In contrast, seeds initialize the stream at different starting points, but the spacing between those points is not exactly known, so different streams with different seeds can overlap. Substreams are a more controlled and lightweight alternative to using different seeds or multiple parallel streams.
To use the Substream property of a
RandStream object, create a stream using a generator that
supports substreams. For a list of generator algorithms that support substreams and
their properties, see the table in the previous section. For example, generate
random numbers in a loop using substreams with the multiplicative lagged Fibonacci
generator.
myStream = RandStream("multFibonacci"); for i = 1:5 myStream.Substream = i; r = rand(myStream,1,i) end
r =
0.6986
r = 1×2
0.9230 0.2489
r = 1×3
0.0261 0.2530 0.0737
r = 1×4
0.3220 0.7405 0.1983 0.1052
r = 1×5
0.2067 0.2417 0.9777 0.5970 0.4187In another loop, you can generate random values that are independent from the first set of five iterations.
for i = 6:10 myStream.Substream = i; r = rand(myStream,1,11-i) end
r = 1×5
0.2650 0.8229 0.2479 0.0247 0.4581
r = 1×4
0.3963 0.7445 0.7734 0.9113
r = 1×3
0.2758 0.3662 0.7979
r = 1×2
0.6814 0.5150
r =
0.5247Substreams are useful in serial computations because they generate distinct, reproducible sequences of random numbers for different iterations or stages of a computation. Substreams can re-create all or part of a simulation by returning to a particular checkpoint in the stream. For example, you can return to the sixth substream in the loop. The result contains the same values as the sixth output above.
myStream.Substream = 6; r = rand(1,5)
r = 1×5
0.2650 0.8229 0.2479 0.0247 0.4581Restore State of Random Number Generator to Reproduce Output
The State property of a RandStream object
represents the internal state of the random number generator. By saving and
restoring the state of a random number stream, you can reproduce the same sequence
of random numbers from a specific point in the stream during your
computations.
For example, use the RandStream.getGlobalStream function to
return a handle to the global stream, that is, the current global stream that
rand uses to generate random numbers. Save the state of the
global stream.
globalStream = RandStream.getGlobalStream; myState = globalStream.State;
Using myState, you can restore the state of
globalStream and reproduce previous
results.
A = rand(1,100); globalStream.State = myState; B = rand(1,100); tf = isequal(A,B)
tf = logical 1
The rand, randi, randn,
and randperm functions draw numbers from the global stream.
Because these functions access the same underlying stream, a call to one affects the
values produced by the others in subsequent calls.
globalStream.State = myState; A = rand(1,100); globalStream.State = myState; C = randi(100); B = rand(1,100); tf = isequal(A,B)
tf = logical 0
You can also reset a stream to its initial settings using the reset
function.
reset(globalStream) A = rand(1,100); reset(globalStream) B = rand(1,100); tf = isequal(A,B)
tf = logical 1
References
[1] Blackman, D. and S. Vigna.
“Scrambled Linear Pseudorandom Number Generators”. ACM
Transactions on Mathematical Software 47(4), no. 36 (September
2021): 1-32. https://doi.org/10.1145/3460772.
[2] Devroye, L. Non-Uniform Random Variate
Generation, Springer New York, 1986. https://doi.org/10.1007/978-1-4613-8643-8.
[3] L’Ecuyer, P. “Good Parameters and Implementations for Combined Multiple Recursive Random Number Generators”, Operations Research, 47(1): 159–164. 1999.
[4] L'Ecuyer, P. and S. Côté. “Implementing A Random Number Package with Splitting Facilities”, ACM Transactions on Mathematical Software, 17: 98–111. 1991.
[5] L'Ecuyer, P. and R. Simard. “TestU01: A C Library for Empirical Testing of Random Number Generators,” ACM Transactions on Mathematical Software, 33(4): Article 22. 2007.
[6] L'Ecuyer, P., R. Simard, E. J. Chen, and W. D. Kelton. “An Objected-Oriented Random-Number Package with Many Long Streams and Substreams.” Operations Research, 50(6): 1073–1075. 2002.
[7] Marsaglia, G. “Random numbers for C: The
END?” Usenet posting to sci.stat.math. 1999. Available online at https://groups.google.com/group/sci.crypt/browse_thread/.
thread/ca8682a4658a124d/
[8] Marsaglia G., and W. W. Tsang. “The ziggurat method
for generating random variables.” Journal of Statistical
Software, 5:1–7. 2000. Available online at https://www.jstatsoft.org/article/view/v005i08.
[9] Marsaglia, G., and A. Zaman. “A new class of random number generators.” Annals of Applied Probability 1(3):462–480. 1991.
[10] Marsaglia, G., and W. W. Tsang. “A fast, easily implemented method for sampling from decreasing or symmetric unimodal density functions.” SIAM J. Sci. Stat. Comput. 5(2):349–359. 1984.
[11] Mascagni, M., and A. Srinivasan. “Parameterizing Parallel Multiplicative Lagged-Fibonacci Generators.” Parallel Computing, 30: 899–916. 2004.
[12] Matsumoto, M., and T. Nishimura.“Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudorandom Number Generator.” ACM Transactions on Modeling and Computer Simulation, 8(1): 3–30. 1998.
[13] Matsumoto, M., and M. Saito.“A PRNG Specialized in Double Precision Floating Point Numbers Using an Affine Transition.” Monte Carlo and Quasi-Monte Carlo Methods 2008, 10.1007/978-3-642-04107-5_38. 2009.
[14] Moler, C. B. Numerical Computing with
MATLAB. SIAM, 2004. Available online at https://www.mathworks.com/moler
[15] O'Neill, M. E.
”PCG: A Family of Simple Fast Space-Efficient Statistically Good Algorithms
for Random Number Generation”. HMC-CS-2014-0905 (September 2014). https://www.cs.hmc.edu/tr/hmc-cs-2014-0905.pdf
[16] Park, S.K., and K.W. Miller. “Random Number Generators: Good Ones Are Hard to Find.” Communications of the ACM, 31(10):1192–1201. 1998.
[17] Salmon, J. K., M. A. Moraes, R. O. Dror, and D. E. Shaw. "Parallel Random Numbers: As Easy As 1, 2, 3." In Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis (SC11). New York, NY: ACM, 2011.
[18] Thomas, D. B., P. H. W. Leong, and J. D. Villasenor. “Gaussian Random Number Generators.” ACM Computing Surveys, 39(4): 11-es. 2007.