1

我想用 FORTRAN 的内在函数和数组表示法替换下面的 do 循环。

do i=2, n
  do j=2, n
     a=b(j)-b(j-1)
     c(i,j)=a*c(i-1,j)+d(i,j)
   end do
end do

但是,由于 c(i,j) 取决于 c(i-1,j),因此以下试验均无效。因为他们不更新 c(i,j)

!FORALL(i = 2:n , j = 2:n ) c(i,j)=c(i-1,j)*(b(j)-b(j-1))+d(i,j)
!FORALL(i = 2:n) c(i,2:n)=c(i-1,2:n)*(b(2:n)-b(1:n-1))+d(i,2:n)
!c(2:n,2:n)=RESHAPE(   (/(c(i-1,2:n)*(b(2:n)-b(1:n-1))+d(i,2:n),i=2,n)/), (/n-1, n-1/))
!c(2:n,2:n)=RESHAPE((/(((b(j)-b(j-1)) *c(i-1,j)+d(i,j)  ,j=2,n),i=2,n)/), (/n-1, n-1/))
!c(2:n,2:n)=spread(b(2:n)-b(1:n-1),ncopies = n-1,dim=1) * c(1:n-1,2:n) +d(2:n,2:n)

这是我能得到的最好的。但它仍然有一个do循环

do i=2, n
     c(i,2:n)=c(i-1,2:n)*(b(2:n)-b(1:n-1))+d(i,2:n)
end do

所有的循环都可以用内在函数和数组表示法代替吗?或者这个可以以某种方式更换吗?

4

2 回答 2

0

从...开始

do i=2, n
   do j=2, n
      a=b(j)-b(j-1)
      c(i,j)=a*c(i-1,j)+d(i,j)
   end do
end do

do我们可以通过巧妙地使用SIZESPREAD来快速消除循环EOSHIFT


res = SPREAD(b - EOSHIFT(b,-1),2,SIZE(c,2))*EOSHIFT(c,-1) + d

啊哈,原来我收到的错误(V1)是由于我使用RESHAPE而不是SPREAD. 我在当前版本(V2)中修复了这个问题,它可以编译并ifortgfortran.

于 2013-10-10T21:03:46.987 回答
0

根据我的经验,没有什么比传统的 do-loop 更好的了。所有扩展内在函数通过将内容复制到临时空间(通常在堆栈上)、重塑和排序来创建内存和 CPU 开销。如果您正在操作大型数组,您可能会遇到内部函数的内存不足问题。

您最好的选择是坚持正确布置索引的二维循环:

do i=2, n
  e = c(1:n,i-1)
  do j=2, n
     a=b(j)-b(j-1)
     c(j,i)=a*e(j)+d(j,i)
   end do
end do

通过替换索引(并确保遵循您的维度声明),您可以节省内存分页。c(j,i) 和 d(j,i) 引用在内存中按列移动,而 c(j,i-1) 会跨列(并产生分页开销)。所以我们将它复制到一个临时的 e 数组中。

我认为这将是最快的......

于 2013-10-09T21:03:51.367 回答