3.8 随机分布

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

为在产生随机值时获得最大灵活性,我们定义 Distribution trait:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# use rand::Rng;
// 类型 T 的数据生产者:
pub trait Distribution<T> {
    // 核心函数:
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T;

    // 基于 sample 定义的便捷函数:
    fn sample_iter<R>(self, rng: R) -> rand::distr::Iter<Self, R, T>
    where
        Self: Sized,
        R: Rng,
    {
        // [有默认实现]
        # todo!()
    }
}

Distribution 的实现是概率分布:将事件映射到概率(例如掷骰子 P(x = i) = ⅙,或均值为 μ=0 的正态分布 P(x > 0) = ½)。

注意,尽管概率分布都有均值、概率密度函数等性质,并可通过累积分布函数求逆来采样,此处我们只关心采样随机值。若需要这些性质,可能更倾向使用 statrs crate。

Rand 实现了许多不同分布;此处介绍最常见的,完整细节请参阅 distr 模块和 rand_distr crate。

均匀分布

最明显的分布类型是我们已讨论过的:每个等长子范围包含下一个样本的概率相等。这称为均匀。

Rand 实际上有几种变体,表示不同范围:

按类型的均匀采样

按类型说明分布:

  • 对 bool,StandardUniform 以 50% 概率采样每个值。

  • 对 Option<T>,StandardUniform 以 50% 概率采样 None,否则按类型采样 Some(value)。

  • 对整数(u8 到 u128、usize 及 i* 变体),StandardUniform 从所有可能值采样,Uniform 从参数化范围采样。

  • 对 NonZeroU8 及其他「非零」类型,StandardUniform 从所有非零值均匀采样(拒绝法)。

  • Wrapping<T> 整数类型由 StandardUniform 分布按对应整数类型采样。

  • 对浮点(f32、f64),

    • StandardUniform 从半开区间 [0, 1) 采样,精度 24 或 53 位(分别对应 f32 和 f64)
    • OpenClosed01 从半开区间 (0, 1] 采样,精度 24 或 53 位
    • Open01 从开区间 (0, 1) 采样,精度 23 或 52 位
    • Uniform 从给定范围采样,精度 23 或 52 位
  • 对 char 类型,StandardUniform 从所有可用 Unicode 码点均匀采样;许多值可能不可打印(取决于字体支持)。Alphanumeric 仅从 a-z、A-Z 和 0-9 均匀采样。

  • 对元组和数组,在支持的情况下每个元素按上述方式采样。StandardUniform 和 Uniform 各自支持部分这些类型(最多 12 元组和 32 元素数组),包括空元组 () 和数组。使用 rustc ≥ 1.51 时,启用 min_const_gen 特性以支持超过 32 元素的数组。

  • 对 SIMD 类型,每个元素按上述方式由 StandardUniform 和 Uniform 采样(后者 low 和 high 参数也是 SIMD 类型,相当于同时从多个范围采样)。SIMD 支持需要 simd_support 特性标志和 nightly rustc。

  • 对枚举,需自行实现均匀采样。例如可采用以下方式:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    # use rand::{Rng, RngExt, distr::{Distribution, StandardUniform}};
    pub enum Food {
        Burger,
        Pizza,
        Kebab,
    }
    
    impl Distribution<Food> for StandardUniform {
        fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Food {
            let index: u8 = rng.random_range(0..3);
            match index {
                0 => Food::Burger,
                1 => Food::Pizza,
                2 => Food::Kebab,
                _ => unreachable!(),
            }
        }
    }
    

非均匀分布

rand crate 仅提供两种非均匀分布:

  • Bernoulli 分布生成布尔值,采样 true 的概率为某常数(Bernoulli::new(0.5))或比率(Bernoulli::from_ratio(1, 6))。
  • WeightedIndex 分布可用于从加权值序列采样。见[序列]一节。

rand_distr crate 提供更多非均匀分布。

整数

Binomial 分布与 Bernoulli 相关:它模拟运行 n 次独立试验,每次成功概率为 p,然后统计成功次数。

注意对大 n,Binomial 分布的实现比逐个采样 n 次试验快得多。

Poisson 分布表示在固定速率 λ 下事件发生时,固定区间内预期事件数。Poisson 分布采样生成 Float 值,因为采样计算使用浮点数,我们倾向于将整数类型及可能有损且可能 panic 的转换留给用户。例如可用 rng.sample(Poisson) as u64 得到 u64 值。

注意 Rust <1.45 中浮点到整数越界转换用 as 是未定义行为,Rust >=1.45 则是饱和转换。

连续非均匀分布

连续分布模拟从实数轴 ℝ 抽取的样本,或在某些情况下从高维点(ℝ²、ℝ³ 等)。大多数情况我们提供 f64 和 f32 输出,但目前 f32 实现通常只是降低 f64 样本的精度。

指数分布 Exp 模拟固定衰变率下的衰变时间(即指数衰变)。

Normal 分布(也称高斯分布)模拟从给定均值和标准差的正态分布(「钟形曲线」)采样。LogNormal 与之相关:对来自对数正态分布的样本 X,log(X) 呈正态分布;这使正态分布「偏斜」以避免负值并具有长正尾。

UnitCircle 和 UnitSphere 分布模拟从圆边或球面均匀采样。

Cauchy 分布(也称洛伦兹分布)是从点 (x0, γ) 发出、角度均匀分布的射线与 x 轴交点的分布。

Beta 分布是两参数概率分布,输出值在 0 和 1 之间。Dirichlet 分布是推广到任意正数个参数的形式。

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