我有一个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的方法可以做到这一点?我想这是一个很常见的问题,但我找不到更好的方法来做到这一点......
感谢您的想法!
答案 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位。