3.2 随机数据

原文链接: https://rust-random.github.io/book/guide-data.html

1
2
3
4
5
6
7
# use rand::Rng;
# fn main() {
// 获取一些随机数据:
let mut data = [0u8; 8];
rand::rng().fill_bytes(&mut data);
println!("{:?}", data)
# }

什么是随机性?

随机是什么意思?日常用语中,这个词可以仅表示出乎意料或未知,但我们需要更精确一些。维基百科给出了更具体的定义:

随机性是指事件缺乏规律或可预测性。

我们可以进一步理解:缺乏规律意味着没有偏倚;换句话说,所有可能的值出现的可能性相等。

要理解什么是随机值,我们仍需要一个上下文:随机值可以从哪些数字集合中抽取?

  • 举个简单例子,考虑骰子:它有 1、2、3、4、5、6 六个值,无偏(公平)的骰子会使每个数字出现概率相等,均为 ⅙。
  • 再看一个极端例子:自然数(1、2、3 等)。这些数没有上限。因此,若要求一个无偏的随机自然数,则 1、5、1000、100 万、1 万亿——出现概率都相同。事实上,对任意自然数 k,数字 1, 2, ..., k 在所有自然数中只占无穷小的一部分,这意味着从该范围内抽取无偏数字的概率实际上是 1/∞ = 0。换言之:对任意自然数,我们期望无偏随机值更大。这是不可能的,因此不存在无偏随机自然数这种东西。
  • 另一个例子:0 到 1 之间的实数。实数包括所有分数、像 π 和 √2 这样的无理数,以及它们的倍数……即使在 (0, 1) 这样的小范围内也有无穷多种可能,因此仅说「所有可能等概率」是不够的。我们换一种方式理解缺乏规律:等长的每个区间出现概率相等;例如可将区间 0,1 划分为 0,½ 和 ½,1,掷硬币决定随机样本来自哪个区间。若选中 ½,1,可再掷硬币在 ½,¾ 和 ¾,1 之间选择,将随机值限制在大小为 ¼ 的区间内。可重复此过程任意次,以所需精度在 0 和 1 之间选取随机值——尽管应意识到我们并非选择精确值,而只是选择一个小区间。

上面定义(或未能定义)的是均匀随机数分布,简称均匀分布。还有非均匀分布,后文会介绍。这里还值得注意:均匀分布并不意味着样本会均匀分布(试试掷六颗骰子:你很可能不会得到 1、2、3、4、5、6)。

回到计算领域,我们现在可以在多种上下文中定义均匀分布的随机值(无偏随机值):

  • u32:0 到 u32::MAX 之间的随机数,每个值等概率
  • BigInt:由于该类型没有上界,无法产生无偏随机值(它会无穷大,并占用无穷内存)
  • f64:我们将其视为实数的近似,并按惯例限制在 0 到 1 的范围(除非另有说明)。后文会回到所用转换;目前请注意这些转换产生 52–53 位精度(取决于所用转换,输出步长为 ε 或 ε/2,其中 1+ε 是大于 1 的最小可表示值)。

随机数据

如上所述,「随机数」一词若无上下文则毫无意义。「随机数据」通常指随机字节序列,其中每个字节的 256 种可能值等概率出现。

RngCore::fill_bytes 正是产生这种数据:随机字节序列。

若将长度正确的无偏随机字节序列解释为整数——例如 u32 或 u64——结果是无偏整数。由于这种转换很简单,RngCore::next_u32 和 RngCore::next_u64 也属于同一 trait。(事实上转换往往相反——算法生成器通常在内部使用整数,再转换为所需的随机数据形式。)

最后修改 August 23, 2026: 更新 (499855b16)