简体   繁体   English

通过函子调用时,rand()会生成相同的随机数集(即使在使用srand(time(NULL))进行播种之后)

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

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: 我有一个函子来生成0.5到-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: 我通过for_each像这样调用:

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: 依次在类的构造函数内部调用(让我说​​myClass),该类的调用方式如下:

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

The problem is that all myVector s in all myClass' objects are filled with the same set of values. These values change with each run but are the same across all 问题是,所有myVector S IN的所有myClass' objects are filled with the same set of values. These values change with each run but are the same across all myClass' objects are filled with the same set of values. These values change with each run but are the same across all myVectors` myClass' objects are filled with the same set of values. These values change with each run but are the same across all myVectors中myClass' objects are filled with the same set of values. These values change with each run but are the same across all

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. 我知道rand()是伪随机数生成器,并且不能期望它生成的数字是真正的随机数。但是,这太巧合了。

Just to clarify: 只是澄清一下:

  • I'm calling srand(time(NULL)) only once in the entire program. 我在整个程序中只调用srand(time(NULL))一次。
  • I'm using thrust::for_each and not std::for_each but that should not make much of a difference 我使用推力::: for_each而不是std :: for_each,但这应该没有太大区别
  • 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. 我知道随机函子远非完美,但我正在修改并除以1000000,以便在小数点后得到6位数字。 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) 我目前不能使用c ++ 11或完全不能使用boost
  • I cannot use default constructor for myClass 我无法为myClass使用默认构造函数
  • A solution which does not require me to change the structure of the code too much would be more appreciated 不需要我过多更改代码结构的解决方案将不胜感激

The problem is that all myVectors in all myClass' objects are filled with the same set of values. 问题是所有myClass对象中的所有myVector都填充有相同的一组值。

That's because std::vector<myClass>(20, myClass(no_of_inputs)) gets you 20 copies of one temporary object. 这是因为std::vector<myClass>(20, myClass(no_of_inputs))您提供20个临时对象的副本。

If you provide a default-ctor for myClass you can skip the second parameter to the vector -ctor. 如果为myClass提供了default-ctor,则可以将第二个参数跳过vector -ctor。
You can also push_back the myClass -objects one after another. 你也可以push_backmyClass -objects此起彼伏。

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 . 我看到您的randomize::operator()被标记为__host__ ,因此没有理由使用thrust::for_each来支持std::for_each

I cannot use c++11 (presently) or boost (at all) 我目前不能使用c ++ 11或完全不能使用boost

But you can use the tr1-extensions, which also offer a <random> -header: 但是您可以使用tr1扩展名,它还提供了<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 : 由于函子现在具有状态,因此最好为它创建一个变量,并将其传递给for_each
twisterize<double> rand_functor(-0.5, 0.5);

If you really want random numbers generated on the gpu look here 如果您真的想在GPU上生成随机数,请查看此处

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

Have you defined a copy constructor for myClass that randomizes the data? 您是否为myClass定义了一个将数据随机化的副本构造函数? (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 . 如果不是,那么您将相同的myClass复制20次到myObj并且将通过调用每个元素的默认复制构造函数来构造vector<myClass> ,后者依次将简单地复制myVector的数据。

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]. 在ENTIRE代码中多次调用srand永远不会使任何事情变得更好[当然,除非您真的想用相同的随机数序列重复另一次运行]。

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. 由于time()从一秒钟到下一秒钟只有一点点变化,即使您等待了几分钟,也只有最后几位数字发生了变化。 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. 您可能会发现,使用不同的时间源(例如,给您毫秒或更少的时间),并将其与time结果相结合,可以为您提供更好的随机数。 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. [当然,有很多聪明的方法可以获取不涉及时间的“随机种子”,但是它们往往更加复杂,不可移植和/或缓慢-例如,您可以发送“今天的日期”添加到google中的搜索页面,然后对返回的HTML进行哈希处理。 That's almost certain to produce a different result every time you do it]. 几乎可以确定每次执行都会产生不同的结果]。

I'm calling srand(time(NULL)) only once. 我只叫srand(time(NULL))一次。

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 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM