提问人:Fareanor 提问时间:2/28/2020 最后编辑:NathanOliverFareanor 更新时间:2/28/2020 访问量:1317
如何以安全便携的方式播种随机数生成器?
How to seed a random number generator in a safe and portable way?
问:
背景:
从 c++11 开始,建议使用 a 而不是 time 来播种随机数生成器。如果我们看一下相关文档,我们可以读到:std::random_device
std::random_device
如果非确定性源(例如硬件设备)不可用于实现,则可以使用实现定义的伪随机数引擎来实现。在这种情况下,每个对象可以生成相同的编号规则。std::random_device
强调我的
现在让我们考虑以下示例:
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution distr(0, 9);
// Print a sequence of 10 uniformly distributed random integers
for(std::size_t i = 0; i < 10; ++i)
std::cout << distr(gen) << ' ';
return 0;
}
如果系统/平台不提供非确定性源,则该程序可能/将始终为每次运行生成相同的数字序列(实际上在我的平台上就是这种情况)。
在这种情况下,远比用当前时间播种随机数生成器更糟糕:std::random_device
std::mt199937 gen(std::chrono::high_resolution_clock::now().time_since_epoch().count()); // time seed
问题:
我担心的是,如果有人想编写一个程序,该程序将依赖于一些随机生成的数字,并且是必需的:
- 便携
- 保证非确定性随机性
那么就不合适了。
另一方面,始终使用时间种子将是一个非常令人沮丧的“解决方案”,因为如果给定的平台有一个不确定的源可用,那么就会“更安全”。std::random_device
std::random_device
问题:
我的问题分为两部分:
- 用户空间
- 有没有一种可移植的方法来检查当前平台上是否存在这种不确定的源?
- 编译器端
- 如果主机平台没有可用的非确定性源,是否允许编译器用时间种子替换种子?或者标准中是否有某些东西会阻止这种替换?
std::random_device
- 如果标准没有禁止这种行为,那么编译器有什么理由不实现它呢?
- 如果主机平台没有可用的非确定性源,是否允许编译器用时间种子替换种子?或者标准中是否有某些东西会阻止这种替换?
也许这些应该是 2 或 3 个单独的问题。由于背景和问题很常见,我在同一篇文章中询问了他们关于该主题的完整性。如果无论如何我必须将它们分成单独的问题,请告诉我。
答:
有没有一种可移植的方法来检查当前平台上是否存在这种不确定的源?
您可以使用 的熵
成员函数来检查源是否是不确定的。不幸的是,它不是一个函数,因此您必须使用常规的 if 语句,例如std::random_device
static constexpr
int main()
{
std::random_device rd;
std::size_t seed;
if (rd.entropy())
seed = rd();
else
seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
std::mt19937 gen(seed);
std::uniform_int_distribution distr(0, 9);
// Print a sequence of 10 uniformly distributed random integers
for(std::size_t i = 0; i < 10; ++i)
std::cout << distr(gen) << ' ';
return 0;
}
如果主机平台没有可用的非确定性源,是否允许编译器用时间种子替换种子?或者标准中是否有某些东西会阻止这种替换?
std::random_device
这将改变程序的可观察行为,所以不,编译器不能这样做。
评论
std::random_device::entropy
评论
std::random_device