3

I am running analyses on very large graphs with random weights. I know that using the rand() function is poor, so I have been using this function based on what I have read to be proper random number generation:

double randomZeroToOne()
{
    random_device rd;
    mt19937 mt(rd());
    uniform_real_distribution<double> dist(0.0, 1.0);
    double randomRealBetweenZeroAndOne = dist(mt);
    return randomRealBetweenZeroAndOne;
}

Everytime I want to put a weight in my graph, I call this function and insert it into my adjacency matrix. However, I am worried that perhaps I am using a slow method to generate these numbers. This has worked fine for small graphs, but my larger graphs are very slow (likely something else is slowing it down, but I just wanted to double check and learn the proper way). What is the best way to preserve the quality of the numbers but to generate them as quickly as possible?

Additionally, if you know a way to initialize a vector of a known size with fast, good, uniformly distributed random numbers, that would be even better (although I am still curious about the answer to my main question).

EDIT:

This is my new proposed solution:

#include <iostream>
#include <random>
#include<vector>
#include<iomanip>
#include<cmath>
using namespace std;

random_device rd;
mt19937 mt(rd());
uniform_real_distribution<double> dist(0.0, 1.0);

int main()
{
    double randomRealBetweenZeroAndOne = dist(mt);
    double anotherRandomRealBetweenZeroAndOne = dist(mt);
    double anothernother = dist(mt);
    vector<double> randoman(10,dist(mt));
    cout << randomRealBetweenZeroAndOne << endl;
    cout << anotherRandomRealBetweenZeroAndOne <<endl;
    cout << anothernother <<endl;
}

Please let me know if you see any issues with this, especially if this function will be called many times.

cchapin
  • 33
  • 4
  • Use only one engine. Multiple call to `random_device` is of course slow. – user202729 Apr 24 '18 at 05:01
  • Possible duplicate of [Why not just use random_device?](https://stackoverflow.com/questions/39288595/why-not-just-use-random-device/39288869) – user202729 Apr 24 '18 at 05:02
  • [What you want, but not this problem](https://stackoverflow.com/questions/35358501/what-is-performance-wise-the-best-way-to-generate-random-bools). – user202729 Apr 24 '18 at 05:03
  • So is the correct solution to make a class, such as is done in the boolean article? Or is there a simpler method that can be done in a function? – cchapin Apr 24 '18 at 05:16
  • I just put the first three lines of my function at the very top of my program (in the global namespace I think--not sure the proper terminology of that), and kept my function as the last two lines. Is this a fine implementation? – cchapin Apr 24 '18 at 05:27
  • Then it's good. Please show your actual code (but still MCVE) instead of this, it's very very different. – user202729 Apr 24 '18 at 05:28
  • [On TIO, generating 50'000'000 numbers that way takes a second. Is that fast enough?](https://tio.run/##Tc5NasMwEAXgvU4h6MISboLSUkpixVfoBQpGkRR3wCMZ/WRTevWqsr2oBdp882Z4ep4Po9alPIHTUzaWSvAxBauwJ/8WlDN@J/JhdfJhB@BROZh3olGlr57kCG6kTqGNs9KWxmQ6QraDg7EPqBYqYTqdz6/vFBMLhnHekezg7gMOtcw0GKit4JYTeCeNz7fJ9nRBJo7imZ6Oom4QcImiAsc4@Sa0vi1JY8ar6FapJ9kSgwog30QjxPq7tgW@BNvrehYT3xZq4ctF@5ykrFMpm0/XdOSnlF99n9QYy@Hj5Q8) // There is [codereview.se] for working code. – user202729 Apr 24 '18 at 05:52

1 Answers1

1

As you suggest in your proposed solution, you don't want to use std::random_device and create your random engine every time you need a random number. But I would avoid making them global variables. I suggest using static variables within a function. They are still only initialized once, so it will be just as quick, but they are then a bit more encapsulated:

double randomZeroToOne()
{
    static mt19937 mt(std::random_device{}());
    static uniform_real_distribution<double> dist(0.0, 1.0);
    return dist(mt);
}

(Beware that it is not safe to call this function from multiple threads at the same time. If that is a requirement change static here to thread_local.)

Chris Drew
  • 14,926
  • 3
  • 34
  • 54