将C ++向量初始化为随机值...快速

时间:2010-05-18 20:00:29

标签: c++ optimization vector random

嘿,我喜欢尽可能快地制作它,因为它在我正在编写的程序中被称为A LOT,所以有没有更快的方法将C ++向量初始化为随机值而不是:

double range;//set to the range of a particular function i want to evaluate.
std::vector<double> x(30, 0.0);
for (int i=0;i<x.size();i++) {
    x.at(i) = (rand()/(double)RAND_MAX)*range;
}

编辑:修正了x的初始化程序。

8 个答案:

答案 0 :(得分:17)

现在,这应该真的快,因为循环不会执行。

就个人而言,我可能会使用这样的东西:

struct gen_rand { 
    double range;
public:
    gen_rand(double r=1.0) : range(r) {}
    double operator()() { 
        return (rand()/(double)RAND_MAX) * range;
    }
};

std::vector<double> x(num_items);
std::generate_n(x.begin(), num_items, gen_rand());

编辑:这纯粹是一种微观优化,根本没有任何区别,但您可以考虑重新安排计算,以获得类似的结果:

struct gen_rand { 
    double factor;
public:
    gen_rand(double r=1.0) : factor(range/RAND_MAX) {}
    double operator()() { 
        return rand() * factor;
    }
};

当然,编译器很可能已经做到这一点(或类似的东西),但无论如何都不会受到影响(尽管它真的只能帮助优化关闭)。

Edit2:“sbi”(通常就是这种情况)是对的:你最初可以通过保留空间获得一点,然后使用插入迭代器将数据放到位:

std::vector<double> x;
x.reserve(num_items);
std::generate_n(std::back_inserter(x), num_items, gen_rand());

和以前一样,我们正在进行这样的微观优化,我完全不确定我是否真的希望看到差异。特别是,由于这一切都是通过模板完成的,因此大多数(如果不是全部)代码都是内联生成的。在这种情况下,优化器可能会注意到初始数据都被覆盖,并跳过初始化。

然而,最终,几乎唯一真正可能才能产生显着差异的部分就是摆脱.at(i)。其他可能,但是在启用优化的情况下,我真的不希望他们这样做。

答案 1 :(得分:11)

我一直在使用Jerry Coffin的仿函数方法,但随着C ++ 11的到来,我们有了很多很酷的新随机数功能。要使用随机float值填充数组,我们现在可以执行以下操作。 。 。

const size_t elements = 300;
std::vector<float> y(elements);    
std::uniform_real_distribution<float> distribution(0.0f, 2.0f); //Values between 0 and 2
std::mt19937 engine; // Mersenne twister MT19937
auto generator = std::bind(distribution, engine);
std::generate_n(y.begin(), elements, generator); 

有关更多引擎和分发的信息,请参阅Wikipedia的相关部分

答案 2 :(得分:5)

是的,而x.at(i)确实进行边界检查,x [i]不这样做。 此外,您的代码不正确,因为您未能提前指定x的大小。您需要使用std::vector<double> x(n),其中n是您要使用的元素数量;否则,你的循环永远不会执行。

或者,您可能想要创建一个自定义迭代器来生成随机值并使用迭代器填充它;因为std :: vector构造函数会初始化它的元素,所以如果你有一个生成随机值的自定义迭代器类,你可以消除对项目的传递。

在实施自己的iterator方面,这是我未经测试的代码:

 class random_iterator
 {
     public:
         typedef std::input_iterator_tag iterator_category;
         typedef double value_type;
         typedef int difference_type;
         typedef double* pointer;
         typedef double& reference;

         random_iterator() : _range(1.0), _count(0) {}
         random_iterator(double range, int count) : 
                                         _range(range), _count(count) {}
         random_iterator(const random_iterator& o) : 
                                         _range(o._range), _count(o._count) {}
         ~random_iterator(){}

         double operator*()const{ return ((rand()/(double)RAND_MAX) * _range); }
         int operator-(const random_iterator& o)const{ return o._count-_count; }
         random_iterator& operator++(){ _count--; return *this; }
         random_iterator operator++(int){ random_iterator cpy(*this); _count--; return cpy; }
         bool operator==(const random_iterator& o)const{ return _count==o._count; }
         bool operator!=(const random_iterator& o)const{ return _count!=o._count; }

     private:
         double _range;
         int _count;
 };

使用上面的代码,应该可以使用:

std::vector<double> x(random_iterator(range,number),random_iterator());

也就是说,给出的其他解决方案的生成代码更简单,坦率地说,我只是明确地填充向量而不诉诸任何像这样的花哨......但是考虑它是一种很酷的。

答案 3 :(得分:3)

#include <iostream>
#include <vector>
#include <algorithm>

struct functor {
   functor(double v):val(v) {}
   double operator()() const {
      return (rand()/(double)RAND_MAX)*val;
   }
private:
   double val;
};

int main(int argc, const char** argv) {
   const int size = 10;
   const double range = 3.0f;

   std::vector<double> dvec;
   std::generate_n(std::back_inserter(dvec), size, functor(range));

   // print all
   std::copy(dvec.begin(), dvec.end(), (std::ostream_iterator<double>(std::cout, "\n")));

   return 0;
}

опоздал:(

答案 4 :(得分:2)

您可以考虑使用伪随机数生成器将输出作为序列。由于大多数PRNG只提供一个序列,这比一遍又一遍简单地调用rand()要高效得多。

但是,我认为我真的需要了解你的情况。

  • 为什么这段代码执行这么多?您是否可以重新构建代码以避免频繁重新生成随机数据?
  • 你的载体有多大?
  • 您的随机数生成器需要“好”吗?高质量的发行版计算成本往往更高。
  • 如果你的向量很大,你是在重用它们的缓冲空间,还是把它丢弃并重新分配到其他地方? willy-nilly创建新的向量是破坏缓存的好方法。

答案 5 :(得分:1)

@Jerry Coffin的回答看起来非常好。但另外两个想法是:

  1. 内联 - 你的所有向量访问都会非常快,但如果对rand()的调用是脱节的,那么函数调用开销可能会占主导地位。如果是这种情况,您可能需要推出自己的pseudorandom number generator

  2. SIMD - 如果你打算推出自己的PRNG,你也可以让它一次计算2个双打(或4个浮点数)。这将减少int到float转换的次数以及乘法。我从来没有尝试过,但显然有一个Mersenne Twister的SIMD版本非常好。一个简单的linear congruential generator也可能已经足够好了(这可能就是rand()已经使用的了。)

答案 6 :(得分:1)

int main() {
  int size = 10;
  srand(time(NULL));
  std::vector<int> vec(size);
  std::generate(vec.begin(), vec.end(), rand);

  std::vector<int> vec_2(size);
  std::generate(vec_2.begin(), vec_2.end(), [](){ return rand() % 50;})
}

您需要包含矢量,算法,时间,cstdlib。

答案 7 :(得分:0)

我想到这些的方式是橡胶与道路的方法 换句话说,有一些必须发生的最小的事情,没有绕过它,例如:

  • rand()函数必须被调用N次。

  • rand()的结果必须转换为double,然后乘以某种东西。

  • 结果数字必须存储在数组的连续元素中。

该对象至少可以完成这些工作。

其他问题,例如是否使用std::vector和迭代器都可以,只要它们不添加任何额外的周期。 查看它们是否添加了大量额外周期的最简单方法是在汇编语言级别单步执行代码。