我最近被要求提供一段能够“就地”降采样/下采样数组的代码。这个“降采样”函数接受一个整数数组,并将数组中偶数索引i处的条目存储在索引i/2处。对于数组中所有条目都是如此。
这会将原始数组中的所有偶索引条目移动到数组的前半部分。然后可以将数组的其余部分初始化为0。总体结果是一个数组,保留了原始数组中所有偶数索引条目(通过将它们移动到前半部分),并且数组的后半部分为0。显然,这用于信号处理中的降采样。
代码大致如下:
这会将原始数组中的所有偶索引条目移动到数组的前半部分。然后可以将数组的其余部分初始化为0。总体结果是一个数组,保留了原始数组中所有偶数索引条目(通过将它们移动到前半部分),并且数组的后半部分为0。显然,这用于信号处理中的降采样。
代码大致如下:
void decimate (vector<int>& a) {
int sz = a.size();
for (int i =0; i < sz; i++) {
if (i%2 == 0) {
a[i/2] = a[i];
}
}
for (int i =(sz-1)/2; i < sz; i++) a[i] = 0;
}
在建议将某些变量保留在寄存器中的基本改进后,我无法找到进一步优化的方法,但不确定是否可以做到。
有没有办法优化循环中的内存访问模式以获得更好的缓存性能? 或者通过矢量化等方式优化压缩/降采样数组的主要复制操作以使其更高效?(例如对于支持该功能的平台)
for (int i =0; i < sz; i++) {
if (i%2 == 0) {
a[i/2] = a[i];
}
}
是否有任何循环转换(例如平铺/条带挖掘),可以为这种减少循环产生高效的代码?
编辑:下面的答案中提出了一些不同的方法,似乎利用了memset/fill或指针算术来提高速度效率。本问题主要关注是否存在明确定义的循环变换,可以显著改善局部性或缓存失效(例如,如果它是一个循环嵌套,有两个循环,可以潜在地研究循环平铺以优化缓存失效)。