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++ 向量问题的主要内容,如果未能解决你的问题,请参考以下文章