最快的方式复制一维二维矢量在c++

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

本文关键字:二维 c++ 方式 复制 一维      更新时间:2023-10-16

我有一个用于复数的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

在我的代码的深度,我需要拉出我的复杂向量的一部分到其他。例如,将索引10的实部复制到某个变量(1D向量)中的实部,并将索引10的映像部分复制到其他变量(1D向量)中的实部。目前我正在使用for循环:

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

如profiler所示,这段代码是整个程序的瓶颈。有什么办法可以改进吗?

小更新: "Sample"变量是8到20的int,通常是8。变量i来自外部for循环。

大更新:所以,我把2D向量和重写的一切与complex类。我也重写了我的多操作在"for"循环。我不知道为什么,但是从complex.imag复制比从complex.real部分复制需要更多的时间(多2)。在所有这些之后,代码的性能从一个样本的~5 ms增加到一个样本的~1.8 ms。(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次乘法,而不是像luk32注意到的那样做2 * Samples

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

那么你将有一个类型为std::complexvector,这将使你的数据更健壮,这可能会改进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, aka Mooling duck)

在你的情况下,你可以尝试我上面的建议,使你的代码更快,但如果你会再次思考你的逻辑,避免/减少你复制的时间,那么将获得一个提升性能的奖励。

对复数使用std::vector<double>是一个巨大的错误。表演为什么?原因如下:

  • 分配是永久的。典型值在200ns以上。

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

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

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

    • std::vector<>的过度分配:典型的实现从不为两个元素分配内存。我估计这个开销至少 6个元素(最小分配8个元素)。这将导致48字节的开销。

    所以,你最终使用了80字节来存储16个字节的内容。

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

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

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