简体   繁体   中英

Generating sequences of random number iteratively

I want to generate many sequences of random numbers in quick succession using C++. The problem I am facing is getting the same sequence using my code. Consider the following toy example of generating variates from 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;
    }
} 

A sample output of this code, indicative of all other runs is shown below.

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

As can be seen, these two sequences are absolutely identical. How can I avoid this problem? I need to do something similar for a project, except that I require about a 1000 unique random number sequences.

You need to understand how PRNG work, and the hint is in the P for Pseudo (the rest is Random Number Generator).

A PRNG does not create a random sequence of number because it is not random: for the same input (seed) the same sequence is always produced, and this sequence cycles at a given period. For example, the common 32 bits Mersenne Twiser has a period of 2 19932 -1 elements, meaning that it would cycle after that many iterations. Of course, there are other interesting properties, such as the speed of generation or the "randomness" observed, I advise you read the article.

What matters most, though, is that a PRNG is totally dependent on its seed; therefore as long as you give it the same seed, it will return the same sequence of numbers. In your case, the C library uses a single (hidden and unspecified) PRNG seeded by srand and iterating over its sequence via rand . The issue you observed is due to the lack of precision of the time function that you use to seed this PRNG: because it is only precise at the second, if you draw N series within the same second you will get all N identical. This can be solved by better seeding: Only seed once, at the start of the process.

Note: some pocker servers using time(0) as a seed were hacked a few years ago, because the output of time is hardly a secret; for secrecy PRNG are not sufficiency, you need CSPRNG that is Cryptographically Secure PRNG.

Now, there is also the issue that, unfortunately, using global state leaves a bad state in the mouth (concurrency issues and all...) and thus it is advisable to use the C++11 <random> library if you have access to it. In C++11, there are 3 parts to generate random numbers:

  1. std::random_device uses an implementation defined source of entropy to seed an engine
  2. The engine itself (such as std::default_random_engine ) produces random values
  3. The distribution, which consumes an engine value and produces a new value matching a certain distribution (uniform, bernoulli, poisson, ...)

Note: both the engine and the distribution are (potentially) stateful and should be passed by reference.

For example you could do:

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

And invoke this function in main , which is tasked with seeding the engine:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM