2.3 可复现性
3 分钟阅读
rust-random 库对可播种 PRNG 和随机算法的可重现性仅作有限承诺。
本章涉及使用 rust-random 库的确定性过程的价值稳定性。
API 破坏性、值破坏性与 SemVer
如果某项变更(对库的变更)可能导致与先前 API 版本兼容的代码编译失败,或属于其他不兼容变更,则视为 API 破坏性变更。
我们力求遵循 SemVer 规则 处理 API 破坏性变更和 MAJOR.MINOR.PATCH 版本。也就是说,在 1.0 之后,新的次要版本不应引入 API 破坏性变更。
如果某项变更不是 API 破坏性的,但会导致仅使用 rust-random API 未变更部分的确定性随机过程输出值发生变化,则视为 值破坏性变更。
值破坏性变更允许出现在次要版本中。
不可移植的确定性项
rust-random API 中的某项(如结构体或函数)可被声明为 不可移植,意味着它放弃所有可重现性保证。不可移植项可能是确定性的,但在不同平台和库版本上可能产生不同结果(它们可能在任何发布中做出值破坏性变更)。
这是影响 rand 从 0.10 或 1.0(以哪个版本先发布为准)起的政策变更;在 0.9 版本之前,不可移植项不允许在补丁发布中做出值破坏性变更。
此不可移植声明必须在文档中明确提及。以下项做出了此类声明:
可移植项
有些项显然是非确定性的(例如 rand::rng)。有些项是确定性的但不可移植(见上文)。rust-random crate 公共 API 的所有其他部分(包括 PRNG、分布和其他随机算法)预期是可移植的:
- 结果应在各平台间可重现
- 结果应在补丁发布间可重现
- 次要版本(包括 1.0 之后)可能对可移植项做出值破坏性变更。此类变更必须有充分理由,并应在 CHANGELOG 中明确提及。
测试
我们期望所有可移植的随机算法以某种形式的测试向量测试其输出的价值稳定性。
对先前版本的支持
我们力求通过以下方式为使用先前 MAJOR.MINOR 版本 rust-random crate 的用户提供可重现性支持:
- 在适当时以补丁版本提供安全修复
- 应请求协助将未来 crate 版本的兼容新增内容向后移植
- 其他修复可能考虑向后移植,但通常无法在不引入 API 破坏性或值破坏性变更的情况下完成
限制
usize 的可移植性
不幸的是,Rust 语言核心中内置了一项不可移植项:usize(以及 isize)。例如,空 Vec 的大小在 32 位和 64 位目标上会有所不同。对大多数用途而言这不是问题,但在以可移植方式生成随机数时确实重要。
一条简单规则:如果需要可移植性,永远不要直接采样 usize 或 isize 值。
从 rand v0.9 起,isize 和 usize 类型在公共 API 的许多部分中不再受支持,包括 StandardUniform。usize 由 SampleUniform 支持,从而由 Rng::random_range 支持,尽可能使用 u32 采样以最大化可移植性。
浮点数的可移植性
浮点运算的结果取决于舍入模式和实现细节。特别是,超越函数的结果因平台而异。因此,rand_distr 中使用 f32 或 f64 的分布结果可能不可移植。
为缓解(或进一步复杂化)此问题,我们倾向于使用 libm 而非 std 实现这些超越函数。参见 rand_distr 特性。