如何改善std :: vector时间? 嗨,我正在制作一个多变量模糊k均值集群的软件。 它通过10个变量对大矩阵的50.000个观测结果起作用。 矩阵不需要长大o收缩或边界检查。 只调整所需的大小,加载项目,然后进行大量访问。
首次使用:
`std::vector< std::vector<double> > matrix(NumClusters, std::vector<double>(NumObs,0.0));`
获取元素:double A = matrix [i] [j];但是过程时间是20分钟。
然后做:
std::vector<double> U(NumClusters *NumObs,0.0);
要获取元素:double A = U [i * NumObs + j];而且时间更好。
现在想提出一个问题: 哪个访问速度会更快:
iterator + int
std::vector<double>::const_iterator Uit = U.begin();
double A= *(Uit+index)
指针[INT]
std::vector<double>::const_pointer Upt = U.data();
double A= Upt[index];
或普通索引访问[int]
双A = U [指数];
问候
答案 0 :(得分:2)
您可以尝试的一件事是切换行和列。如果你有一个10×50,000的矩阵并且你将它放在一行接一行,那么对行的操作将比列上的操作更有效,因为它们具有更好的局部性。您可能还需要考虑std::valarray
,因为该容器应优化对矢量数据的某些数学运算。
如前所述,就效率而言,使用指数与指针无关紧要。指数可能更具可读性。
你可能想要做的非常C ++的事情(它不应该对效率有任何影响,只是代码可读性)将矢量包装在一个容器中,使其行为类似于2D矩阵,但在下面使用连续的1D向量。看一下How can I use a std::valarray to store/manipulate a contiguous 2D array?的灵感。
答案 1 :(得分:0)
当您将2D矩阵存储为vector<vector<int>>
时,您必须取消引用两个指针才能访问一个alement(双重间接)。这就是为什么大多数库将矩阵存储为线性数组vector<int>
的原因。在这种情况下,只使用单个间接,而且所有数据都以更紧凑的布局存储在内存中。
现在关于最快的访问。理想情况下,您提到的所有三种访问形式都同样快速。但是,没有编译器是完美的,有些可能有内联深度调用的问题(至少MSVC似乎很少有这样的问题)。这就是为什么如果你想确保最大速度,你应该避免在你的内循环中使用任何C ++抽象。仅使用指针和索引,这确实是最快的方法。但请注意,与其他方法相比,很可能会有 no 加速(也许生成的程序集绝对相同)。
总之,这种方式对我来说是最快的:
auto ptr = matrix.data();
auto num = matrix.size();
for (size_t i = 0; i < num; i++)
ptr[i] = ...; //do whatever complex math you have
答案 2 :(得分:-1)
假设你正在做一个简单的嵌套循环
for (int i = 0; i < NumObjs; ++i)
{
for (j = 0; j < NumClusters; ++j)
{
a = matrix[j][i];
// do something
}
}
问题是,matrix[j][i]
扩展为matrix.operator[](j).operator[](i)
。简单的诀窍是避免调用次数。
要查找执行此操作的选项,有必要检查循环体中的代码(例如,由注释// do something
指示)。
如果循环中的顺序并不重要,可以进行简单的更改
for (int i = 0; i < NumClusters; ++i)
{
for (j = 0; j < NumObjs; ++j)
{
a = matrix[i][j]; // note swapping
// do something
}
}
此更改在循环中执行的运行次数相同,但它们的顺序不同。显然,如果循环的顺序很重要,那么这种转换是不可能的。但是,如果可能的话......
可以优化此表单。如果循环体没有调整矩阵或其中的一部分,那么每个调用matrix[i]
将扩展到相同的东西 - 到;
for (int i = 0; i < NumClusters; ++i)
{
std::vector<double> &row(matrix[i]);
for (j = 0; j < NumObjs; ++j)
{
a = row[j];
// do something
}
}
这通常会提供一些加速,因为matrix[i]
仅在外循环中调用/计算一次,而不是内循环的每次迭代。
请注意,使用迭代器也可以进行这种简单的转换。
除此之外,您需要检查您的算法 - 代码中具体发生的事情的逻辑,它执行事务的顺序等等。