6

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

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

比我需要i,j,kindex. 这样做的明显方法是这样的:

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

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

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

谢谢你的想法!

4

3 回答 3

6

尝试将您的尺寸四舍五入到二的下一个幂。然后,您可以使用位移位和掩码来代替乘法、除法和取模。

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);
于 2012-12-15T17:17:30.377 回答
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;

然后非常直接地扩展到任意维度。您可以尝试通过执行诸如 precomputing 之类的操作来调整上述内容WIDTH*HEIGHT,但我只会进行优化并相信编译器会为您执行此操作。

关于四舍五入到 2 的幂的建议是正确的,因为它会加快指数计算,但代价相当高。在这种(还不错)的情况下WIDTH=HEIGHT=100,它会将 3d 数组的内存需求增加 60%(WIDTH=HEIGHT=128),并且 GPU 上的内存通常已经很紧张了;并且根据您的访问模式,使您的数组大小为二次方很可能会引入银行冲突问题。

于 2012-12-17T01:02:38.373 回答
1

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

于 2012-12-15T17:14:17.147 回答