繁体   English   中英

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

[英]Fastest way to copy one dimension of 2D vector in c++

我有一个二维向量,即时通讯用于复杂的数字。 例如:

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

在我的代码深处,我需要将我的Complex向量的一部分拉到其他部分。 像是从某个变量(1D向量)的索引10到18实数部分复制,并从其他变量(1D向量)的索引10到18 imag部分复制。 目前,我使用for周期来执行此操作:

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一部分。 之后,所有代码的性能从一个样本的〜5 ms增加到一个样本的〜1.8 ms。 (在我重写mul操作并重写整个周期后2.5毫秒,这是一个非常有用的建议,非常感谢)

如果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

然后,您将拥有一个类型为std::complexvector ,该vector将使您的数据更加健壮,这可能会改善locality ,并应利用caching

您可以执行以下操作:

#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鸭子)

在您的情况下,您可以尝试上面我建议的方法,以使您的代码更快,但是,如果您再考虑一下逻辑并避免/减少了复制的时间,则性能会得到提高。

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

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

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

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

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

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

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

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

  • 内存分配在堆上。 这意味着您的复数可能会分散。 这是对缓存效率的又一打击。

如果想提高速度,请使用带有两个元素的数组(使用C样式数组或C ++ std::array<>都没关系),或者将复杂类型定义为普通的旧数据struct 这三个选项均具有相同的内存布局,因此性能应相同。 但是我更喜欢使用struct方法,因为它允许您重载运算符,这对复数,向量,四元数等数学类型非常有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM