【问题标题】:Does Fortran make copies of array sections passed to function/subroutine?Fortran 是否会复制传递给函数/子例程的数组部分?
【发布时间】:2020-03-04 21:40:18
【问题描述】:

当将数组部分传递给 Fortran 中的子例程时,例如f(a, b, c(2:5,4:6))(都是二维数组),程序是先做一个c的临时拷贝,然后传递给子程序(作为引用、指针等),还是整个动态处理?

我正在尝试将一些 Fortran 代码转换为 C++,并且我看到对将数组部分作为参数传递的子例程的调用。据我所知,C++ 不允许这样做,所以我试图在 C++ 中像这样 (mat2d = std::vector<std::vector<T>>) 规避这一点:

f(mat2d &a, mat2d &b, mat2d *a, int rows, int rows, int offsetx, int offsety) {...}

并调用为:

f(a, b, c.data(), ...)

这可行,但它需要大小,并且在我想要进行通用矩阵乘法的情况下(例如)还需要偏移量。因此,如果 Fortran 首先将 c(2:5,4:6) 复制到(比如说)temp(4,3) 数组,那么我可以在 C++ 中模仿:只需复制到一个临时文件,然后将该临时文件的引用传递给函数,没有行/列/偏移量。但如果不是……我不介意听听别人的想法。


示例子程序:

subroutine f(A, B, C)
  implicit none
  real(kind(1d0)) :: A(2,2), B(2,2), C(2,2)
  C = A*B
  return
end f

如果我的话不好,也许一张带有真实代码的图片可以吗?这些数组是auxfour(4,4)aux44(4,4)Gv(2,2)

这是一个电话,auxp(5) 和相同的Gv

完整的子程序。图片,而不是文字。

【问题讨论】:

  • 这真的取决于 Fortran 子例程(您没有显示)。 Fortran 还可以为非连续数组传递数组描述符。
  • @VladimirF 我添加了一些虚假的,类似于我在 Fortran 代码中看到的示例。如果没有,请考虑内置的matmul(),这也很有趣(对我来说)。我也有类似x(1:2,:)=matmul(y,z(1:2,:)) 的东西。但我对传递数组切片的任何情况都很感兴趣:这是一个副本吗?
  • 你用的是什么编译器? gfortran 有一个选项可以告诉您何时创建临时数组。
  • 上床睡觉,但简短的回答是您最初的问题没有答案,因为 Fortran 标准没有说明是否需要制作副本 - 它只说明了结果应该是什么。这对于 Fortran 来说很常见,只要结果正确,编译器就可以随意实现它。因此,一个编译器可以制作副本,而另一个编译器可能不会。同一个编译器的不同版本可能会做不同的事情。您只能依赖结果是什么,而不是如何实现该结果。
  • @ja72 我不使用英特尔编译器,但我想它类似于上面 cmets 中某处提到的 g++。但是,是的,这非常有用,并且(部分)得出了结论。

标签: c++ arrays fortran


【解决方案1】:

确实,Fortran 标准没有指定传递机制的细节。但是,由于编译器正在努力提高效率,因此我们可以对实践中通常发生的情况进行很多说明。

Fortran 标准没有指定参数是通过引用传递的,但规则实际上要求它。但是,它始终可以是对临时副本的引用。引用通常仅表示第一个元素的内存地址(指针)。当只传递一个元素并在子例程/函数中引用整个数组时,这将实现完全有效的用法。

在某些情况下,临时副本几乎是不可避免的。

让我们考虑

real :: a(10,10)

call f(a(2:5,4:6))

那么如果f

subroutine f(c)
  real :: c(3,3)

那么编译器可以做的很少,临时副本几乎可以保证。

subroutine f(c)
  real :: c(3,*)

但是,对于假设的形状数组

subroutine f(c)
  real :: c(:,:)

事实并非如此。这些参数是使用数组描述符传递的,并且可以是不连续的,您通常不会看到它们的临时副本。

最后,如果第一个维度是完整的:

real :: a(2:5,10)

call f(a(:,4:6))

副本也不是必需的,因为子数组在内存中是连续的。


即使不需要临时的,编译器也总是可以做到,但没有任何保证。但在实践中不太可能。编译器试图提高效率。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-15
    • 2012-10-15
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多