rand()在通过仿函数调用时生成相同的随机数集(即使在使用srand播种后(time(NULL))

时间:2014-01-04 16:30:05

标签: c++ random vector foreach thrust

我在生成随机数时遇到问题,我在SO上阅读了关于这个主题的大多数帖子,但没有一个解决方案似乎有效。 请在将其标记为重复之前仔细阅读

我有一个仿函数来生成介于0.5和-0.5之间的随机数:

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

我正在通过for_each呼叫,如此:

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

反过来在类的构造函数中调用(比如myClass),它被称为:

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

问题在于所有myVector myVectors中的所有myClass' objects are filled with the same set of values. These values change with each run but are the same across all

我知道rand()是一个伪随机数生成器,由它生成的数字不能说是真正随机的。但这太巧合了。

只是为了澄清:

  • 我在整个程序中只调用srand(time(NULL))一次。
  • 我正在使用thrust :: for_each而不是std :: for_each,但这不应该有太大的区别
  • 我知道随机化仿函数远非完美,但我正在修改并除以1000000以获得小数点后的6位数。如果你能指出一个更好的方法来做到这一点,那就太好了,但请不要被它带走。
  • 我不能使用c ++ 11(现在)或者提升(根本不是)
  • 我不能使用myClass的默认构造函数
  • 不需要我过多地改变代码结构的解决方案将会更受欢迎

4 个答案:

答案 0 :(得分:2)

  

问题是所有myClass对象中的所有myVectors都填充了相同的值集。

那是因为std::vector<myClass>(20, myClass(no_of_inputs))可以获得一个临时对象的20个副本。

如果您为myClass提供默认值,则可以跳过vector - ctor的第二个参数。 您也可以push_back myClass - 一个接一个的对象。

这给我们提出了建议:

我看到您的randomize::operator()已标记为__host__,因此没有理由使用thrust::for_each支持std::for_each

  

我不能使用c ++ 11(现在)或者提升(根本不是)

但您可以使用tr1-extensions,它还提供<random> - 标题:

#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
    }
};

由于仿函数现在具有状态,因此最好为其创建变量,并将其传递给for_each
twisterize<double> rand_functor(-0.5, 0.5);

如果你真的想要在gpu look here

上生成随机数

答案 1 :(得分:1)

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

您是否为myClass定义了一个随机化数据的副本构造函数? (但在我看来,这会违反复制构造函数的目的)

如果没有,那么您将相同的myClass 20次复制到myObj中,vector<myClass>将通过调用每个元素的默认复制构造函数来构建,而myVector将依次为只需复制{{1}}中的数据。

答案 2 :(得分:0)

在ENTIRE代码中不止一次调用srand,永远不会做得更好[除非你真的想用相同的随机数序列重复另一次运行,当然]。

您获得的实际数字取决于种子。由于time()仅从一秒钟到下一秒钟稍有变化,即使您等待几分钟,也只会改变最后几位数字。您可能会发现使用不同的时间源(例如,给出毫秒或更短的时间)并将其与time的结果相结合可以获得更好的随机数。但是,如果您需要非常便携的代码,这将有点尴尬。

[当然有许多聪明的方法可以获得一个不涉及时间的“随机种子”,但它们往往更复杂,不便携和/或慢 - 例如你可以发送“今天日期”到谷歌的搜索页面,并对返回的HTML进行哈希处理。几乎可以肯定每次都会产生不同的结果]。

答案 3 :(得分:-2)

  

我只调用一次srand(time(NULL))。

不,你说你在类构造函数中调用它,所以每次创建实例时都会调用 。每次发生时,伪随机序列都会被重置(到相同的序列,因为这一切都在一秒钟内运行,因此种子不会改变),并且会发生这种情况。

在整个程序中只调用一次