一、Matlab随机数产生的核心机制
在科学计算与工程仿真中,Matlab随机数扮演着不可或缺的角色。然而,计算机本质上是确定性的逻辑机器,无法通过硬件电路真正产生“绝对随机”的数字。因此,Matlab(以及绝大多数编程语言)所生成的实际上是伪随机数(Pseudorandom Numbers)。这些数字虽然具有统计上的随机性,但它们是由一个确定性的数学算法生成的序列。
1.1 伪随机数生成器 (PRNG)
Matlab目前默认使用的随机数生成算法是 Mersenne Twister (MT19937)。这是一种广泛认可的算法,具有以下显著特点:
- ? 极长的周期:其周期为 219937 - 1,这是一个拥有6000多位数的巨大数字,远超任何实际模拟的需求。
- ? 均匀分布:在1到6的维度上表现出高度的均匀性,消除了传统线性同余生成器中的相关性缺陷。
- ⚙️ 状态依赖:生成器的状态(State)由一个初始种子(Seed)决定。相同的种子永远产生相同的序列,这是可复现性的基础。
种子 (Seed) 的重要性
种子是随机数生成的起点。如果不手动设置种子,Matlab会根据系统时钟或其他熵源自动初始化。这意味着每次启动Matlab或运行脚本时,默认生成的随机数序列是不同的。但在科研复现中,固定种子(如 rng(0))是必须的操作规范。
算法演进
早期版本的Matlab使用线性同余生成器(LCG),其随机性较差,存在明显的周期性模式。自R2008b版本起,Matlab将MT19937设为默认算法,极大地提升了模拟的可靠性,特别是在大规模蒙特卡洛模拟中。
二、核心随机函数详解
理解底层原理后,我们需要掌握Matlab中用于生成不同类型随机数的核心函数。这些函数虽然接口简单,但背后的数学变换却十分精妙。
1. 均匀分布:rand 函数
rand 函数生成服从 [0, 1] 区间上均匀分布的伪随机数。它是所有其他分布生成的基础。
% 生成一个 1x5 的向量
r = rand(1, 5)
% 生成一个 3x3 的矩阵
M = rand(3, 3)
% 注意:rand 生成的数包含 0 但不包含 1 (半开区间 [0, 1))
技术细节: MT19937 生成的是32位或64位的整数,然后将其除以最大可能值,映射到 [0,1) 区间。这保证了浮点数的精度和均匀性。
2. 正态分布:randn 函数
randn 生成服从标准正态分布(均值 μ=0,方差 σ²=1)的随机数。在金融建模、噪声模拟和统计检验中极为常用。
% 生成 1000 个标准正态分布随机数
data = randn(1000, 1);
% 生成均值为 5,标准差为 2 的正态分布
% 公式:X = mu + sigma Z, 其中 Z ~ N(0,1)
custom_normal = 5 + 2 randn(1000, 1);
Box-Muller 变换: 虽然底层仍依赖均匀分布生成器,但Matlab内部使用高效的算法(如Ziggurat算法或Box-Muller变换的变体)将均匀随机数转换为正态分布数,以确保计算速度和统计特性的平衡。
3. 整数分布:randi 函数
randi 用于生成指定范围内的均匀分布整数。这在离散事件模拟、游戏开发和随机抽样中非常有用。
% 生成 1 到 100 之间的随机整数
int_val = randi([1, 100]);
% 生成 3x3 的矩阵,元素范围为 -5 到 5
matrix_int = randi([-5, 5], 3, 3);
三、进阶应用与常见陷阱
在实际工程应用中,许多用户虽然会使用 rand,却往往忽略了随机数生成器状态管理的重要性,导致结果不可复现或存在隐蔽的相关性。
3.1 随机数生成器状态管理:rng 函数
rng 是控制随机数生成器行为的统一接口。它允许你设置种子、选择算法以及保存/恢复状态。
| 命令 | 功能描述 | 适用场景 |
|---|---|---|
rng default |
重置为默认设置(种子为0,算法为MT19937) | 脚本调试、结果复现 |
rng(seed) |
设置特定整数种子 | 固定随机序列 |
rng('shuffle') |
基于系统时间生成随机种子 | 每次运行都需要不同序列时 |
state = rng; |
保存当前状态到变量 | 暂停并恢复随机序列 |
3.2 网友们还关心:随机数的“独立性”陷阱
一个常见的误区是认为每次调用 rand 都是完全独立的。虽然从统计上讲它们是独立的,但在并行计算或多线程环境中,如果多个线程共享同一个随机数生成器状态而不加锁,可能会导致序列重叠或相关性增强。
步骤一:初始化环境
在大型模拟开始前,始终使用 rng('shuffle') 或记录具体的 rng(seed)。对于需要高并发随机数的场景,考虑使用 RandStream 类为每个线程创建独立的流。
步骤二:执行模拟
调用 rand 或 randn 进行蒙特卡洛积分、路径模拟或噪声添加。确保在循环内部不要反复重置种子,否则会产生完全相同的数字。
步骤三:验证与统计
使用直方图(histogram)或 Kolmogorov-Smirnov 检验(kstest)验证生成数据的分布是否符合预期。不要仅凭肉眼观察。
3.3 特殊分布的生成
除了均匀和正态分布,Matlab还支持通过 Random 函数(来自Statistics and Machine Learning Toolbox)生成指数分布、泊松分布等。其核心原理通常是通过逆变换采样法(Inverse Transform Sampling),即利用累积分布函数(CDF)的逆函数,将均匀分布的随机数映射为目标分布。
五、高频问题解答 (FAQ)
这是因为Matlab默认使用系统时间作为种子初始化随机数生成器。如果你希望每次运行得到相同的结果(例如为了复现论文中的数据),请在代码开头添加 rng(0) 或 rng('default')。
它们底层共享同一个随机数生成器状态。如果你先调用 rand,再调用 randn,它们的序列是连续的。但在统计独立性上,均匀分布和正态分布样本之间没有线性相关性。不过,为了严格隔离,建议在不同类型的模拟中分别管理状态。
如果安装了Statistics and Machine Learning Toolbox,可以使用 random('exponential', lambda, [1, 100])。如果没有工具箱,可以通过逆变换法手动实现:例如指数分布可以通过 -log(rand())/lambda 生成。
在并行池(parfor)中,每个worker需要独立的随机数流以避免冲突。推荐使用 RandStream.create 创建多个独立的流,并将它们分配给不同的worker,或者使用 parfor 内置的确定性索引来生成种子。