迭代生成随机数序列

时间:2014-04-30 18:10:42

标签: 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个独特的随机数序列。

1 个答案:

答案 0 :(得分:3)

你需要了解PRNG是如何工作的,而提示是在 Pseudo 的P中(其余是随机数生成器)。

PRNG不会创建随机的数字序列,因为它不是随机的:对于相同的输入(种子),始终会生成相同的序列,并且此序列在给定的时间段内循环。例如,公共32 bits Mersenne Twiser的周期为2 19932 -1个元素,这意味着它会在多次迭代后循环。当然,还有其他有趣的属性,例如生成速度或随机性&#34;观察,我建议你阅读这篇文章。

最重要的是,PRNG完全依赖于它的种子;因此,只要你给它相同的种子,它将返回相同的数字序列。在您的情况下,C库使用由srand播种的单个(隐藏和未指定)PRNG,并通过rand迭代其序列。你观察到的问题是由于你用来为这个PRNG种子的time函数缺乏精确性:因为它只在第二个时精确,如果你在同一秒内绘制N系列,你将获得所有N相同。这可以通过更好的播种来解决:在过程开始时只播种一次。

注意:几年前使用time(0)作为种子的一些pocker服务器被黑客入侵,因为time的输出几乎不是秘密;为了保密PRNG是不够的,你需要CSPRNG,这是密码安全的PRNG。

现在,还有一个问题,不幸的是,使用全局状态会在口中留下不良状态(并发问题和所有......)因此建议使用C ++ 11 <random>库,如果你有权访问它。在C ++ 11中,有3个部分可以生成随机数:

  1. std::random_device使用实现定义的熵源来为引擎播种
  2. 引擎本身(例如std::default_random_engine)生成随机值
  3. 分布,消耗引擎值并产生与某个分布匹配的新值(uniform,bernoulli,poisson,......)
  4. 注意:引擎和分发都是(可能)有状态的,应该通过引用传递。

    例如你可以这样做:

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