我需要优化三次嵌套循环。操作
在循环内基本上是调用l1
,m1
,l2
,m2
,l3
,m3
的函数
并将其添加到(它有点复杂,有更多的总和)。
在我的计算中,我需要运行这个循环以获得大量不同的东西
k值(见下面的代码)。优化我所用代码的第一步是在程序开始时创建一次数组,然后读取它们。这意味着每次嵌套循环执行时都不必评估函数。我的lmax
介于20-60之间,我希望尽可能大。
我的一个优点是数组中的大多数值都是零。这使得可以在不耗尽内存的情况下进行此计算。我已经这样做了,所以数组只包含非零值,然后我创建了一个函数,它有一组if条件来评估索引是否应该迭代。选择规则是 有些复杂,但并不过分。
这样做的原因是现在循环包括按顺序读取N个数组,而且应该相当快。交易是我需要评估一堆if语句。
以下Fortran伪代码原则上显示了它是如何完成的。
do l1 = 0,lmax
do m1 = -l1,l1
do l2 = 0,lmax
do m2 = -l2,l2
do l3 = 0,lmax
do m3 = -l3,l3
tmp1 = 0.0d0
j1 = incr(l1, m1, l2, m2, l3, m3,i1)
if(j1 .gt.i1) then
i1=j1
tmp1 = array1(i1)
endif
.....
a = a + k1*tmp1 + k2*tmp2 ....
end do
end do
end do
end do
end do
end do
我的问题是:有没有人看到改善这种情况的方法?我在哪里浪费时间,甚至可以希望改进它?
我应该注意到,我正在运行OpenMP。循环的不同执行是独立的,我可以并行执行。他们唯一要分享的是数组array1
,array2
等等。
答案 0 :(得分:1)
我认为这可能是一个好的开始。但是需要更多信息。
基本上,将6个循环重写为2个循环。一个超过L值,一个超过M值。您可以使用整数运算来重建原始(l1,l2,l3)
和(m1,m2,m3)
。
lim = lmax+1
l_loop : DO l_idx = 0,lim**3-1
l1 = l_idx/(lim*lim)
l2 = MOD(l_idx,lim*lim)/lim
l3 = MOD(MOD(l_idx,lim*lim),lim)
! implement quick return
m_loop : DO m_idx = 0,(2*l1+1)*(2*l2+1)*(2*l3+1)-1
m1 = m_idx / ((2*l2+1)*(2*l3+1)) - l1
m2 = MOD(m_idx,(2*l2+1)*(2*l3+1))/(2*l3+1) - l2
m3 = MOD(MOD(m_idx,(2*l2+1)*(2*l3+1)),(2*l3+1)) - l3
! implement quick return
tmp1 = 0.0d0
j1 = incr(l1, m1, l2, m2, l3, m3,i1)
IF(j1 .GT.i1) THEN
i1=j1
tmp1 = array1(i1)
ENDIF
...
a = a + k1*tmp1 + k2*tmp2 ...
END DO m_loop
END DO l_loop