是否可以消除do循环

Is it possible to eliminate do loop

据我们所知,较新版本的Fortran 支持数组操作,这可以消除许多循环。所以我想知道是否有可能消除以下代码片段中的最后一个剩余循环(使其成为单行代码):

subroutine test(n,x,lambda)
   integer, intent(in) :: n
   real, dimension(:), intent(in) :: x
   real, dimension(:), intent(out) :: lambda
   real :: eps
   integer :: i

   do i=1,n
      lambda(i) = product(x(i)-x, mask=(abs(x(i)-x) > epsilon(eps)))
   enddo
end subroutine

它的目的是计算 n lambda(i) 个值,其中

lambda(i) = (x(i)-x(1))*(x(i)-x(2))*...*(x(i)-x(i-1)*(x(i)-x(i+1))*...*(x(i)-x(n))

是的,你可以缩短这个,product可以使用二维数组:

  1. 您首先需要建立差异矩阵:
   do i=1,n
     mat(:,i) = x(i) - x
   enddo

或者,作为单行:

   forall ( i=1:n ) mat(:,i) = x(i) - x
  1. 现在可以沿着第二个维度做乘积了:
   lambda = product(mat, dim=2, mask=(abs(mat) > epsilon(eps)))

整个节目:

program test
   integer, parameter  :: n = 3
   real, dimension(n) :: x
   real, dimension(n) :: lambda
   real, dimension(n,n) :: mat
   real :: eps = 1.
   integer :: i

   call random_number( x )

   do i=1,n
      lambda(i) = product(x(i)-x, mask=(abs(x(i)-x) > epsilon(eps)))
   enddo
   print *,lambda

   forall ( i=1:n ) mat(:,i) = x(i) - x
   lambda = product(mat, dim=2, mask=(abs(mat) > epsilon(eps)))
   print *,lambda

end program

您是否尝试过在数组创建中使用隐含的 do 循环?像 real, dimension(:), intent(out):: lambda =(/product(x(i)-x, mask=(abs(x(i)-x)>epsilon(eps))), i=1, n/) 这样的东西……我不确定这里的语法,但类似的东西可能有用。 如果您的 x-array 可用,您甚至可以在不调用子例程的情况下创建数组并在主程序中执行此操作。

希望对您有所帮助。

好的,试试这个

lambda = product(max(spread(x, dim=1, ncopies=size(x)) - &
            spread(x, dim=2, ncopies=size(x)), eps), dim=2)

那是一条线。它也相当浪费内存,而且比原来的更难理解。