正确地播种随机数发生器(Mersenne Twister)C

Correctly seeding random number generator (Mersenne twister) c++

本文关键字:Mersenne Twister 发生器 随机数 正确地      更新时间:2023-10-16

除了是垃圾程序员外,我的术语还没有划痕。我将尽力解释自己。我已经使用Randomlib实现了Merssene Twister随机数生成器。诚然,我对Visual 8 C 的随机数生成器的工作方式并不太熟悉,但是我发现可以在main()中播种srand(time(NULL)),并且可以在其他类中安全地使用rand()。我需要创建一个对象,然后播种该对象的Merssene Twister。

#include <RandomLib/Random.hpp>
RandomLib::Random r;        // create random number object
r.Reseed();                 // seed with a "unique" seed
float d = r.FloatN();   // a random in [0,1] rounded to the nearest double

如果我想在类中生成一个随机数,我该如何执行此操作而无需每次定义对象。我只是担心,如果我使用计算机时钟,我将每次运行使用相同的种子(每秒只会更改)。

我解释自己对吗?

预先感谢

随机对象本质上是您需要保留的状态信息。您可以使用所有普通技术:可以将其作为全局变量或将其作为参数传递。如果特定类需要随机数,则可以将Random对象作为类成员保留以提供该类的随机性。


C <random>库是相似的,因为它需要对象作为随机性/RNG状态的来源。这是一个很好的设计,因为它允许程序控制对状态的访问,例如,通过多个线程确保良好的行为。C <random>库甚至包括Mersenne Twister算法。

这是一个示例,显示保存RNG状态为类成员(使用std::mt19937而不是Random

#include <random> // for mt19937
#include <algorithm> // for std::shuffle
#include <vector>
struct Deck {
    std::vector<Cards> m_cards;
    std::mt19937 eng; // save RNG state as class member so we don't have to keep creating one
    void shuffle() {
        std::shuffle(std::begin(m_cards), std::end(m_cards), eng);
    }
};
int main() {
    Deck d;
    d.shuffle();
    d.shuffle(); // this reuses the RNG state as it was at the end of the first shuffle, no reseeding
}

所接受的答案实际上并未播种其MT19937,请参阅此Q&amp; a,以了解如何实现这一目标以及为什么没有单一解决方案:

如何简洁,便捷和彻底播种MT19937 PRNG?

tl; dr:

这个问题与Randomlib有关,但由于<random>更容易访问10年,我将通过参考STL实现来回答。这些原则应适用于所有mt19937实施。

std::mt19937std::mt19937_64具有内部默认种子,为发动机提供了某种状态。默认种子将使发动机每次都会产生相同的值,除非重新种子。

std::mt19937提供了两种通过seed()函数播种的方法。

第一个过载接受result_type的参数(std::mt19937uint32_tstd::mt19937_64uint64_t)。在内部(至少在MSVC实施中),此功能将使用提供的种子值来通过一系列的钻头操作来填充其内部状态。大多数快速和dix的示例将使用std::random_device提供此种子值,但是由于标准允许random_device只是另一个PRNG,在所有情况下都不能依靠它,显然是(或)Mingw的情况Windows上的编译器。

第二个过载可以接受更通用的生成器/范围参数,该参数可以与std::seed_seq一起使用。链接的问题有一个如何创建其中之一的示例。

创建seed_seq或足够随机的初始种子是一个挑战,以及为什么提供链接的问题。

不建议您每次需要一个新的Mersenne Twister Prng,因为播种过程是非平凡的。取而代之的是,最好将一次声明并保留为静态的静态,全局,或一堂课的成员。