rand() generating same set of random numbers when called through functors (even after seeding with srand(time(NULL))

StackOverflow https://stackoverflow.com/questions/20923551

Вопрос

I have problem with generating random numbers and I've read through most posts on this topic on SO but none of the solutions seem to work. Please read it through before marking it as a duplicate

I have a functor to generate random numbers between 0.5 and -0.5:

struct randomize
{
    __host__  void operator()( double &x ) const {
        x=(double) (rand() % 1000000) / 1000000 - 0.5;
    }
};

which I'm calling through a for_each like so:

thrust::for_each(myVector.begin(),myVector.end(),randomize());

which in turn is called inside the constructor of a class (lets say myClass) which is called like:

myObjs=std::vector<myClass>(20,myClass(no_of_inputs));

The problem is that all myVectors in all myClass' objects are filled with the same set of values. These values change with each run but are the same across allmyVectors`

I know that rand() is a pseudorandom number generator, and numbers generated by it cannot be expected to be truly random.. But this is too much of a coincidence.

Just to clarify:

  • I'm calling srand(time(NULL)) only once in the entire program.
  • I'm using thrust::for_each and not std::for_each but that should not make much of a difference
  • I know that randomize functor is far from perfect but i'm moding and dividing by 1000000 in order to get a 6 digits after the decimal point. if you could point out a better way to do it, that would be great but please dont get carried away by it.
  • I cannot use c++11 (presently) or boost (at all)
  • I cannot use default constructor for myClass
  • A solution which does not require me to change the structure of the code too much would be more appreciated
Это было полезно?

Решение

myObjs=std::vector<myClass>(20,myClass(no_of_inputs));

Have you defined a copy constructor for myClass that randomizes the data? (Which however would defy the purpose of a copy constructor in my opinion)

If not, then you are copying the same myClass 20 times into myObj and the vector<myClass> will be constructed by calls to the default copy constructor for each element, which in turn will simply copy the data in myVector.

Другие советы

The problem is that all myVectors in all myClass' objects are filled with the same set of values.

That’s because std::vector<myClass>(20, myClass(no_of_inputs)) gets you 20 copies of one temporary object.

If you provide a default-ctor for myClass you can skip the second parameter to the vector-ctor.
You can also push_back the myClass-objects one after another.

Which brings us to suggestions:

I see your randomize::operator() is marked __host__, then there is no reason to use thrust::for_each in favor of std::for_each.

I cannot use c++11 (presently) or boost (at all)

But you can use the tr1-extensions, which also offer a <random>-header:

#include <tr1/random>

template <typename T>
struct twisterize {
    const T min;
    const T max;
    twisterize(const T & min, const T & max) : min(min), max(max) {}
    void operator()(T & x) {
        typedef std::tr1::mt19937 rng_t;
        typedef std::tr1::uniform_real<T> dist_t;

        static rng_t rng( ((std::tr1::random_device())) ());//most vexing parse, yikes
        static dist_t dist(min, max);// [min,max) for real distributions
        static std::tr1::variate_generator<rng_t, dist_t> bound_dist(rng, dist);//not necessary in c++11

        x = bound_dist();//using the c++11 way `dist(rng)` produces unexpected results with tr1
    }
};

Since the functor now has state, you better create a variable for it, and pass that to for_each:
twisterize<double> rand_functor(-0.5, 0.5);

If you really want random numbers generated on the gpu look here

Calling srand more than once in the ENTIRE code, will never make anything better [unless you really want to repeat another run with the same sequence of random numbers, of course].

The actual numbers you get will depend on the seed. Since time() only changes a little bit from one second to the next, and even if you wait several minutes, only the last few digits will have changed. You may find that using a different source of time (for example one that gives you milliseconds or smaller) and combining that with the result from time gives you a better random number. However, this will be slightly awkward if you need very portable code.

[There are of course lots of clever ways to get a "random seed" that doesn't involve time, but they tend to either be a bit more complex, non-portable and/or slow - for example you could send "todays date" to the search-page in google, and hash the returned HTML. That's almost certain to produce a different result every time you do it].

I'm calling srand(time(NULL)) only once.

No, you said you're calling it in the class constructor, so it'll be invoked every time an instance is created. Every time that happens, the pseudo-random sequence is reset (to the same sequence, since this is all running in under a second and thus the seed doesn't change), and this happens.

Invoke it only once in your entire program.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top