【问题标题】:How to run Mersenne Twister inside a function?如何在函数中运行 Mersenne Twister?
【发布时间】:2015-03-01 19:57:32
【问题描述】:

我有一小段代码运行 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 中的错误,但无论出于何种原因,随机数总是相同的。我相信 time(0) 将是适合我使用的种子。

编辑 2: 考虑到 T.C. 的建议以及 time(0) 仍然导致十个相同数字的事实,这是迄今为止的最终代码。我知道 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;
}

【问题讨论】:

  • 你用的是什么编译器?使用g++-4.9 对我来说效果很好。
  • 在第一种情况下你总是得到相同的随机值序列吗?
  • 我使用 MinGW,实际上现在我检查过,我确实得到了相同的十个随机数,每个随机数都使用第一个代码运行。
  • 你不应该每次调用函数时都真正构造引擎。

标签: c++ c++11 mersenne-twister


【解决方案1】:

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

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

#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;
}

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

【讨论】:

  • 感谢您改进我的代码,但在这种情况下,问题不是我正在重新创建种子,而是使用 std::random_device 的 Eclipse 或 MinGW 的错误。
  • GCC random_device 问题在链接的问题中得到了很好的回答。我的回答是针对您最初提出的问题,可能对其他人有用。
【解决方案2】:

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

顺便说一句,似乎有人问了同样的问题:

Why do I get the same sequence for every run with std::random_device with mingw gcc4.8.1?

显然,Windows 上的 GCC4.8 也将 std::random_device 实现为伪随机。

【讨论】:

  • 我使用 Eclipse C++ IDE (Luna) 和 MinGW。
  • 我认为上述线程的答案正是您所寻求的
猜你喜欢
  • 2014-02-22
  • 2020-01-10
  • 2020-02-03
  • 2012-01-13
  • 2020-05-22
  • 1970-01-01
  • 2014-04-17
  • 2016-02-21
  • 1970-01-01
相关资源
最近更新 更多