C++ 高效访问存储为一维阵列的三维阵列
我有一个3D数组,它以列方式存储为一维数组。比如说,C++ 高效访问存储为一维阵列的三维阵列,c++,c,arrays,multidimensional-array,fft,C++,C,Arrays,Multidimensional Array,Fft,我有一个3D数组,它以列方式存储为一维数组。比如说, for( int k = 0; k < nk; k++ ) // Loop through the height. for( int j = 0; j < nj; j++ ) // Loop through the rows. for( int i = 0; i < ni; i++ ) // Loop through the columns. { ijk = i
for( int k = 0; k < nk; k++ ) // Loop through the height.
for( int j = 0; j < nj; j++ ) // Loop through the rows.
for( int i = 0; i < ni; i++ ) // Loop through the columns.
{
ijk = i + ni * j + ni * nj * k;
my3Darray[ ijk ] = 1.0;
}
我的计算效率高吗?是否有可能将
my3Darray
直接传递给处理向量FFT的函数(而不是将向量复制到myvec
)?当所有内容都缩减到最里面的位和字节时,三维数组当然会存储在一维内存中。因此,给定数组元素的三个维度,编译器生成的代码与您自己计算数组元素位置的代码几乎相同。惊喜
换句话说,这几乎是一样的
对于显式三维数组,唯一对编译器有利的事情是编译器知道所有内部维度的大小,如果最内部维度切片的大小恰好是方便的,比如2的幂,编译器可能会用等效的左移位替换一些乘法,我想这会稍微快一点,然后是一个完整的乘法指令。但如果结果是性能上的巨大差异,我会感到惊讶
选择维度的相对顺序可能更为重要,这样,用于转换的典型访问模式将对CPU缓存更为友好。您可以通过预先计算这样的步长来减少倍数:
...
for( int j = 0; j < nj; j++ ) // Loop through the rows.
{
int stride = ni * nj;
ijk = i + ni * j;
for( int k = 0; k < nk; k++ ) // Loop through the heights.
{
myvec[ k ] = my3Darray[ ijk ];
fft( myvec, myvec_processed );
ijk += stride;
}
}
。。。
for(int j=0;j
但这只会让事情加快一点。由于以非顺序方式访问
my3Darray
,您仍然会遇到缓存问题。您不能将k设置为最内部的变量,这样您就不会跳入ni*nj
步骤,而是按1,使其对缓存友好。你能做的不多了。我需要计算所有向量的FFT:行方向、列方向以及高度方向。你说的是高度。。。是什么让你觉得它现在很慢,更重要的是,它可以改进。您展示了最不利于缓存的示例(顺便说一句,高度也是如此)。同样,在我看来,除了为所显示的代码改进缓存友好性之外,没有什么可以做的了。希望我错了。我实际上会尝试的一件事是,复制整个数组,对其重新编制索引。可能两次跳跃为1的迭代比一次跳跃较大的迭代要快,但这取决于CPU缓存预测器的智能程度。您可以用ijk+=stride替换复杂的乘法行代码>如果计算跨步
并在循环外初始化ijk
。但是不幸的是,如果您不按顺序访问,您仍然会遇到缓存问题。
...
for( int j = 0; j < nj; j++ ) // Loop through the rows.
{
int stride = ni * nj;
ijk = i + ni * j;
for( int k = 0; k < nk; k++ ) // Loop through the heights.
{
myvec[ k ] = my3Darray[ ijk ];
fft( myvec, myvec_processed );
ijk += stride;
}
}