Mohamed Dame
Mohamed Dame

Reputation: 35

c++ - How to use <random> to fill std::array

I am trying new ways to generate random numbers and fill them in an array. So far I have done.

template<size_t SIZE>
void fill_array(array<int, SIZE>& a)
{
    default_random_engine dre;
    uniform_int_distribution<int> uid1(0, 1000);

    for (int i = 0; i < a.size(); i++)
    {
        a[i] = uid1(dre);

    }

}

My main file is very simply and looks like this

    array<int, 10> a;

    Array3 a1;

    a1.fill_array(a);
    a1.print_array(a);

I thought I managed to get random numbers everytime I debug but I get the same numbers everytime. Weird enough sometimes I do get different numbers but then it's the same thing where I have to debug multiple times to get new numbers. What did I do wrong?

Upvotes: 1

Views: 6409

Answers (4)

Nate M
Nate M

Reputation: 104

May I suggest using std::vector instead of an array. If you use the std::rand function, you can seed it with time with srand(time(NULL));. Of course you will need to include time.h for this. You can fill the vector with generate(a.begin(), a.end(), rand); without using a loop. This will give you a new random number sequence every time.

Upvotes: -1

Richard Hodges
Richard Hodges

Reputation: 69854

something along these lines:

#include <random>
#include <array>
#include <algorithm>

template<class Engine, class Integer, size_t SIZE>
void fill_array(Engine& eng, std::array<Integer, SIZE>& a, Integer lower = 0, Integer upper = 1000)
{
    std::uniform_int_distribution<Integer> uid1(lower, upper);

    std::generate(a.begin(), a.end(), [&]
    {
        return uid1(eng);
    });
}

int main()
{
    std::random_device rnd;  // a source of machine-wide entropy
    std::default_random_engine eng(rnd()); // use it to initialise the psuedo-random engine

    std::array<int, 100> arr;
    fill_array(eng, arr);
}

Upvotes: 2

Bob__
Bob__

Reputation: 12749

Even if you use std::random_device there's no guarantee to obtain a different sequence every time:

std::random_device may be implemented in terms of an implementation-defined pseudo-random number engine if a non-deterministic source (e.g. a hardware device) is not available to the implementation. In this case each std::random_device object may generate the same number sequence.

That happened, for example, with older g++ implentation of stdlibc++ on Windows.

Moreover, due to performace issues, random_device is generally only used (once) to seed a pseudo random bit generator such as the Mersenne twister engine (std::mt19937).

Your fill function could be implemented like this:

#include <iostream>
#include <array>
#include <iterator>
#include <random>
#include <algorithm>

template< class Iter >
void fill_with_random_int_values( Iter start, Iter end, int min, int max)
{
    static std::random_device rd;    // you only need to initialize it once
    static std::mt19937 mte(rd());   // this is a relative big object to create

    std::uniform_int_distribution<int> dist(min, max);

    std::generate(start, end, [&] () { return dist(mte); });
}

int main()
{
    std::array<int, 10> a;

    fill_with_random_int_values(a.begin(), a.end(), 0, 1000);

    for ( int i : a ) std::cout << i << ' ';
    std::cout << '\n';
}

live demo HERE.

Upvotes: 5

Chase R Lewis
Chase R Lewis

Reputation: 2307

You aren't initializing the seed to a random value. So your random generator always starts from the same position.

Here's an example of how to initialize your seed to start from some place. Essentially you need some source that isn't always the same so your generator produces random results, time is the most common value used.

#include <iostream>
#include <chrono>
#include <random>

int main ()
{
  typedef std::chrono::high_resolution_clock clock;


  std::default_random_engine generator(clock::now().time_since_epoch().count());
  std::uniform_int_distribution<int> rand(0,1000);

  for(int i = 0;i < 10;i++)
 {
    std::cout << rand(generator) << std::endl;
 }

  return 0;
}

Upvotes: -2

Related Questions