使用 2 维的幂转换 1D -> 3D 的更快方法

Faster way to convert 1D -> 3D using powers of 2 dimensions

我正在尝试优化访问和更改 3D 环境的数据,因为某些操作必须执行数百万次。目前我有以下优化:

3D向量的索引如下:

给定以下伪代码:

mapSize.X = 4
mapSize.Y = 4
mapSize.Z = 2

Xdif = 1
Ydif = mapSize.X = 4
Zdif = mapSize.X * mapSize.Y = 16

Xexponent = log2(Xdif) = log2(1) = 0 (2^0 = 1 = Xdif)
Yexponent = log2(Ydif) = log2(4) = 2 (2^2 = 4 = Ydif)
Zexponent = log2(Zdif) = log2(16) = 4 (2^4 = 16 = Zdif)

一个人会从 3D -> 1D 给定 Vector(1,2,1) 使用以下方法:

location.X = 1
location.Y = 2
location.Z = 1

shiftIndex.X = location.X << Xexponent = 1 << 0 = 1
shiftIndex.Y = location.Y << YExponent = 2 << 2 = 8
shiftIndex.Z = location.Z << Zexponent = 1 << 4 = 16

index = shiftIndex.X + shiftIndex.Y + shiftIndex.Z = 1 + 8 + 16 = 25

如您所见,我正在使用位移来提高处理速度。现在我知道如何使用给定索引 30 的除法和除法余数来转换 3D -> 1D,如下所示:

index = 30

location.X = index % mapSize.X
location.Y = (index / mapSize.X) % mapSize.Y
location.Z = ((index / mapSize.X) / mapSize.Y) % mapSize.Z

有没有什么方法可以在这里使用位移(或其他任何与此相关的方法)来使速度更快?一段时间以来,我一直在尝试破解它,但我无法破解它,如果它一开始是可能的话。

你只是想把 3 个数字打包成一个更大的数字吗?

如果是这样,你为什么不转移并遮住?

ThreeToOne(v3) -> v3.x | (v3.y << 8 ) | (v3.z << 16)

OneToThree(v) -> v3(v & 0xFF, v >> 8 & 0xFF, v >> 16 & 0xFF)

我在别处得到了答案。

当你除以一个 2 的幂的数时,你可以用一个右移操作代替那个除法,它是 2 的幂的指数。 模数运算可以用按位运算符和 n - 1 替换(同样,如果它是 2 的幂)。其中 n 是你潜水的数字。 所以总结代码:

mapSize.X = 4
mapSize.Y = 4
mapSize.Z = 2

Xdif = 1
Ydif = mapSize.X = 4
Zdif = mapSize.X * mapSize.Y = 16

XDifExponent = log2(Xdif) = log2(1) = 0 (2^0 = 1 = Xdif)
YDifExponent = log2(Ydif) = log2(4) = 2 (2^2 = 4 = Ydif)
ZDifExponent = log2(Zdif) = log2(16) = 4 (2^4 = 16 = Zdif)

XSizeExponent = log2(mapSize.X) = log2(4) = 2 (2^2 = 4 = mapSize.X)
YSizeExponent = log2(mapSize.Y) = log2(4) = 2 (2^2 = 4 = mapSize.Y)
ZSizeExponent = log2(mapSize.Z) = log2(2) = 1 (2^1 = 2 = mapSize.Z)

Vector3D -> Index example:
location.X = 1
location.Y = 2
location.Z = 1

shiftIndex.X = location.X << XDifExponent = 1 << 0 = 1
shiftIndex.Y = location.Y << YDifExponent = 2 << 2 = 8
shiftIndex.Z = location.Z << ZDifExponent = 1 << 4 = 16

index = shiftIndex.X + shiftIndex.Y + shiftIndex.Z = 1 + 8 + 16 = 25

Index -> Vector3D example:
index = 30

location.X = index & (mapSize.X - 1) = 2
location.Y = (index >> XSizeExponent) & (mapSize.Y - 1) = 3
location.Z = ((index >> XSizeExponent) >> YSizeExponent) & (mapSize.Z - 1) = 1