【发布时间】:2015-05-25 10:39:02
【问题描述】:
对于我目前在网格生成算法方面的工作,我需要一种有效的方法将三维坐标转换为 z 顺序(更准确地说:三个 4 字节整数转换为一个 8 字节整数),反之亦然。这篇维基百科文章很好地描述了它: Z-order curve。 由于我不是程序员,所以我提出的解决方案可以完成它应该做的事情,但使用 mvbits 内在明确地进行位交错可能非常幼稚:
SUBROUTINE pos_to_z(i, j, k, zval)
use types
INTEGER(I4B), INTENT(IN) :: i, j, k
INTEGER(I8B), INTENT(OUT) :: zval
INTEGER(I8B) :: i8, j8, k8
INTEGER(I4B) :: b
zval = 0
i8 = i-1
j8 = j-1
k8 = k-1
do b=0, 19
call mvbits(i8,b,1,zval,3*b+2)
call mvbits(j8,b,1,zval,3*b+1)
call mvbits(k8,b,1,zval,3*b )
end do
zval = zval+1
END SUBROUTINE pos_to_z
SUBROUTINE z_to_pos(zval, i, j, k)
use types
INTEGER(I8B), INTENT(IN) :: zval
INTEGER(I4B), INTENT(OUT) :: i, j, k
INTEGER(I8B) :: i8, j8, k8, z_order
INTEGER(I4B) :: b
z_order = zval-1
i8 = 0
j8 = 0
k8 = 0
do b=0, 19
call mvbits(z_order,3*b+2,1,i8,b)
call mvbits(z_order,3*b+1,1,j8,b)
call mvbits(z_order,3*b ,1,k8,b)
end do
i = int(i8,kind=I4B) + 1
j = int(j8,kind=I4B) + 1
k = int(k8,kind=I4B) + 1
END SUBROUTINE z_to_pos
请注意,我更喜欢输入和输出范围以 1 而不是 0 开头,这会导致一些额外的计算。
事实证明,这个实现相当慢。我测量了变换和重新变换 10^7 个位置所需的时间:
gfortran -O0:6.2340 秒
gfortran -O3:5.1564 秒
ifort -O0:4.2058 秒
ifort -O3:0.9793 秒
我还为 gfortran 尝试了不同的优化选项,但没有成功。虽然使用 ifort 优化的代码已经快了很多,但它仍然是我程序的瓶颈。 如果有人能指出正确的方向如何在 Fortran 中更有效地进行位交错,那将非常有帮助。
【问题讨论】:
-
您是否有理由在位级别而不是例如直接存储整数坐标?
-
这两个子程序的主要目的之一是在人口稀少的笛卡尔网格中寻找邻居。我看不出存储整数坐标对我有什么帮助。你能说得更具体点吗?
标签: fortran bit-manipulation z-order