[英]What's the fastest way to copy and manipulate large, dense 2D arrays in c++
[英]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::complex
的vector
,该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.