与C++2011不相关的并行随机种子

Uncorrelated parallel random seeds with C++ 2011?

本文关键字:随机 种子 并行 C++2011 不相关      更新时间:2023-10-16

目前,我在Fortran中有一个主要应用程序,它需要一个种子来生成伪随机数。我想用完全不相关的种子(以及完全独立的伪随机数链)运行很多次这个应用程序。

我的问题是:如何用C++2011生成种子?

在主线程中,从一个好的随机源(例如Linux上的/dev/urandom)中提取一个种子(或种子序列)。使用该数据为单个根PRNG设定种子。然后使用PRNG为线程本地PRNG生成种子值。

#include <random>
#include <vector>
typedef std::mt19937 rng_type;
std::uniform_int_distribution<rng_type::result_type> udist;
int main()
{
    rng_type rng;
    // seed rng first, and store the result in a log file:
    rng_type::result_type const root_seed = get_seed();
    rng.seed(root_seed);
    // make thread seeds:
    std::vector<rng_type::result_type> seeds(NUMBER_OF_THREADS);
    for (auto & n : seeds) { n = udist(rng); }
    // make threads...
}

<random>中的随机数引擎接口允许您从单个整数和整数的序列进行种子设定。如果需要额外的随机性,可以从几百个整数的序列中为mt19937种子。

C++11提供std::random_device,以便在源可用的情况下提供非确定性随机数。不过,您必须检查您的实现,以确保它是好的。libc++默认使用/dev/urandom。如果定义了宏_GLIBCXX_USE_RANDOM_TR1,那么libstdc++也可以。不幸的是,VisualStudio的实现不是非确定性的edit:从VS2012开始,它们的实现使用Windows的加密服务

如果std::random_device提供对非确定性随机性源的访问(通常/dev/urandom使用加密PRNG),那么这应该足以生成独立种子。

#include <random>
int main() {
    std::random_device r;
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
    std::mt19937 engine(seed);
}

有些引擎可能会使用更多的种子数据,而不是使用单个值作为种子。种子序列是该标准提供的替代方案。引擎可以使用种子序列进行种子设定,种子序列是用任意数量的数据加载的对象,并在此基础上生成种子数据。

std::random_device r;
std::vector<std::mt19937> engines;
int engines = 50;
for (int i = 0; i < engines; ++i) {
    std::seed_seq s{r(), r(), r(), r(), r(), r(), r(), r()};
    engines.emplace_back(s);
}

八个32位值,256位,已经足够了,但如果你真的想要,你可以使用更多。每个标准引擎都记录了它从种子序列中使用了多少数据。

例如,每个mt19937引擎将从种子序列中检索mt19937::state_size(624)32位值。从种子序列中检索到的种子与输入数据不同,但它们是基于这些数据的,所以我们可以在序列中使用那么多随机数据。

std::random_device r;
std::vector<std::uint_least32_t> data;
std::generate_n(back_inserter(data), 624, std::ref(r));
std::seed_seq seed(begin(data), end(data));
std::mt19937 engine(seed); // 'fully' seeded mt19937

您永远无法真正生成随机种子。你把它们从某个地方拉出来。操作系统可能有一种方法来检索可用于种子的伪随机值(例如,Linux上的/dev/urandom)。

获取表示当前时间的时间戳也是一种常见的选择——然后,为了确保每个线程获得不同的种子,只需确保他们在稍微不同的时间请求时间戳,并使用高分辨率计时器来确保他们实际上获得不同的值作为种子。

C++11中没有"获得一个好的种子"函数,因为这样的函数本质上是没有意义的。计算机无法生成随机数据。你必须选择一些看起来足够随机的东西来达到你的目的,并用它来为随机生成器

播种