Generating Random Numbers
Most scientific computing software nowadays has built-in random number generators. For common types of random variables, e.g., Gaussian or exponential, these random number generators can easily generate numbers according to the chosen distribution. However, if we are given an arbitrary PDF (or PMF) that is not among the list of predefined distributions, how can we generate random numbers according to the PDF or PMF we want?
4.8.1General principle
Generating random numbers according to the desired distribution can be formulated as an inverse problem. Suppose that we can generate uniformly random numbers according to Uniform(0,1). This is a fair assumption, and this process can be done on almost all computers today. Let us call this random variable \(U\) and its realization \(u\). Suppose that we also have a desired distribution \(f_X(x)\) (and its CDF \(F_X(x)\)). We can put the two random variables \(U\) and \(X\) on the two axes of Figure 4.36, yielding an input-output relationship. The inverse problem is: By using what transformation \(g\), such that \(X = g(U)\), can we make sure that \(X\) is distributed according to \(f_X(x)\) (or \(F_X(x)\))?

The transformation \(g\) that can turn a uniform random variable into a random variable following a distribution \(F_X(x)\) is given by
That is, if \(g = F_X^{-1}\), then \(g(U)\) will be distributed according to \(f_X\) (or \(F_X\)).
Proof. First, we know that if \(U \sim \mathrm{Uniform}(0,1)\), then \(f_U(u) = 1\) for \(0 \le u \le 1\), so
for \(0 \le u \le 1\). Let \(g = F^{-1}_X\) and define \(Y = g(U)\). Then the CDF of \(Y\) is
Therefore, we have shown that the CDF of \(Y\) is the CDF of \(X\).
■The theorem above states that if we want a distribution \(F_X\), then the transformation should be \(g = F_X^{-1}\). This suggests a two-step process for generating random numbers.
- sep0ex
- Step 1: Generate a random number \(U \sim \mathrm{Uniform}(0,1).\)
Step 2: Let
$$Y = F_X^{-1}(U).$$Then the distribution of \(Y\) is \(F_X\).
4.8.2Examples
How can we generate Gaussian random numbers with mean \(\mu\) and variance \(\sigma^2\) from uniform random numbers?
First, we generate \(U \sim \text{Uniform}(0,1)\). The CDF of the ideal distribution is
Therefore, the transformation \(g\) is
In Figure 4.37, we plot the CDF of \(F_X\) and the transformation \(g\).


To visualize the random variables before and after the transformation, we plot the histograms in Figure 4.38.


The MATLAB and Python codes used to generate the histograms above are shown below.
% MATLAB code to generate Gaussian from uniform
mu = 3;
sigma = 2;
U = rand(10000,1);
gU = sigma*icdf('norm',U,0,1)+mu;
figure; hist(U);
figure; hist(gU);# Python code to generate Gaussian from uniform
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
mu = 3
sigma = 2
U = stats.uniform.rvs(0,1,size=10000)
gU = sigma*stats.norm.ppf(U)+mu
plt.hist(U); plt.show()
plt.hist(gU); plt.show()How can we generate exponential random numbers with parameter \(\lambda\) from uniform random numbers?
First, we generate \(U \sim \text{Uniform}(0,1)\). The CDF of the ideal distribution is
Therefore, the transformation \(g\) is
The CDF of the exponential random variable and the transformation \(g\) are shown in Figure 4.39.


The PDF of the uniform random variable \(U\) and the PDF of the transformed variable \(g(U)\) are shown in Figure 4.40.


The MATLAB and Python codes for this transformation are shown below.
% MATLAB code to generate exponential random variables
lambda = 1;
U = rand(10000,1);
gU = -(1/lambda)*log(1-U);# Python code to generate exponential random variables
import numpy as np
import scipy.stats as stats
lambd = 1;
U = stats.uniform.rvs(0,1,size=10000)
gU = -(1/lambd)*np.log(1-U)How can we generate the 4 integers \(1,2,3,4\), according to the histogram \([0.1\; 0.5\; 0.3\; 0.1]\), from uniform random numbers?
First, we generate \(U \sim \text{Uniform}(0,1)\). The CDF of the ideal distribution is
This CDF is not invertible. However, we can still define the “inverse” mapping as
For example, if \(0.1 < U \le 0.6\), then on the black curve shown in Figure 4.41(a), we are looking at the second vertical line from the left. This will go to “2” on the \(x\)-axis. Therefore, the inversely mapped value is 2 for \(0.1 < U \le 0.6\).


The PDFs of the transformed variables, before and after, are shown in Figure 4.42.


In MATLAB, the above PDFs can be plotted using the commands below. In Python, we need to use the logical comparison np.logical_and to identify the indices. An alternative is to use gU[((U<=0.5)*(U>=0.0)).astype(np.bool)]=1.
% MATLAB code to generate the desired random variables
U = rand(10000,1);
gU = zeros(10000,1);
gU((U>=0) & (U<=0.1)) = 1;
gU((U>0.1) & (U<=0.6)) = 2;
gU((U>0.6) & (U<=0.9)) = 3;
gU((U>0.9) & (U<=1)) = 4;# Python code to generate the desired random variables
import numpy as np
import scipy.stats as stats
U = stats.uniform.rvs(0,1,size=10000)
gU = np.zeros(10000)
gU[np.logical_and(U >= 0.0, U <= 0.1)] = 1
gU[np.logical_and(U > 0.1, U <= 0.6)] = 2
gU[np.logical_and(U > 0.6, U <= 0.9)] = 3
gU[np.logical_and(U > 0.9, U <= 1)] = 4