C++ 向量问题

Posted

技术标签:

【中文标题】C++ 向量问题【英文标题】:C++ vectors question 【发布时间】:2010-07-15 18:41:52 【问题描述】:

有谁知道如何加速boost::numeric::ublas::vector

我正在使用typedef ublas::vector<float, ublas::bounded_array<float, 3> > MYVECTOR3 并将其速度与D3DXVECTOR3 在普通操作中进行比较。

测试如下所示:

#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")

static const size_t kRuns = static_cast<size_t>(10e6);

TEST(Performance, CStyleVectors) 

   D3DXVECTOR3 a(1.0f, 2.0f, 3.0f);
   D3DXVECTOR3 b(2.0f, 3.0f, 1.0f);
   D3DXVECTOR3 c(6.0f, 4.0f, 5.0f);

   for (size_t i = 0; i < kRuns; ++i) 
      c = c + (a + b) * 0.5f;
   


#include <boost/numeric/ublas/vector.hpp>

TEST(Performance, CppStyleVectors) 

   typedef boost::numeric::ublas::vector<float, 
      boost::numeric::ublas::bounded_array<float, 3> > MYVECTOR3;

   MYVECTOR3 a(3), b(3), c(3);
   a[0] = 1.0f, a[1] = 2.0f, a[2] = 3.0f;
   b[0] = 2.0f, b[1] = 3.0f, b[2] = 1.0f;
   c[0] = 6.0f, c[1] = 4.0f, c[2] = 5.0f;

   for (size_t i = 0; i < kRuns; ++i) 
      noalias(c) = c + (a + b) * 0.5f;
   

结果如下:

[----------] 2 tests from Performance
[ RUN      ] Performance.CStyleVectors
[       OK ] Performance.CStyleVectors (484 ms)
[ RUN      ] Performance.CppStyleVectors
[       OK ] Performance.CppStyleVectors (9406 ms)
[----------] 2 tests from Performance (9890 ms total)

如您所见,即使使用自定义的基于堆栈的分配器,纯 C 样式的向量也比来自 boost::numeric::ublas 的向量快约 20 倍。有人对我如何加快速度有任何想法吗?

也许通过编写自定义包装器或类似的东西?

谢谢

【问题讨论】:

请确认您正在使用发布库进行构建,而不是调试,并且您已打开编译器优化。什么是 noalias()? @ravenspoint Release build,/O2 /Ox 给出相同的结果)noalias 代表 boost::numeric::ublas 内部优化,当已知结果不'不共享相同的存储空间。 "有人知道如何加快速度吗?"获取分析器,分析应用程序,找到在访问向量时占用大部分处理时间的例程/行,然后思考。 AQTime 提供了一个不错的分析器(价格昂贵,但您应该能够为您的任务使用试用版)。 【参考方案1】:

Boost uBLAS(以及一般的 BLAS)支持向量和矩阵代数,其中维数在运行时确定。它适用于解决某些数值问题(如使用 FEM 或类似方法进行模拟、优化问题、逼近)。对于这些问题,它相对较快,但在性能上无法与专业的 3d 矢量类库竞争。

使用其他库。如果 D3DXVECTOR3 不够,请查看例如CGAL。

【讨论】:

【参考方案2】:

我认为如果您从 ublas::vector 类继承到具有手动编码的复制构造函数等的专用 3D 矢量类中,您可能会获得更好的性能。类似这段代码的东西(使用双精度)

/**

  A 3D vector

*/
class c3d : public boost::numeric::ublas::bounded_vector<double, 3>

    typedef boost::numeric::ublas::bounded_vector<double, 3> Base_vector;
public:

    //  ctors
    c3d () : Base_vector()
    
    c3d (double x, double y, double z) : Base_vector()
     Base_vector::iterator p = begin(); *p++=x; *p++=y; *p++=z;
    template <class R> c3d (const boost::numeric::ublas::vector_expression<R>& r) : Base_vector(r)
    
    template <class R> void operator=(const boost::numeric::ublas::vector_expression<R>& r)
     Base_vector::operator=(r); 
    template <class R> void operator=(const Base_vector& r)
     Base_vector::operator=(r); 

【讨论】:

"应该注意的是,这只会改变 uBLAS 用于向量 3 的存储。uBLAS 仍将使用所有相同的算法(假设可变大小)来操作向量 3。实际上,这似乎对速度没有负面影响。上面的运行速度与不使用 uBLAS 的手工制作的 vector3 一样快。唯一的负面影响是 vector3 总是存储一个“大小”成员,在这种情况下是多余的。“crystalclearsoftware.com/cgi-bin/boost_wiki/… 【参考方案3】:

我又看了一遍,意识到加快速度的最好方法是重写

   for (size_t i = 0; i < kRuns; ++i) 
      c = c + (a + b) * 0.5f;
   

作为

c = c + kRuns * ( a + b ) * 0.5f

这根本不需要时间。

当我使用简单的数组对其进行手动编码时,我的优化编译器显然会这样做,因为“循环”在很短的时间内运行了一百万次。

   float a[3], b[3], c[3];
   a[0] = 1.0f, a[1] = 2.0f, a[2] = 3.0f;
   b[0] = 2.0f, b[1] = 3.0f, b[2] = 1.0f;
   c[0] = 6.0f, c[1] = 4.0f, c[2] = 5.0f;

   for (size_t i = 0; i < KRUNS; ++i) 
       c[0] = c[0] + ( a[0] + b[0] ) * 0.5;
       c[1] = c[1] + ( a[1] + b[1] ) * 0.5;
       c[2] = c[2] + ( a[2] + b[2] ) * 0.5;
   

不是你的吗?

使用 ublas 库会阻止优化器执行其操作。运行这段代码

   #define KRUNS 1000000
   typedef boost::numeric::ublas::vector<float, 
      boost::numeric::ublas::bounded_array<float, 3> > MYVECTOR3;

   MYVECTOR3 a(3), b(3), c(3);
   a[0] = 1.0f, a[1] = 2.0f, a[2] = 3.0f;
   b[0] = 2.0f, b[1] = 3.0f, b[2] = 1.0f;
   c[0] = 6.0f, c[1] = 4.0f, c[2] = 5.0f;

   for (size_t i = 0; i < KRUNS; ++i) 
      noalias(c) = c + (a + b) * 0.5f;
   

需要 63 毫秒。我无法想象为什么它需要 9400 毫秒,不管你的机器有多慢。我又问了:你确定你已经开启优化并链接到发布库吗?

【讨论】:

以上是关于C++ 向量问题的主要内容,如果未能解决你的问题,请参考以下文章

C++中向量的向量顺序

向量c++的向量大小

C++ 按列对二维向量进行排序

(向量对)与(向量对)C++的速度[关闭]

C++ 将元素从一个向量移动到另一个向量

为啥我不能将整数向量推入 C++ 中的二维整数向量?