0
votes

I have a std::vector<double> x, who's size I do not know at compile time. Assuming the size of the vector is N, I want to assign N uniformly distributed random values to it. I currently do this within a loop

std::default_random_engine generator;
std::uniform_real_distribution<double> distribution_pos(0.0,1.0);
for (auto it = x.begin(); it != x.end(); it++)
{
  *it = distribution_pos(generator);
}

This doesn't seem very elegant to me, so I was wondering if there was a smarter way to do this?

4
You can use range iteration: for (auto &v:x) v=distribution_pos(generator); - Sam Varshavchik
If you want to go more functional - and especially if you're in modern C++ with lambdas (for syntax ease) you can use std::generate. - davidbak
@davidbak since they're using the <random> library, they must have at least C++11, which means lambdas. - Brian Bi
OK @Brian though of course std::generate will work with any generating function, not just the OP's specific example or <random>, in case anyone's interested ... - davidbak

4 Answers

3
votes

I would use std::generate:

std::vector<double> x(10);

std::default_random_engine gen{std::random_device{}()};
std::uniform_real_distribution<double> dist(0.0, 1.0);

std::generate(std::begin(x), std::end(x), [&]{ return dist(gen); });

Note:

You need to seed your random number generator otherwise you'll get the same sequence of numbers each time.

I don't recommend std::default_random_engine because the Standard does not guarantee quality or reproducibility across implementations or compiler versions.

3
votes

You could use std::generate like the following:

// First create an instance of an engine.
random_device rnd_device;

// Specify the engine and distribution.
mt19937 mersenne_engine {rnd_device()};  // Generates random doubles
std::uniform_real_distribution<double> dist (0, 1.0);

auto gen = [&dist, &mersenne_engine](){
               return dist(mersenne_engine);
           };

std::vector<double> x(N);
std::generate(begin(x), end(x), gen);

See demo

3
votes

You can make use of std::generate or std::generate_n as:

#include <algorithm>

std::generate(std::begin(x), std::end(x), [&] {
    return distribution_pos(generator);
});

std::generate_n(std::begin(x), N, [&] {
    return distribution_pos(generator);
});
0
votes

If you do not want to reserve memory in the vector beforehand then this will work.

#include <vector>
#include <random>
#include <algorithm>
#include <iterator>

int main() {
  std::vector<double> x;
  const int n = 10;

  std::default_random_engine gen(std::random_device{}());
  std::uniform_real_distribution<double> dist(0.0, 1.0);
  std::generate_n(std::back_inserter(x), n, [&]{ return dist(gen); });
}