我在我的代码中使用 OpenMP,但为了做到这一点,我必须解决这个依赖关系:
do q=1,pppp
i=0
DO j=1, pppp
do c1=1,3
vect(c1)=xx(q,c1)-xx(j,c1)
end do
dist=sqrt(vect(1)**2+vect(2)**2+vect(3)**2)
if(dist<0.0001)then
i=i+1
if(i>10)i=10
caravec(q,i)=j
endif
ENDDO
ENDDO
我试图避免 ordered
子句,因为它很昂贵,但我不知道如何删除依赖项。我该怎么做?
感谢大家的帮助
最佳答案
在 @dreamcrash 上,您可以做一些 Fortran 语言的改进。 ' 出色的回答:
Fortran 是 column-major ,所以你想迭代内部循环中最左边的索引,而不是最右边的索引。所以你应该转置 xx
, 所以它是 3*pppp
索引为 xx(c1,q)
的数组而不是 pppp*3
索引为 xx(q,c1)
的数组.
您可能希望使用整个数组操作而不是单个元素操作,因为它们更有可能被向量化。
您可以存储 dist<0.0001
的结果而不是 dist
.
您可以替换 if (i>10)...
用min
语句,它将是无分支的,因此可能运行得更快。
所以代码看起来像这样:
do q=1,pppp
do j=1,pppp
vect = xx(:,q)-xx(:,j)
within_tolerance(j, q) = dot_product(vect, vect) < 1.0e-8
enddo
enddo
do q=1,pppp
i=0
do j=1,pppp
if (within_tolerance(j, q)) then
i = min(i+1, 10)
caravec(q,i)=j
endif
enddo
enddo
您可能还想转置 caravec
, 但这将取决于它在其他地方的使用方式。
如果这是您的代码的瓶颈,您可能需要研究基于体素的方法来查找向量集中的最近邻居。快速谷歌带来例如this .
体素方法消除了对 q
的双重循环的需要和 j
,这可能会让您更快地进行此类比较。
另一方面,体素方法非常复杂,我认为它们并不适合所有情况(例如,如果点的区域非常密集,而点的区域非常稀疏,那么我认为体素方法会斗争)。
关于multithreading - 我怎样才能避免这个循环中的 "i"依赖?语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72836033/