从1D数组表示计算3D索引的有效方法

时间:2012-12-15 16:33:26

标签: c++ math cuda

我有一个3D数据,存储在一维数组中。我像这样计算1D索引:

index = i + j * WIDTH + k * WIDTH * HEIGHT

我需要从i,j,k获取原始index索引。显而易见的方法就是这样:

k = index / (WIDTH * HEIGHT) 
j = (index % (WIDTH * HEIGHT)) / WIDTH
i = index - j * WIDTH - k * WIDTH * HEIGHT

但我想知道,有没有更有效的方法来做到这一点?至少没有模数...

这个问题的上下文 - 我在CUDA中有一个内核,我在其中访问数据并计算i, j, k索引(index对应于唯一的线程ID)。那么也许有一些特定于CUDA的方法可以做到这一点?我想这是一个很常见的问题,但我找不到更好的方法来做到这一点......

感谢您的想法!

3 个答案:

答案 0 :(得分:6)

尝试将您的尺寸调整为下一个2的幂。然后你可以使用位移和掩码代替乘法,除法和模数。

index = i | (j | k << HEIGHT_BITS) << WIDTH_BITS;

k = index >> (WIDTH_BITS + HEIGHT_BITS);
j = (index >> WIDTH_BITS) & ((1 << HEIGHT_BITS) - 1);
i = index & ((1 << WIDTH_BITS) - 1);

答案 1 :(得分:6)

你得到的很好;如果你想避免使用模数(因为这在gpus上非常昂贵)你可以使用j完成i所做的事情:

j = (index - (k*WIDTH*HEIGHT))/WIDTH

如果您希望逻辑更清晰,并且不需要原始index,则可以

k = index/(WIDTH*HEIGHT); 
index -= k*WIDTH*HEIGHT; 

j = index/WIDTH; 
index -= j*WIDTH; 

i = index/1;

然后非常直接地扩展到任意维度。您可以尝试通过预先计算WIDTH*HEIGHT这样的事情来调整上述内容,但我只是提出优化并信任编译器为您执行此操作。

关于向2舍入幂的建议是正确的,因为它会加速指数计算,但需要付出相当大的代价。在这个(不是太糟糕)的情况下WIDTH=HEIGHT=100,它会使你的3d阵列的内存需求增加60%(WIDTH=HEIGHT=128)并且GPU上的内存通常已经很紧;并且根据您的访问模式,使您的阵列具有两个大小的权限可能会引发银行冲突问题。

答案 2 :(得分:1)

仅适用于尺寸为2的幂的情况。使用位掩码。例如,如果第一个索引最大值为4,那么它应该占索引中的前2位。