Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reference random generator?

I am trying to generate randoms within a range. I have multiple objects in multiple threads that would be calling this function, the function is in a singleton class so there is only one object that is called. But I noticed that my random numbers are closer to the middle of the range and by consequence, to each other for the first 200 calls, then they start to slowly disperse over the given range.

  1. Is there a harm in re-instantiating and re-seeding every time the function called? i did read this answer but didn't fully understand it.
  2. I tried to keep std::uniform_real_distribution<double> dis as a class variable but i kept getting errors that uniform_real_distribution is not a member of std:: why is that ?
  3. I tried to keep std::shared_ptr< std::uniform_real_distribution<double> > _uniform_distribution as a class variable, and still got errors.
  4. What is the correct way to reference a random generator?
  5. What is the right solution for this problem?

double getRandom(Object* foo){  
 std::random_device rnd;
 std::mt19937 gen(rnd());
 std::uniform_real_distribution<double> dis(0, foo->limit);
 double random = dis(gen);
 return random;
}
like image 280
InsaneBot Avatar asked Jan 09 '23 17:01

InsaneBot


2 Answers

You should seed a random number generator only once. Other than that, your getRandom function is correct. As for how to use all this in a class context, here's how you could do it:

#include <random>

class RNG
{
public:
    RNG::RNG() : gen(std::random_device()()) {} // Seeds the mt19937.

    double getRandom(Object* foo){  
        std::uniform_real_distribution<double> dis(0, foo->limit);
        double random = dis(gen);
        return random;
    }

private:
    std::mt19937 gen;
};

So at the the start of the program, you instantiate one RNG, and the mt19937 will be seeded once. Then you just call getRandom on that same RNG whenever you need a random number.

like image 199
emlai Avatar answered Jan 13 '23 23:01

emlai


If you want to make your distribution a member variable then you have to create new parameters on each invocation:

#include <random>
#include <iostream>

class Object
{
public:
    double limit = 100.0;
};

class MyRandomGen
{
    // typedef this for readability
    typedef typename std::uniform_real_distribution<double>::param_type param_type;

    std::mt19937 gen;
    std::uniform_real_distribution<double> dis;

public:
    MyRandomGen(): gen(std::random_device()()) {} // seed only once

    double getRandom(Object* foo)
    {
        param_type range {0, foo->limit}; // new distribution parameters
        return dis(gen, range);
    }
};


int main()
{
    Object o;
    MyRandomGen gen;

    for(auto i = 0; i < 10; ++i)
        std::cout << gen.getRandom(&o) << '\n';
}

Output:

48.4072
11.9905
39.0123
49.2113
69.3635
0.369986
19.9654
42.4251
92.9024
29.7522
like image 45
Galik Avatar answered Jan 14 '23 01:01

Galik