通过构造函数错误地播种Mersenne Twister

时间:2017-06-20 22:00:20

标签: c++ random constructor std mersenne-twister

我的构造函数有什么问题?每当我调用一个应该生成随机数的函数(大约每五秒一次)时,它就会生成相同的数字。每个调用都会在下面实例化其中一个对象。我以为我随机播放了m_gen m_rd operator() m_rd()的输出。{/ p>

我可以将Shuffler(std::random device& rd)的结果传递给构造函数吗?签名是什么? #include <random> class Shuffler { private: std::random_device m_rd; std::mt19937 m_gen; public: //! The default constructor. Shuffler(); }; ?但那对用户来说会更难。

编辑:

实际上,如果可能的话,我更喜欢一个解决方案,你不需要将任何东西传递给构造函数。

shuffler.h

#include "shuffler.h"

Shuffler::Shuffler() : m_gen(m_rd())
{
}

shuffler.cpp

"bundles": {
    "dist/app-build": {
        "includes": [
            "[**/*.js]",
            "**/*.html!text",
            "**/*.css!text"
        ],
        "options": {
            "sourceMaps": 'inline'
            "inject": true,
            "minify": true,
            "depCache": true,
            "rev": true
        }
    },

2 个答案:

答案 0 :(得分:3)

std::random_device通常适用于此类事情,但它可能不适用于所有平台。而大多数平台&#39;标准库根据一些底层OS随机功能(即Linux上的/ dev / urandom或Windows上的CryptGenRandom)实现它,C ++标准不要求这样做。在某些平台上,高质量的随机生成器可能无法使用,标准允许std::random_device成为简单的静态种子PRNG。如果是,则每个std::random_device对象将生成相同的数字序列。

出于这些原因,你可能想回到简单的时间播种。标准 提供std::chrono::high_resolution_clock

class Shuffler
{
private:
    std::mt19937 m_gen;
public:
    Shuffler()
        : m_gen{static_cast<std::uint32_t>(
              std::chrono::high_resolution_clock::now().time_since_epoch().count()
          )}
    {}
};

std::chrono::high_resolution_clock通常具有纳秒或数百纳秒的分辨率。这足够高,通过调用high_resolution_clock播种的两个PRNG不太可能最终使用相同的种子。但这也不能保证。例如,std::chrono::high_resolution_clock在macOS上只有微秒级的分辨率,这可能会或可能不足以满足您的需要。

最后,这两种方法都不完美。您可能希望使用std::seed_seq组合两者:

std::seed_seq make_seeds() {
    thread_local std::random_device rd;
    return {{
        static_cast<std::uint32_t>(std::chrono::high_resolution_clock::now().time_since_epoch().count()),
        rd()
    }};
}

// Cast away rvalue-ness because the standard random generators need
// an lvalue reference to their seed_seq for some strange reason
template <typename T>
T& identity(T&& t) { return t; }

class Shuffler
{
private:
    std::mt19937 m_gen;
public:
    Shuffler()
        : m_gen{identity(make_seeds())}
    {}
};

正如你所看到的,这远非简单,而且还不完美。有关种子和随机数生成器的详细信息,请参阅these blog posts

答案 1 :(得分:0)

与此example一样,你必须播种它,random_device似乎没有做到这一点 *

// do this once somewhere
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();


class Shuffler
{
private:
    std::mt19937 m_gen;
public:
    Shuffler()  : m_gen(seed) {}

};

*如上所述hererandom_device不是种子序列!