Random Number Generation#
GAUSS provides a powerful suite of random number generation (RNG) functionality for simulation, Monte Carlo studies, and statistical sampling. Key features include:
Multiple modern pseudo-random generators (Mersenne Twister, MRG32k3a, and more)
Quasi-random sequences (Sobol, Niederreiter) for numerical integration
Over 20 distribution-specific sampling functions
Thread-safe state-based generation for parallel computing
Reproducible sequences via seeding
Before diving in, here are a few terms used throughout this page:
Seed — an integer that initializes a generator. The same seed always produces the same sequence of random numbers.
State — a data vector that captures a generator’s type and current position in its sequence. Passing a state to a function continues the sequence where the previous call left off.
Stream — an independent sequence within a multi-stream generator (e.g., MT2203 has 6024 streams).
Period — the length of the full cycle before a generator repeats.
Note
If you are coming from R, rndn is equivalent to rnorm and
rndu is equivalent to runif. The rndseed statement is
analogous to set.seed(). If you are coming from Python/NumPy,
rndn corresponds to numpy.random.randn and rndu to
numpy.random.rand.
Basic Random Number Functions#
GAUSS provides two fundamental functions for generating random numbers:
// 3x2 matrix of standard normal random numbers
x = rndn(3, 2);
// 3x2 matrix of uniform random numbers on [0, 1)
u = rndu(3, 2);
For random integers in a range, use rndi():
// 3x1 vector of random integers between 1 and 100
ri = rndi(3, 1, 1|100);
These functions use a shared global state. For reproducible results, set the seed before generating:
rndseed 42;
x = rndn(3, 2);
Running the above code will always produce the same output:
0.55850061 2.0347955
0.24048153 -0.97476365
-0.85727785 -0.98405229
Note
rndseed is a language statement, not a function — write
rndseed 42;, not rndseed(42);. It sets the global seed
for rndn, rndu, rndi, and all distribution-specific
functions that do not take an explicit state. Setting the seed
again resets the sequence to the same starting point.
Sampling from Distributions#
GAUSS includes functions for sampling from many common distributions:
Function |
Distribution |
|---|---|
Standard normal (mean 0, variance 1) |
|
Uniform on [0, 1) |
|
Random integers in a range |
|
Bernoulli (binary outcomes) |
|
Beta |
|
Binomial |
|
Cauchy |
|
Chi-square |
|
Exponential |
|
Gamma |
|
Geometric |
|
Gumbel (extreme value type I) |
|
Hypergeometric |
|
Laplace (double exponential) |
|
Log-normal |
|
Multivariate normal |
|
Multivariate Student’s t |
|
Negative binomial |
|
Poisson |
|
Rayleigh |
|
Weibull |
|
Wishart |
|
Inverse Wishart |
Example: Distribution sampling#
rndseed 42;
// 1000 Gamma(shape=2, scale=1) draws
g = rndGamma(1000, 1, 2, 1);
// 1000 Poisson(lambda=5) draws
p = rndPoisson(1000, 1, 5);
// Multivariate normal with correlation
// { 0, 0 } is a 2x1 column vector; { 1 0.5, 0.5 1 } is a 2x2 matrix
// (commas separate rows, spaces separate columns)
mu = { 0, 0 };
sigma = { 1 0.5, 0.5 1 };
mv = rndMVn(500, mu, sigma);
Available Generators#
GAUSS includes several pseudo-random and quasi-random number
generators. You select a generator by creating a state with
rndCreateState():
Generator |
Streams |
Period |
BigCrush |
Notes |
|---|---|---|---|---|
SFMT19937 |
1 |
219937 |
— |
Default for |
MRG32k3a |
1 |
2191 |
0 failures |
Supports block-skipping via |
MT19937 |
1 |
219937 |
2 failures |
Classic Mersenne Twister |
MT2203 |
6024 |
22203 |
4 failures |
Multiple independent streams for parallel work |
Wichmann-Hill |
273 |
242.7 |
22 failures |
Multiple independent streams. Supports block-skipping |
Sobol |
— |
— |
— |
Quasi-random (low discrepancy). Dimensions 1–40.
The seed argument to |
Niederreiter |
— |
— |
— |
Quasi-random (low discrepancy). Dimensions 1–318. The seed argument sets the dimension |
The BigCrush column shows the number of failures on the TestU01 BigCrush test suite (160 tests). All generators pass DIEHARD. SFMT19937 was not tested because its output is not compatible with the scalar-at-a-time interface required by TestU01.
Choosing a generator#
For most work, the default generator (SFMT19937 for rndn/rndu)
is an excellent choice. Consider switching when:
You need parallel streams — use MT2203 (6024 streams) or Wichmann-Hill (273 streams)
You need block-skipping — use MRG32k3a or Wichmann-Hill (the generators that support
rndStateSkip())You need top statistical quality — use MRG32k3a (zero BigCrush failures)
You need quasi-random sequences — use Sobol or Niederreiter for numerical integration (these are deterministic, not pseudo-random)
Tip
For simulation studies that do not require parallel generation,
the simplest approach is rndseed plus rndn/rndu. You
only need explicit state management when working with threads or
when you need multiple independent sequences.
State-Based Generation#
For full control over the random number sequence, GAUSS supports state-based generation. A state encapsulates the generator type, stream index, and current position in the sequence.
Creating a state#
Use rndCreateState() to create a state for any generator:
// MRG32k3a with seed 192938
state = rndCreateState("mrg32k3a", 192938);
// Generate 3 standard normal values using this state.
// The { x, state } syntax is a multi-return assignment:
// x gets the random numbers
// state gets the updated generator state
{ x, state } = rndn(3, 1, state);
print x;
This prints:
0.20471263
0.14053340
-1.4368991
Always pass the updated state to the next call to continue the sequence where it left off — do not reuse the original seed or state.
Selecting a stream#
For generators with multiple streams (MT2203, Wichmann-Hill), append a hyphen and stream number to the generator name:
seed = 192938;
// Wichmann-Hill stream 3
whState3 = rndCreateState("wh-3", seed);
// MT2203 stream 21
mtState21 = rndCreateState("mt2203-21", seed);
Each stream is an independent pseudo-random sequence with the same statistical properties. Two different streams seeded identically will produce completely different sequences.
Note
The KISS-Monster generator and its dedicated functions
(rndKMn, rndKMu, rndKMi) are deprecated. Use
rndCreateState() with any supported generator instead.
Thread Safety#
When using threads (threadBegin / threadEnd), the global-state
functions (rndn, rndu, rndGamma, etc.) share a single state
and must not be called concurrently:
// WRONG — concurrent writes to global state
threadBegin;
x = rndn(500, 1);
threadEnd;
threadBegin;
x2 = rndn(500, 1);
threadEnd;
threadJoin;
There are two safe alternatives:
Option 1: Generate before threads
x = rndn(500, 1);
x2 = rndn(500, 1);
threadBegin;
y = myFunction(x);
threadEnd;
threadBegin;
y2 = myFunction(x2);
threadEnd;
threadJoin;
Option 2: Use explicit states
Each thread gets its own state, so there is no shared global state to corrupt. This example uses MRG32k3a, but any generator works:
state1 = rndCreateState("mrg32k3a", 723193);
state2 = rndCreateState("mrg32k3a", 94493);
threadBegin;
{ x1, state1 } = rndn(500, 1, state1);
y1 = myFunction(x1);
threadEnd;
threadBegin;
{ x2, state2 } = rndn(500, 1, state2);
y2 = myFunction(x2);
threadEnd;
threadJoin;
Parallel Generation with Block-Skipping#
When you need a single contiguous pseudo-random sequence split across
multiple threads, use block-skipping. The rndStateSkip()
function advances a state by a specified number of values without
generating them:
// Create initial state
seed = 2342343;
state1 = rndCreateState("mrg32k3a", seed);
// Create 3 additional states, each starting 1e8 values forward
state2 = rndStateSkip(1e8, state1);
state3 = rndStateSkip(1e8, state2);
state4 = rndStateSkip(1e8, state3);
// Process each block in a separate thread
threadBegin;
{ x1, state1 } = rndGamma(1e8, 1, 2, 2, state1);
y1 = myfunc(x1);
threadEnd;
threadBegin;
{ x2, state2 } = rndGamma(1e8, 1, 2, 2, state2);
y2 = myfunc(x2);
threadEnd;
threadBegin;
{ x3, state3 } = rndGamma(1e8, 1, 2, 2, state3);
y3 = myfunc(x3);
threadEnd;
threadBegin;
{ x4, state4 } = rndGamma(1e8, 1, 2, 2, state4);
y4 = myfunc(x4);
threadEnd;
threadJoin;
The four threads together produce the same sequence as a single call generating 4 x 108 values — just processed in parallel.
Note
Block-skipping via rndStateSkip() is available with the
MRG32k3a and Wichmann-Hill generators. For other
generators, use multiple independent streams (MT2203) or
separate seeds instead.
Performance Tips#
Generate in bulk. Creating one million numbers in a single call is much faster than 100,000 calls of 10 numbers each. Avoid generating random numbers one at a time inside loops.
Use SFMT19937 for speed. The optimized Mersenne Twister is the fastest generator available. The default generator for
rndn/rnduis already very fast.Use multiple threads. For large-scale simulations, distribute work across threads using state-based generation (see above).
Watch memory. Generating a very large matrix in one call can exhaust available RAM. Balance batch size against available memory.
Quick Reference#
Task |
How |
|---|---|
Set seed for reproducibility |
|
Standard normal matrix |
|
Uniform matrix |
|
Random integers in [a, b] |
|
Gamma draws |
|
Multivariate normal |
|
Create generator state |
|
Generate with state |
|
Select a stream |
|
Skip ahead in sequence |
|
See also