Far*_*nor 5 c++ language-lawyer random-seed
背景:
从c++11开始,建议使用 astd::random_device而不是 time 来为随机数生成器提供种子。如果我们看一下相关文档,我们可以读到:
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;
}
Run Code Online (Sandbox Code Playgroud)
如果系统/平台不提供非确定性源,则该程序可能/将始终为每次运行生成相同的数字序列(实际上在我的平台上就是这种情况)。
在这种情况下,std::random_device比用当前时间播种随机数生成器要糟糕得多:
std::mt199937 gen(std::chrono::high_resolution_clock::now().time_since_epoch().count()); // time seed
Run Code Online (Sandbox Code Playgroud)
问题:
我担心的是,如果有人想编写一个依赖于一些随机生成的数字的程序,并且需要:
那么std::random_device就不会是一个合适的人选。
另一方面,始终使用时间种子将是一个非常令人沮丧的“解决方案”,因为如果给定平台具有可用的非确定性源,std::random_device那么就会“更安全”。
问题:
我的问题分为两部分:
std::random_device如果主机平台没有可用的非确定性源,是否允许编译器用时间种子替换种子?或者标准中是否有某些内容会阻止这种替换?也许这些应该是 2 或 3 个独立的问题。由于背景和问题很常见,因此我在同一篇文章中询问了他们,以确保该主题的完整性。无论如何,如果我必须将它们分成单独的问题,请告诉我。
是否有一种可移植的方法来检查当前平台上是否存在此类非确定性源?
您可以使用entropy成员函数std::random_device来检查源是否是不确定的。不幸的是它不是一个static constexpr函数,所以你必须使用常规的 if 语句,例如
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;
}
Run Code Online (Sandbox Code Playgroud)
std::random_device如果主机平台没有可用的非确定性源,是否允许编译器用时间种子替换种子?或者标准中是否有某些内容会阻止这种替换?
这会改变程序的可观察行为,所以不,编译器不能这样做。