是否标准:: mt19937需要预热?(Does std::mt19937 require warm

2019-07-22 01:29发布

我读过许多伪随机数发生器要求下令“热身”许多样品。 是的情况下使用时的std :: random_device种子的std :: mt19937,或者我们可以预期,它的建设后,准备好了? 有问题的代码:

#include <random>
std::random_device rd;
std::mt19937 gen(rd());

Answer 1:

梅森倍捻机是一个移位寄存器基于PRNG(伪随机数生成器),并因此受到与0或1的长版活,直到内部状态混合了足够导致相对可预测的结果坏种子。

但是这需要一个单一的值的构造上使用,其被设计以最小化生产这样的“坏”的状态的可能性种子值的复杂函数。 有初始化第二种方式mt19937 ,你直接设置内部状态,经由符合SeedSequence概念的对象。 这是初始化,您可能需要担心选择一个“好”的状态或做热身的第二种方法。


该标准包括一个对象符合SeedSequence概念,称为seed_seqseed_seq取输入的种子值的任意数量,并且然后执行对这些值的某些操作,以产生适合于直接设置一个PRNG的内部状态不同的值的序列。

下面是装载了足够的随机数据的种子序列,填补了整个的一个实例std::mt19937状态:

std::array<int, 624> seed_data;
std::random_device r;
std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));

std::mt19937 eng(seq);

这确保了整个状态是随机的。 此外,每个引擎指定它从seed_sequence读取的数据量,所以你可能需要阅读的文档找到你使用什么引擎,信息。

虽然在这里我从完全加载了seed_seq std::random_deviceseed_seq ,特别规定只是几个数字不是特别随机应该很好地工作。 例如:

std::seed_seq seq{1, 2, 3, 4, 5};
std::mt19937 eng(seq);

在下面Cubbi的评论表明, seed_seq的工作原理是对你进行热身序列。

以下是应该是你播种“默认”:

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 rng(seed);


Answer 2:

如果只用一个32位的值种子,所有你曾经得到的是同样的2 ^ 32的轨迹,通过状态空间之一。 如果您使用状态的一个知识密集型服务业PRNG,那么你或许应该种子全部。 正如评论描述@ bames63的回答,使用std::seed_seq可能不是一个好主意,如果你想用随机数初始化整个国家。 可悲的是, std::random_device不符合SeedSequence概念,但你可以写一个包装,做:

#include <random>
#include <iostream>
#include <algorithm>
#include <functional>

class random_device_wrapper {
    std::random_device *m_dev;
public:
    using result_type = std::random_device::result_type;
    explicit random_device_wrapper(std::random_device &dev) : m_dev(&dev) {}
    template <typename RandomAccessIterator>
    void generate(RandomAccessIterator first, RandomAccessIterator last) {
        std::generate(first, last, std::ref(*m_dev));
  }
};

int main() {

    auto rd = std::random_device{};
    auto seedseq = random_device_wrapper{rd};
    auto mt = std::mt19937{seedseq};
    for (auto i = 100; i; --i)
        std::cout << mt() << std::endl;

}

这个工程至少要等到您启用的概念。 根据你的编译器是否知道SeedSequence作为C ++ 20 concept ,它可能无法工作,因为我们只供应缺失的generate()方法,没有别的。 在鸭类型的模板编程,该代码是足够的,但是,因为该PRNG不存储种子序列对象。



Answer 3:

我相信有MT在那里可以“很差”,这导致非最佳序列播种情况。 如果我没有记错,播种全0就是这样的情况。 我建议你尝试使用WELL发电机,如果这是一个严重的问题给你。 我相信他们是更加灵活 - 种子的质量没有关系一样多。 (也许是为了更直接地回答你的问题:它可能更有效地专注于播种以及反对接种不良然后试图生成一堆样品拿到发电机到最佳状态。)



文章来源: Does std::mt19937 require warmup?