1

I would like to maintain the random number generator state as a member variable, so every object generated from this class will have its one. It is necessary, that everytime an object is generated the seed gets changed too.

I did the following thing, namely changing the seed through the object's constructer. The seeding I did with time(NULL) but this is not accurate enough, since the the objects get created way faster than within a second, haha.

#include <iostream>
#include <cmath>
#include<random>
#include<chrono>
#include <ctime>


class Test{
public:
    Test();
    std::mt19937 rng;
    double randomNumber(double min, double max);

};
Test::Test(){
    rng.seed(time(NULL));
}

double Test::randomNumber(double min, double max){
    std::uniform_real_distribution<double> uniformDistribution(min, max);
    return uniformDistribution(rng);
}

int main(){
    Test a;
    Sleep(1000*1);
    Test b;

    for (int i = 0; i < 10; i++){
        std::cout << "Random number a: " << a.randomNumber(0, 10) << "\tRandom number b: " << b.randomNumber(0, 10) << std::endl;

    }

}

I am struggling with the method described in [Seeding rand() for a C++ class by bames53.

Including this piece

std::mt19937 eng{ std::chrono::high_resolution_clock::now().time_since_epoch().count() };

into the class declarations yields the following error:

Error: no instance of constructor "std::merseene_twister_engine<_Ty,_Wx, many more things> argument types are (std::chrono::system_clock::rep)

Now I do not exactly know where the error comes from and how to achieve my problem. Please keep in mind I am more or less an c++ newby. Thank you!

Community
  • 1
  • 1
nerdizzle
  • 424
  • 4
  • 17
  • " It is necessary, that everytime an object is generated the seed gets changed too." Can you be very specific as to why? (This sounds a whole lot like a XY problem to me). Also are the `max` and `min` values always the same or will the change from call to call? – shuttle87 Nov 10 '14 at 20:23
  • To the XY problem part, I just wanted to mention that I tried other attempts to solve my problem, like the description in the link I posted. – nerdizzle Nov 10 '14 at 20:31
  • Try casting the result of `count()` using `static_cast`, you may have a narrowing conversion in your code, although the error message doesn't seem to indicate that. Another way to seed the RNG would be using `random_device`. `std::mt19937 eng{ std::random_device{}() }` – Praetorian Nov 10 '14 at 20:35
  • I do have particles on a grid and they should move independently from each other, therefore I would like to have different random numbers everytime a object was created. There are many functions, depending on "random steps" and I do not want the particles to correlate. This is how far I can answer the why part. – nerdizzle Nov 10 '14 at 20:38
  • the `min` `max` will change in different calls. – nerdizzle Nov 10 '14 at 20:50
  • I think @shuttle87 has a good answer. It might also be worth mentioning `std::seed_seq` **[REFERENCE](http://en.cppreference.com/w/cpp/numeric/random/seed_seq)** – Galik Nov 10 '14 at 21:14
  • I've updated the answer you reference to improve seeding by not using the current time. – bames53 Nov 06 '20 at 07:04

1 Answers1

1

Given your description you could initialize the RNG once then pass it as a reference to the Test class:

class Test{
public:
    Test(std::mt19937& rng): m_rng(rng){
    }

    std::mt19937& m_rng;
    double randomNumber(double min, double max){
        std::uniform_real_distribution<double> uniformDistribution(min, max);
        return uniformDistribution(m_rng);
    }

};

std::mt19937 rng{std::chrono::high_resolution_clock::now().time_since_epoch().count()};
Test a(rng);

Because this particular RNG has a very long period you can instantiate it once then draw values from it across all your classes that need the random number generation.

Sample usage:

std::mt19937 rng{std::chrono::high_resolution_clock::now().time_since_epoch().count()};
Test a(rng);
Test b(rng);
for(int i=0; i<10; ++i){
    std::cout<< "a: " << a.randomNumber(0.0,1.0) << "b: " << b.randomNumber(5.0,6.0) << std::endl;
}

Here's this code in action: http://ideone.com/Lzyp22

shuttle87
  • 15,466
  • 11
  • 77
  • 106
  • Thank you, just what the doctor ordered! - Altough I get this `conversion from 'std::chrono::system_clock::rep' to 'unsigned int' requires a narrowing conversion` error. Praetorian mentioned this before, but I still dont know where to cast. I am using c++11 with VS 13. – nerdizzle Nov 10 '14 at 21:11
  • Interesting, I didn't get that same error when I compiled. Perhaps just do an explicit `static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count())` to tell the compiler that you don't necessarily mind if you lose some bits. (Generally speaking though you don't want to do narrowing conversions, so don't get in the habit of ignoring these errors :) ) – shuttle87 Nov 10 '14 at 21:19
  • Since I'm new in c++, I do have a conventional question. If one is in need of a RNG like this one, does one implement it as a class and then instantiate it in the other classes, or are there other methods? – nerdizzle Nov 10 '14 at 23:00
  • @nerdizzle c++ gives you a few options for doing this. At the most basic level you need to initialize the rng and provide it a seed before you can then start pulling numbers out from the rng, encapsulating this might be good. You could just do this with global state but that's generally speaking a code smell. So if you were to encapsulate it there's 2 ways that make a bit of sense, you can create a `class`/`struct` that wraps the functionality and exposes a method to pull out numbers from the rng. Or alternatively you could make a function that keeps some state via a `static` variable. – shuttle87 Nov 10 '14 at 23:31
  • Ok. I'm just used to think in encapsulation, but what I've seen so far in c++ this isn't always the best thing to do. I'm somehow confused how to implement RNGs and about the only seed once paradigm. So if I've a main() funtion, where I just do some calculations with the objects from the class Test and I do need a RNG for my class Test, where some things need to be random. Im trying cright now, but without great success :D. Generating the random numbers in main and give them to the objects is not what I intend to do. If you don't mind, could you post a code snippet? thank you! – nerdizzle Nov 11 '14 at 00:02
  • @nerdizzle, encapsulation is just good software engineering, you definitely want to do this in all languages and c++ is no different. I suspect that you might be confusing classes with encapsulation. The thing about random numbers is that conceptually you would only need a single source of entropy to generate all the random numbers you require. It's not as though you need 2 random number generators to generate 2 streams of random numbers. You *could* do that but the downside is that generating the extra random number generator isn't going to be free... – shuttle87 Nov 11 '14 at 15:09
  • ... at the very least you are adding some complexity to the code by doing it that way. When you are using pseudo random number generators you run into additional issues like the one in your question and issues to do with performance. These generators are relatively cheap to pull elements out of compared to constructing them. So cutting back on any unnecessary construction/destruction of the RNG itself is a win. Also I did post some code indicating the usage of this in the ideone link, I'll edit and place it in the answer. – shuttle87 Nov 11 '14 at 15:15