如何在函数内运行 Mersenne Twister?
How to run Mersenne Twister inside a function?
我有一小段代码可以运行 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) 仍然导致相同数字的 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;
}
您使用什么编译器和OS?
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 作为伪随机实现。
问题是每次调用该函数时,您都会创建一个全新的种子、随机数生成器和分布。这不是使用这些 类.
的正确方法
使用随机数生成器的正确方法是创建一次,然后在整个程序中根据需要多次使用(或至少使用相当长的时间)。单函数形式:
#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;
}
静态变量在第一次调用函数时初始化,并在所有后续调用中重复使用。
我有一小段代码可以运行 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) 仍然导致相同数字的 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;
}
您使用什么编译器和OS? 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 作为伪随机实现。
问题是每次调用该函数时,您都会创建一个全新的种子、随机数生成器和分布。这不是使用这些 类.
的正确方法使用随机数生成器的正确方法是创建一次,然后在整个程序中根据需要多次使用(或至少使用相当长的时间)。单函数形式:
#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;
}
静态变量在第一次调用函数时初始化,并在所有后续调用中重复使用。