3.8 随机分布
4 分钟阅读
为在产生随机值时获得最大灵活性,我们定义 Distribution trait:
| |
Distribution 的实现是概率分布:将事件映射到概率(例如掷骰子 P(x = i) = ⅙,或均值为 μ=0 的正态分布 P(x > 0) = ½)。
注意,尽管概率分布都有均值、概率密度函数等性质,并可通过累积分布函数求逆来采样,此处我们只关心采样随机值。若需要这些性质,可能更倾向使用 statrs crate。
Rand 实现了许多不同分布;此处介绍最常见的,完整细节请参阅 distr 模块和 rand_distr crate。
均匀分布
最明显的分布类型是我们已讨论过的:每个等长子范围包含下一个样本的概率相等。这称为均匀。
Rand 实际上有几种变体,表示不同范围:
StandardUniform无需参数,按类型均匀采样。Rng::random是该分布的快捷方式。Uniform由Uniform::new(low, high)(含low、不含high)或Uniform::new_inclusive(low, high)(两端都含)参数化,在该范围内均匀采样。Rng::random_range是定义在Uniform::sample_single之上的便捷方法,针对单次采样优化。Alphanumeric在char值0-9A-Za-z上均匀。Open01和OpenClosed01为浮点类型提供替代采样范围(见下文)。
按类型的均匀采样
按类型说明分布:
对
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特性标志和 nightlyrustc。对枚举,需自行实现均匀采样。例如可采用以下方式:
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 轴交点的分布。