4. 随机性测试的统计语言

随机数发生器输出的比特流看起来“像不像随机”,不能靠肉眼判断,也不能靠“感觉均匀”下结论。NIST STS、Dieharder、TestU01 这些测试套件,本质上都在做同一件事:把一段比特流交给某个统计量,算出它在“理想随机”假设下出现的概率,再据此判断这段序列是否可疑。要读懂它们的输出,必须先掌握一套统计语言:假设检验、显著性水平、p 值、两类错误,以及多重比较问题。

一、假设检验:把“随机”变成一个可检验的命题

假设检验的核心思路是“反证”。我们先把待检验的命题设为原假设 H₀,在本课程中通常就是“该比特流来自理想随机源,比特独立且 0/1 等概率”。与之对立的备择假设 H₁ 是“该比特流不满足理想随机性”。

但“随机”本身无法被直接证明,只能通过某个统计量间接观察。于是我们构造一个检验统计量,例如频数检验中的 0/1 计数偏差、游程检验中的游程长度分布、块内频数检验中的块内 1 的比例。在 H₀ 成立时,这个统计量的分布是已知的——通常近似服从正态分布、χ² 分布或其它标准分布。把实际观测值代入,就能算出“在 H₀ 为真时,出现当前或更极端结果的概率”,这就是 p 值。

因此,一次随机性测试的完整逻辑链是:设定 H₀ → 选择统计量 → 推导 H₀ 下的分布 → 计算观测值 → 得到 p 值 → 与显著性水平比较 → 做出判断。NIST STS 的每一项测试,都是这条链的一个具体实例。

二、显著性水平 α 与 p 值:判断的标尺

显著性水平 α 是我们事先设定的“容忍犯错的阈值”,表示在 H₀ 为真时,我们愿意以多大概率错误地拒绝它。工程中常用 α = 0.01,NIST STS 默认也采用 0.01。α 越小,判断越保守,越不容易把合格序列误判为不合格,但也越容易漏掉真正有问题的序列。

p 值 是数据给出的证据强度。判断规则非常直接:

  • 若 p ≥ α,不拒绝 H₀,认为该测试未发现异常;
  • 若 p < α,拒绝 H₀,认为该测试发现异常,序列在该项上不合格。

需要特别强调:p 值不是“序列是随机的概率”,也不是“H₀ 为真的概率”。它只是“在 H₀ 为真时,观测到当前或更极端结果的概率”。p = 0.03 并不意味着“有 3% 的概率是随机的”,而是“如果序列真的随机,出现这种偏差的概率约为 3%”。这是初学者最容易误解的地方。

p 值接近 1 也不代表“更随机”。在理想情况下,p 值本身应服从 [0,1] 上的均匀分布。若大量测试的 p 值都集中在 0.9 以上,反而可能说明统计量选择或数据预处理存在问题。

三、第一类错误与第二类错误

任何基于阈值的判断都会犯错,错误分两类:

错误类型含义概率后果
第一类错误(弃真)H₀ 为真却拒绝它α把合格随机源误判为不合格
第二类错误(取伪)H₀ 为假却不拒绝它β把有缺陷的随机源误判为合格

α 由我们事先设定,β 则取决于真实偏差大小、样本长度和检验方法,通常难以精确控制。二者存在权衡:降低 α 会减少误杀,但会增大 β,使弱偏差更难被发现。在随机数检测中,增大样本长度、增加测试项、使用更敏感的统计量,都可以在保持 α 不变的前提下降低 β。

这里有一个工程上的关键认识:“通过测试”不等于“证明随机”。它只意味着“在给定样本长度和显著性水平下,没有发现足以拒绝 H₀ 的证据”。一个设计糟糕的伪随机发生器,完全可能通过某一项测试,却通不过另一项。

四、多重比较问题:为什么不能只看单项结果

NIST STS 包含 15 项测试,每项又可能产生多个 p 值;Dieharder 的测试项更多。如果对每个 p 值都独立地用 α = 0.01 判断,那么即使输入是完全理想的随机序列,也会有一定比例的测试“偶然失败”。

假设有 m 个相互独立的检验,每个检验在 H₀ 为真时误拒概率为 α,则至少出现一次误拒的概率约为 1 − (1 − α)m。当 m = 100、α = 0.01 时,这个概率约为 63%。也就是说,即使序列完全合格,也大概率会看到若干项 p < 0.01。这就是多重比较问题。

处理多重比较的常见方法有三类:

  • Bonferroni 校正:把单项阈值改为 α/m。简单保守,但 m 很大时过于严格,容易漏检。
  • 比例判据:NIST STS 采用的方式。它不要求所有 p 值都 ≥ α,而是统计 p < α 的比例,并检查该比例是否落在置信区间内。例如 1000 个 p 值中,允许约 1% 落在 [0, 0.01) 区间,但若显著超过这个比例,则判定异常。
  • p 值均匀性检验:把所有 p 值收集起来,用 χ² 或 KS 检验判断它们是否服从均匀分布。若 p 值整体偏小或分布畸形,说明发生器存在系统性问题。

因此,实际使用 NIST STS 时,正确做法不是“逐项看有没有 p < 0.01”,而是:先看各测试项的 p 值通过比例,再看 p 值整体分布是否均匀,最后结合具体失败项定位问题。单点失败可能是偶然,系统性失败才指向真正的缺陷。

随机性测试的统计判断链 从原假设到多重比较校正 原假设 H₀ 比特独立、0/1 等概率 检验统计量 频数 / 游程 / χ² H₀ 下分布 正态 / χ² / KS 计算 p 值 观测值 → 概率 p < α ? α = 0.01 拒绝 H₀ 该项不合格 不拒绝 H₀ 该项未发现异常 第一类错误 α H₀ 真却拒绝(误杀) 第二类错误 β H₀ 假却不拒绝(漏检) 多重比较校正: Bonferroni α/m | NIST 比例判据(p<α 占比 ≈ 1%) | p 值均匀性检验 m 个独立检验中至少一次误拒概率 ≈ 1 − (1 − α)ᵐ,m=100、α=0.01 时约 63%

五、把统计语言落到测试套件上

理解了上述概念,再看 NIST STS 的输出就不会迷惑。它给出的每一项 p 值,都是在 H₀ 下计算出的证据强度;它给出的“通过比例”,是在处理多重比较;它给出的“p 值均匀性检验结果”,是在检查整体分布是否正常。Dieharder 的 -a 全量测试、TestU01 的 BigCrush 套件,同样遵循这套逻辑,只是测试项更多、统计量更复杂。

实际判断时,建议按以下顺序阅读结果:

  1. 先看总体通过比例是否接近 1 − α,而不是逐项盯 p 值;
  2. 再看 p 值是否整体服从均匀分布,若大量 p 值偏小,说明存在系统性偏差;
  3. 最后定位具体失败项,结合该测试的统计含义分析原因,例如频数检验失败指向 0/1 比例失衡,游程检验失败指向局部相关性;
  4. 若只有个别项偶然失败,可增大样本长度复测,观察失败是否稳定复现。
不要用“所有 p 值都大于 0.01”作为唯一合格标准。在多重比较下,这种要求既不现实,也会掩盖真正的问题。正确的判据是比例合理、分布均匀、失败项可解释。

这套统计语言是后续所有随机性测试工具的共同基础。掌握了 H₀、α、p 值、两类错误和多重比较,就能把测试套件输出的数字翻译成对随机源质量的可靠判断,而不是被单个 p 值牵着走。