在c ++中复制2D向量的一个维度的最快方法

时间:2014-05-19 15:41:42

标签: c++ vector multidimensional-array

我有一个2D矢量,它可用于复数。 仅举例:

vector<vector<double>> Complex;
vector<double> ComplexNumber;
ComplexNumber.push_back(5);  // real part
ComplexNumber.push_back(-4); // imag part
Complex.push_back(ComplexNumber); // Complex[i][0] - real part, [i][1] - imag

在我的代码的深度,我需要将我的复杂向量的一部分拉出到其他。 例如,从某个变量(1D向量)中的索引10到18实部复制,并在其他变量(1D向量)中从索引10复制到18个成像部分。 目前我正在以循环方式执行此操作:

for (int j=0; j<=Samples; j++)
{
  refRealSignal[j] = ReferenseComplexSignalsSampled[(i*SignalSampleIndex)+j][0] ;
  refImagSignal[j] = ReferenseComplexSignalsSampled[(i*SignalSampleIndex)+j][1] ;
}

此代码是分析器显示的整个程序的瓶颈。有没有办法改善它?

小更新:“示例”变量是int,从8到20,通常是8.变量i来自外部for循环。

大更新:所以,我推出了2D矢量并用complex类重写了所有内容。我也在“for”循环中重写了我的mul操作。我不知道为什么,但是从complex.imag复制需要花费更多时间(更多2),然后从complex.real部分复制。在所有这些代码性能从一个样本的~5ms增加到一个样本的~1.8ms之后。 (在我重写mul操作并重写整个周期后2.5毫秒,这是一个非常有用的建议,非常感谢)

2 个答案:

答案 0 :(得分:1)

如果Samples很大,您可以保存一些与i相关的乘法。所以改变这个:

for (int j=0; j<=Samples; j++)
{
  refRealSignal[j] = ReferenseComplexSignalsSampled[(i*SignalSampleIndex)+j][0] ;
  refImagSignal[j] = ReferenseComplexSignalsSampled[(i*SignalSampleIndex)+j][1] ;
}

到此:

int index;
for(i = ..) {                    // assuming your code has a for loop for i
  index = i*SignalSampleIndex;
  for (int j=0; j<=Samples; ++j) // change the ++ as pre-fix
  {
    refRealSignal[j] = ReferenseComplexSignalsSampled[index+j][0] ;
    refImagSignal[j] = ReferenseComplexSignalsSampled[index+j][1] ;
  }
}

这样你就可以做1次乘法,而不是2 * Samples,就像luk32注意到的那样。

另一种方法,如评论中所述,您可以使用类来表示复数。 STL为此提供了一个类:std::complex

然后你会得到一个类型为vector的{​​{1}},这会让你的数据更加健壮,这可能会提升std::complex localitycaching将会利用。

你可以这样做:

#include <iostream>     // std::cout
#include <complex>      // std::complex, std::real
#include <vector>   // std::vector

int main ()
{
  std::vector<std::complex<double> >complex;

  // if you know the amount of your numbers,
  // use a reserve(). Assuming you will insert
  // 100000 numbers, the code would be
  complex.reserve(100000);

  for(int i = 0; i < 100000; ++i)
      complex[i] = {0.1, 0.2};

  std::cout << "Real part of 1st element: " << std::real(complex[0]) << '\n';

  return 0;
}

[编辑]

通过使用优化标志,编译器可以执行乘法问题。当使用优化标志编译代码时,请确保对代码进行概要分析。

提示

通常情况下,如果一个部分减慢你的程序速度,有两种方法:(1)使该部分更快,或(2)找到一种方法更少地执行该部分。

(归功于Psyduck,又名Mooling duck)

在您的情况下,您可以尝试我上面提到的建议,以使您的代码更快,但如果您再次考虑您的逻辑并避免/减少您复制的时间,那么将会提高性能。 / p>

答案 1 :(得分:1)

使用std::vector<double>复数是一个很大的错误。性能。为什么?有几个原因:

  • 分配需要永远。典型值在200 ns以上。

  • 内存分配在堆上。空间方面的开销很大。

    • 内存分配器中的典型开销:两个指针,i。即8或16字节,具体取决于您的架构。

    • std::vector<>本身的开销:两个指针,另外8个或16个字节。

    • std::vector<>的总体配置:典型实现永远不会仅为两个元素分配内存。我估计这个开销至至少六个元素(八个元素最小分配)。这将导致48字节的开销。

    因此,您最终会使用80字节来存储适合16的内容。

    这很重要,因为这意味着您的缓存/内存总线必须完成五倍的工作!

  • 内存分配在堆上。这意味着您的复杂数字可能分散。这是缓存效率的另一个打击。

如果你想要快,请使用带有两个元素的数组(如果使用C风格数组或C ++ std::array<>无关紧要)或将复杂类型定义为普通旧数据{{1} }。所有三个选项都具有相同的内存布局,因此在性能上应该相同。但我更喜欢struct方法,因为它允许你重载运算符,这对数学类型如复数,向量,四元数等很好。