我想使用 C++ 快速连续地生成许多随机数序列。我面临的问题是使用我的代码获得相同的序列。考虑以下从 U[0,1] 生成变量的玩具示例
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <fstream>
using namespace std;
// function to generate uniform random
// variates on [0,1]
void uniform(double *pt, int n);
int main()
{
// File to output results
ofstream output("output.txt");
// Generate two sequences of uniform random variates
double uniform_variates1[10];
double *pt_uniform1 = uniform_variates1;
uniform(pt_uniform1, 10);
double uniform_variates2[10];
double *pt_uniform2 = uniform_variates2;
uniform(pt_uniform2, 10);
// Output results
for( int i=0; i < 10; i++)
{
output << uniform_variates1[i] << "\t" << uniform_variates2[i] << endl;
}
return 0;
}
void uniform(double *pt, int n)
{
// seed for rand()
srand((unsigned)time(0));
for( int i=0; i < n; i++)
{
pt[i] = 1.0*rand()/RAND_MAX;
}
}
此代码的示例输出,指示所有其他运行如下所示。
0.0769677 0.0769677
0.933256 0.933256
0.234535 0.234535
0.413251 0.413251
0.0505387 0.0505387
0.854274 0.854274
0.0886563 0.0886563
0.57152 0.57152
0.697195 0.697195
0.7004 0.7004
可以看出,这两个序列是完全相同的。我怎样才能避免这个问题?我需要为一个项目做一些类似的事情,除了我需要大约 1000 个唯一的随机数序列。
最佳答案
您需要了解 PRNG 的工作原理,提示在 P 中代表 Pseudo(其余为随机数生成器)。
PRNG 不会创建随机数字序列,因为它不是随机的:对于相同的输入(种子),始终会生成相同的序列,并且该序列在给定的周期内循环。比如常见的32 bits Mersenne Twiser有 219932-1 个元素的周期,这意味着它将在多次迭代后循环。当然,还有其他有趣的属性,例如生成速度或观察到的“随机性”,我建议您阅读这篇文章。
不过,最重要的是 PRNG 完全依赖于它的种子;因此只要你给它相同的种子,它就会返回相同的数字序列。在您的情况下,C 库使用由 srand
播种的单个(隐藏和未指定的)PRNG。并通过 rand
迭代其序列.您观察到的问题是由于 time
不够精确所致你用来播种这个 PRNG 的函数:因为它只在第二个是精确的,如果你在同一秒内绘制 N 个系列,你将得到所有 N 个相同的。这可以通过更好的播种来解决:只播种一次,在过程开始时。
注意:一些 pocker 服务器使用 time(0)
因为种子在几年前被黑了,因为 time
的输出几乎不是 secret ;对于保密性 PRNG 是不够的,您需要 CSPRNG,它是加密安全的 PRNG。
现在,还有一个问题是,不幸的是,使用全局状态会留下不好的状态(并发问题和所有...),因此建议使用 C++11 <random>
图书馆,如果你可以访问它。在C++11中,生成随机数分为3个部分:
-
std::random_device
使用实现定义的熵源为引擎播种 - 引擎本身(例如
std::default_random_engine
)产生随机值 - 分布,消耗引擎值并产生与特定分布(均匀分布、伯努利分布、泊松分布等)匹配的新值
注意:引擎和分发(可能)都是有状态的,应该通过引用传递。
例如你可以这样做:
std::vector<double> uniform(std::default_random_engine& engine, size_t length) {
std::uniform_real_distribution<> dist(0, 1);
std::vector<double> result;
for (size_t i = 0; i != length; ++i) {
result.push_back(dist(engine));
}
return result;
}
并在main
中调用这个函数,其任务是为引擎播种:
int main()
{
static size_t const Size = 10;
// File to output results
std::ofstream output("output.txt");
// Initialize the engine
std::random_device rd;
std::default_random_engine engine(rd());
// Generate two sequences of uniform random variates
std::vector<double> const u1 = uniform(engine, Size);
std::vector<double> const u2 = uniform(engine, Size);
// Output results
for (size_t i = 0; i < Size; i++)
{
output << u1[i] << "\t" << u2[i] << "\n";
}
return 0;
}
关于c++ - 迭代生成随机数序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23395172/