c++ - 迭代生成随机数序列

标签 c++ random

我想使用 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个部分:

  1. std::random_device使用实现定义的熵源为引擎播种
  2. 引擎本身(例如 std::default_random_engine )产生随机值
  3. 分布,消耗引擎值并产生与特定分布(均匀分布、伯努利分布、泊松分布等)匹配的新值

注意:引擎和分发(可能)都是有状态的,应该通过引用传递。

例如你可以这样做:

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/

相关文章:

java - 在大于 Integer.MAX_VALUE 的范围内选择随机整数?

c++ - SetWindowsHookEx() ,钩子(Hook)不维护? (可能)

c++ - 获取用数字字符串表示的树中的所有直接父/子

c++ - 如何更改背景颜色 OnMouseover c++ MFC

.net - 先学什么——C++/STL/QT 或 .NET/C#——如果我的学习和工作时间有限?

python - 在 Python 中生成非重复随机数

c - 在C中随机打印一个字符

c - 合并排序的打印时间

java - 自动生成的静态变量,必须在构造函数中传递以进行对象实例化

c++ - 需要一个好的非托管 C++ OCX 示例