如何在函数中运行Mersenne Twister



我有一小段代码运行Mersenne Twister PRNG,它工作得很好:

std::random_device randDev;
std::mt19937 twister(randDev());
std::uniform_int_distribution<int> dist(0,99);
for (int i = 0; i < 10; i++) {
    std::cout << dist(twister) << std::endl;
}

它输出十个随机数。但是,如果我将完全相同的代码放入函数中:

#include <random>
int getRand(const int& A, const int& B) {
    std::random_device randDev;
    std::mt19937 twister(randDev());
    std::uniform_int_distribution<int> dist(A,B);
    return dist(twister);
}
int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << getRand(0,99) << std::endl;
    }
    return 0;
}

它输出相同的数字十次。我刚刚开始使用C++所以我不知道是什么原因造成的,也不知道如何解决问题。

编辑:问题出在std::random_device。这可能是Eclipse C++ IDE(Luna版本)或MinGW 4.8.1中的错误,但无论出于何种原因,随机数总是相同的。我相信时间(0)将是适合我使用的种子。

编辑 2:考虑到 T.C. 的建议以及 time(0) 仍然产生 10 个相同数字的事实,这是到目前为止的最终代码。我知道 rand() 很糟糕,但它有效。

#include <iostream>
#include <random>
std::mt19937 twister(rand());
int getRand(const int& A, const int& B) {
    std::uniform_int_distribution<int> dist(A,B);
    return dist(twister);
}
int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << getRand(0,99) << std::endl;
    }
    return 0;
}

问题是每次调用函数时都会创建一个全新的种子、随机数生成器和分布。这不是使用这些类的正确方法。

使用随机数生成器的正确方法是创建一次,并根据整个程序的需要多次使用它(或至少相当长的时间)。以单个函数的形式:

#include <random>
#include <iostream>
int getRand(const int& A, const int& B) {
    static std::random_device randDev;
    static std::mt19937 twister(randDev());
    static std::uniform_int_distribution<int> dist;
    dist.param(std::uniform_int_distribution<int>::param_type(A, B));
    return dist(twister);
}
int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << getRand(0, 99) << std::endl;
    }
    return 0;
}

静态变量在第一次调用函数时初始化,并重新用于所有后续调用。

您使用什么编译器和操作系统?Visual Studio 2012(不确定2013年)没有真正的std::random_device实现,这意味着它每次都使用相同的值初始化 - 所以在这种情况下,每次都会使用相同的种子初始化mersenne twister,因此结果相同。

顺便说一句,似乎提出了同样的问题:

为什么使用 mingw gcc4.8.1 每次使用 std::random_device 运行都会得到相同的序列?

所以显然 Windows 上的 GCC4.8 也有 std::random_device 作为伪随机实现的。

最新更新