Physicist
Physicist

Reputation: 3048

problems in seeding random number in c++

I used the following code (copied somewhere from the web) and managed to generate some an array of random numbers.

std::default_random_engine generator;
std::uniform_real_distribution<double> distribution(0,1);

int N;
std::cout<< "Please enter the number of disks to be generated: ";
std::cin>> N;

// generates N pairs of coordinates
double** R;
R = new double* [N];
for (int i=0; i<N; i++) {
    R[i] = new double [3];
    for (int j=0; j<3; j++) {
        R[i][j] = distribution(generator);
    }
}

The problem is that the output is always the same, so I think it is not seeded properly. Then I found the following code from the web, but it didn't work on my computer (I always get runtime error)

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(1, 2);
for (int n = 0; n < 10; ++n) {
    std::cout << dis(gen) << ' ';
}
std::cout << '\n';

What's wrong with the above code? How to seed my code so I can get different outputs everytime? Besides, for the first code, is the linear congruential algorithm being used? How to use 'better' algorithm like the Mersenne Twister (mt19937) ?

thanks

Upvotes: 3

Views: 2408

Answers (3)

emsr
emsr

Reputation: 16353

You need to provide a random seed for the random number generators. (BTW, the library default of producing the same numbers in the generators is so test results can be predictable). I use the system time as others have shown.

One way I haven't seen mentioned is std::seed_seq which addresses this very issue. Feed is a few integers and it produces a nice sequence of seeds:

#include <random>
#include <vector>
#include <array>
#include <iostream>
#include <iomanip>
#include <chrono>

unsigned long
system_now()
{
  std::chrono::system_clock::time_point now{std::chrono::system_clock::now()};
  std::chrono::system_clock::duration epoch{now.time_since_epoch()};
  return static_cast<unsigned long>(now.time_since_epoch().count());
}

int
main()
{
    // ...
    auto N = 500;

    std::vector<std::array<double, 3>> R(N);

    std::seed_seq seq{1, 2, 3, 4, 5};
    std::vector<std::uint32_t> seeds(1000);
    seq.generate(seeds.begin(), seeds.end());

    std::mt19937 generator(seeds[system_now() % seeds.size()]);
    std::uniform_real_distribution<double> distribution{0.0, 1.0};

    for (auto & V : R)
        for (auto & C : V)
            C = distribution(generator);

    for (const auto & V : R)
    {
        std::cout << '(';
        for (const auto & C : V)
            std::cout << ' ' << std::setw(10) << C;
        std::cout << " )\n";
    }
}

Warning! The seed sequence is also repeatable - with the same input it returns the same output! Also, with 1000 seeds you'll eventually set the same numbers again. Same seed, same generated numbers.

Upvotes: 0

ForEveR
ForEveR

Reputation: 55887

default_random_engine is implementation-defined. It's not specified which algo it will use.

Which runtime_error you get? It should work correct, but as workaround, you can seed mt19937 with current time as with srand.

std::mt19937 gen(static_cast<std::mt19937::result_type>(std::time(nullptr)));

Upvotes: 4

Elemental
Elemental

Reputation: 7521

You need to explicitly seed the random number generator in the constructor with something like this (this example uses the system clock to uniquely seed the generator):

  // obtain a seed from the timer
  unsigned seed = myclock::now().count();
  //construct the generator
  std::default_random_engine generator(seed);

Upvotes: 3

Related Questions