Main Content

Create and Control Random Number Streams

R2026b

Creating 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.7255

The 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.

AlgorithmNameMultiple Stream and Substream SupportMultithreading SupportDescriptionApproximate Period in Full Precision

"dsfmt19937"

"simdTwister"NoNoSIMD-oriented fast Mersenne Twister219937 – 1

"mcg16807"

"v4"NoNoMultiplicative congruential generator231 – 2

"mlfg6331_64"

"multFibonacci"YesYesMultiplicative lagged Fibonacci generator2124 (251 streams of length 272)

"mrg32k3a"

"combRecursive"YesYesCombined multiple recursive generator2191 (263 streams of length 2127)

"mt19937ar"

"twister"NoNoMersenne Twister219937 – 1

"pcg64dxsm" (since R2026b)

"pcg"YesYes64-bit permuted congruential generator with double xor-shift multiply2255 (263 streams of length 2192)

"philox4x32_10"

"philox"YesYesPhilox 4x32 generator with 10 rounds2193 (264 streams of length 2129)

"shr3cong"

"v5normal"NoNoSHR3 shift-register generator summed with linear congruential generator264

"swb2712"

"v5uniform"NoNoModified subtract-with-borrow generator21492

"threefry4x64_20"

"threefry"YesYesThreefry 4x64 generator with 20 rounds2514 (2256 streams of length 2258)

"xoshiro256pp" (since R2026b)

"xoshiro"YesYesXor-shift-rotate generator with 256-bit state and double addition2256 (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

dsfmt19937

The 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 2199371, and the possible values are multiples of 252 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 a=75, modulo m=2311. This generator has a period of 2312. 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 rand and randn functions beginning in MATLAB Version 4, activated using rand('seed',s) or randn('seed',s).

mlfg6331_64

The 64-bit multiplicative lagged Fibonacci generator, as described in [11], has lags l=63, k=31. This generator is similar to the MLFG implemented in the SPRNG library. It has a period of approximately 2124. It supports up to 261 parallel streams through parameterization and 251 substreams, each of length 272. The generator uses one 64-bit integer to create each U(0,1) value.

mrg32k3a

The 32-bit combined multiple recursive generator, as described in [3], is similar to the CMRG implemented in the RngStreams package in C. It has a period of 2191 and supports up to 263 parallel streams through sequence splitting, each of length 2127. The generator uses two 32-bit integers to create each U(0,1) value.

mt19937ar

The Mersenne Twister, as described in [12], has a period of 2199371. 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 rand function beginning in MATLAB Version 7, activated using rand('twister',s). The rng function 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_10

The 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.

shr3cong

Marsaglia's SHR3 shift-register generator summed with a linear congruential generator has a multiplier a=69069, addend b=1234567, and modulus 232. SHR3, as described in [8], is a 3-shift-register generator defined as u=u(I+L13)(I+R17)(I+L5), where I is the identity operator, L is the left-shift operator, and R is the right-shift operator. The combined generator has a period of approximately 264. 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 randn function beginning in MATLAB Version 5, activated using randn('state',s). MATLAB uses the year 2000 version of the generator, as discussed in [8].

swb2712

The 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 21492. 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 rand function beginning in MATLAB Version 5, activated using rand('state',s).

threefry4x64_20

The 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

Inversion

The 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 RandStream object 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, use parallel.gpu.RandStream (Parallel Computing Toolbox).

Polar

The 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 rand and randn. This algorithm is provided for compatibility reasons as the default normal transform used by the mcg16807 generator, which is the generator used in MATLAB Version 4 by rand('seed',s) and randn('seed',s).

Ziggurat

The 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 for dsfmt19937, mlfg6331_64, mrg32k3a, mt19937ar, shr3cong, and swb2712.

  • "Polar" is the default for mcg16807.

  • "Inversion" is the default for pcg64dxsm, philox4x32_10, threefry4x64_20, and xoshiro256pp.

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.3381

Configure 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: Polar
r2 = randn(s1,1,5)
r2 = 1×5
     -0.5100     -0.2807     0.0589     0.5752     -0.0694

When 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.0975

Restore 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.9025
tf = 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: 1
set(s2,A)
get(s2)
               Type: 'mt19937ar'
         NumStreams: 1
        StreamIndex: 1
          Substream: 1
               Seed: 0
              State: [625x1 uint32]
    NormalTransform: 'Polar'
         Antithetic: 0
      FullPrecision: 1

Create 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.4187

In 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.5247

Substreams 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.4581

Restore 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.

See Also

|

Topics