choose random vector entry

Pages: 123
A single constant value may not always guarantee high quality randomness (the choice of the single constant value maybe an unfortunate one; the state of std::mt19937 consists of 624 unsigned integer values).

To get a sequence of reproducible pseudo random numbers, perhaps use a seed sequence of several constant values; for instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <random>
#include <iomanip>

double random_double( double a, double b ) {

    // seed sequence of constant values: this will generate
    // the same sequence of pseudo random numbers each time the program is run
    static std::seed_seq seed_sequence { 100, 78639, 193, 55555, 3, 2348089, 6474367, 264441578 } ;
    static std::mt19937 rng (seed_sequence) ;
    static std::uniform_real_distribution<double> distribution ;

    distribution.param( std::uniform_real_distribution<double>::param_type{ a, b } ) ;
    return distribution(rng) ;
}

int main() {

    std::cout << "\nthis program generates the same sequence of pseudo random numbers "
                 "each time it is run\n\n" ;
    const double dl = 0.1 ;
    const double a = -1 ;
    const double b = +1 ;

    std::cout << std::fixed << std::setprecision(8) << std::showpos ;

    for( int i = 0 ; i < 50 ; ++i ) {

        for( int j = 0 ; j < 10 ; ++j )
            std::cout << std::setw(11) << dl * random_double(a,b) << ' ' ;
        std::cout << '\n' ;
    }
}

http://coliru.stacked-crooked.com/a/4a3f12e229e89204
http://rextester.com/GRAAOE14775
Ok.. can you explain to me what exactly is going on?
I understand you are using a sequence of seeds.

1
2
3
4
5
6
for( int i = 0 ; i < 50 ; ++i ) {

        for( int j = 0 ; j < 10 ; ++j )
            std::cout << std::setw(11) << dl * random_double(a,b) << ' ' ;
        std::cout << '\n' ;
    }


Why is the inner loop running to j=9?
I assume the inner loop takes the first random number from the different seeds.
If the outer loop goes to its second iteration, the inner loop takes the second random number from the different seeds.
The random number engine is seeded just once in the program, using a seed sequence of constant values. (Note the static storage duration).

In main, we just print out the first 500 values that are generated; the two loops are there only to make it convenient to print out 50 lines with 10 numbers per line.
Ok, but how does the generator work with a seed sequence? I assumed it would 'work through the different seeds' to create different sequences.
Is it a completely different appraoch than working with a single seed?
Depends on how it was implemented by whoever wrote the code for the particular library you've got. Here's one implementation;https://code.woboq.org/gcc/libstdc++-v3/include/bits/random.tcc.html#352
Last edited on
So, it's not trivial. But how is using a constant worse than using the actual system time like I did before? Both are single seeds. Or are both just not as safe as having a seed sequence?
I don't see the answer in this link.
It basically says seed_seq is rubbish and raises more questions for me than it answers.

Does that mean my random number generator needs 624 different seeds? You (edit: not you but JLBorges, sorry) also did not use that many.
Also, is random device the same as my usage of system.time?
Where is the difference now between using a constant int and a random int generated from some random device or the systems time?
Is it because of this? That with using system-randomness, I might be luckier than using a single constant?
JLBorges wrote:
A single constant value may not always guarantee high quality randomness (the choice of the single constant value maybe an unfortunate one


Last edited on
Perhaps this one will be more to your liking:

https://stackoverflow.com/questions/47562404/deciding-between-random-device-and-seed-seq-to-generate-seeds-for-multiple-rando

If you use a constant as your seed, you'll get the same sequence every time. That's not exactly random.
Last edited on
Ok, so to explain the code:
1
2
3
4
5
std::vector<uint32_t> random_data(624);
std::random_device source;
std::generate(random_data.begin(), random_data.end(), std::ref(source));
std::seed_seq seeds(random_data.begin(), random_data.end());
std::mt19937 engine(seeds);


source is an object that gets some random value from the system.
generate(random_data.begin(), random_data.end(), std::ref(source)); fills my vector with source() in each entry.
std::seed_seq seeds(random_data.begin(), random_data.end()); writes all the 624 source() commands into the seed sequence.

So this is the optimal way to do it?

If you use a constant as your seed, you'll get the same sequence every time. That's not exactly random.

Yeah, but what if I want the same sequence each time I run the program, just to be able to reproduce my simulation results? Then it would be best to put 624 constants in the vector?
> what if I want the same sequence each time I run the program,
> just to be able to reproduce my simulation results?

Create a seed sequence containing constant values and use it to seed the random number engine.


> Then it would be best to put 624 constants in the vector?

To guard against one poorly chosen initial seed, a seed sequence of a fairly small size (say, a dozen or so) would be adequate. The initialisation of the state of the random number engine goes through a well defined warm up sequence based on the seed sequence. The algorithm used for the warm up sequence is given here: https://en.cppreference.com/w/cpp/numeric/random/seed_seq/generate

For example, this is what we would get if we dump the state of std::mt19937 after it is initialised with a small seed sequence of eight values. Note that even a small change in one of the values in the seed sequence produces a state that is quite different.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <random>

int main() {

    std::seed_seq sseq[] { { 100, 78639, 193, 55555, 3, 2348089, 6474367, 264441578 },
                           { 100, 78639, 193, 55555, 4, 2348089, 6474367, 264441578 }, 
                           { 100, 78639, 193, 55555, 5, 2348089, 6474367, 264441578 },
                           { 100, 78639, 193, 55555, 6, 2348089, 6474367, 264441578 },
                           { 100, 78639, 193, 55555, 7, 2348089, 6474367, 264441578 } } ;
                           
    for( auto& s : sseq ) std::cout << std::mt19937(s) << '\n' ;
}

http://coliru.stacked-crooked.com/a/03b3deafaa3be43f

Ok, so I get good randomness by using only 8 numbers in the seed sequence.
In one simulation, I will call upon 5 billion random numbers, this number is way too small to get repitition, right?

I will adopt your code and write it like this for example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <random>


using namespace std;

function_name(){
    
    int N=1000;
    int M=5 000 000 000;
    //some commands

    // seed sequence of constant values: this will generate
    // the same sequence of pseudo random numbers each time the program is run
    static seed_seq seed_sequence { 100, 78639, 193, 55555, 3, 2348089, 6474367, 264441578 };
    static mt19937 gen (seed_sequence); //initialize random-number-generator with seed_sequence
    uniform_int_distribution<int> random_index(0,N-1); //distribution of all int in [a,N-1]
    uniform_real_distribution<double> random_double(-1, 1); //uniform distribution of real numbers in [-1,1]
    uniform_real_distribution<double> random_double2(0, 1);

     double z;

    //some commands
    for(size_t i=1; i<M; i++){
           //some commands
            z=random_double(gen);
           //some commands
    }
}


Last edited on
I would expect the period to be of order 10^6000. If you had started grabbing a million random numbers a second at the birth of the universe, by today you would have consumed only a tiny tiny fraction of one period of a 19937 mersenne twister.

A well made one, that is. I'm sure there are bad implementations out there that don't do a very good job.

"Way too small to get repitition" doesn't even begin to cover it :)

You should, of course, expect repeated random numbers; just not to loop right around the sequence.
Last edited on
The algorithm to be used by std::mt19937 is completely specified by the standard; every conforming implementation would generate the same identical sequence of pseudo random numbers for an engine seeded in the same way.

The 19937 in the name of the engine comes from the length of its cycle: 219937 - 1

Note that the standard does not specify the algorithm for to be used for the distributions.
Thank you guys, you have been a great help :)!
Topic archived. No new replies allowed.
Pages: 123