跳至主要内容

博文

精选博文

如何安全地初始化 C++ 标准库中的 mt19937

如何安全地初始化 C++ 标准库中的 mt19937 背景 在看到 C++ Seeding Surprises ᴮᵃᶜᵏᵘᵖ 这篇文章之前,我一直使用如下代码初始化 std::mt19937 : std::mt19937 mtr(std::random_device{}()); 问题 std::random_device 可能根本不是随机的 旧版 MinGW 中的 GCC 将其实现为确定性的,参见 std::random_device not working properly ᴮᵃᶜᵏᵘᵖ ,这一问题已在 MinGW GCC 9.2 中修复。 std::random_device 的值域不够大 std::random_device 的值域同 unsigned int ,在我的环境中为 [0,2^{32}-1] ,只提供了 32 位的随机性。 2^{32} 并不是一个很大的数字,下面我们来进行一组测试: 测试 环境: Intel Core i7-9750H @ 2.60GHz 单核 代码: 🔗 链接 编译结果: 🔗 链接 输出: Time: 1.74991 0 100035 1 100466 2 99877 3 100526 4 99746 5 100291 6 99643 7 99749 8 100147 9 99520 测试的数据范围是 10^6 ,因此预计可以在 2.09 小时内遍历 2^{32} 种情况。 众所周知,只要知道种子,就可以预测整个随机序列。因此,对于需要高安全性的用例来说,32 位的种子远远不够。 需要高安全性的用例应当使用 密码学安全伪随机数生成器 ᴮᵃᶜᵏᵘᵖ 。 std::seed_seq 的实现不靠谱 上面的代码中,我们只给 std::mt19937 提供了一个 32 位整数,但是 Mersenne Twister 的状态包含 624 个 32 位整数(参见 维基百科 ᴮᵃᶜᵏᵘᵖ ),因此标准库会使用 std::seed_seq 来扩充状态。 然而 std::seed_seq 的实现有问题。 在使用 32 位整数进行播种时,包括 7 和 13 在内的大约 \frac{2^{32}}e 个数永远不可能作为 std::mt

最新博文

Sperner 定理

WSL 中 /dev/random 和 /dev/urandom 的熵是哪里来的

【分享】《银河系漫游指南》PDF 版本

物理思维导图

作文听课笔记