【问题标题】:What is the best practice when a Fortran function returns an array?Fortran 函数返回数组时的最佳实践是什么?
【发布时间】:2019-07-16 17:34:54
【问题描述】:

假设我想编写一个函数,该函数将一个维度的数组 x 作为输入,并基于它返回另一个相同维度的数组 y(以说明它我正在使用一个将其乘以 2) 的函数。我对该代码有两个选择:

function times2(x) result(y)
    real, intent(in) :: x(:)
    real, allocatable :: y(:)

    allocate(y(size(x))
    y = 2*x
end function

function times2(x,n) result(y)
    real, intent(in) :: x(n)
    integer, intent(in) :: n
    real  :: y(n)

    y = 2*x
end function

我个人更喜欢第一个,因为 更容易 用于调用者,但我不确定哪个在内存方面更好,假设数组 x 可能很大,我不知道不知道是延迟数组好还是自动数组好。 在任何情况下,在现代 Fortran 中哪种方法是最好的方法?

【问题讨论】:

  • 我认识的大多数人会使用子程序,而不是函数。修改参数的函数是邪恶的——它们会引起混乱,而且我的理解是,在更复杂的表达式中使用它们时,它们的作用并不总是得到很好的定义。因此,如果您必须使用函数,请使用第一种方式,但我想大多数人会说子程序是要走的路。
  • 为什么对呼叫者来说应该“更容易”?
  • 在底层,函数结果通常是通过创建一个带有隐藏参数的子例程来实现的。然而,如果您在复杂表达式中使用该函数,您最终可能会在堆栈上得到一个临时的。但是,只要您对数组使用复杂的表达式,就会发生这种情况。
  • 我想我会为 cross(u, v) 之类的函数使用自动返回数组(对于返回另一个向量的两个向量的叉积),而对 matmul 之类的函数使用可分配的返回数组(A, B) 如果 A 或 B 可能非常大(因此它们可能不适合堆栈)。
  • 但是您可以重写第二个以使y(size(x)) 仍然具有x(:) (我承认这是我认为您所做的:我可能会根据最小的差异跳过实际代码在自动和延迟之间。)

标签: arrays function fortran heap-memory stack-memory


【解决方案1】:

可能两者都没有,尽管与这些事情一样,答案取决于具体情况。

假设一个非元素操作,我倾向于写这样一个函数(在一个模块中):

function times2(x) result(y)
  real, intent(in) :: x(:)
  real :: y(size(x))

  y = 2*x
end function

上面有一个假定的形状虚拟参数,具有自动函数结果。它:

  • 在写入 Fortran 95 标准时可用;

  • 在源代码中明确指定函数结果大小对函数参数的依赖性,这可能(或可能不会)帮助您的代码读者了解正在发生的事情(其中一个读者是编译器本身,这可能有助于优化);

  • 可以(也可以不)避免数组值的中间副本;

  • 可能(或可能不)需要空间来存放函数结果或堆栈上的等效临时空间。

如果操作是元素的(即每个元素上的相同操作,根据给出的实际示例),我会编写一个元素函数。此类函数的源代码采用标量参数并提供不可分配的非指针标量结果。

elemental function times2(x) result(y)
  real, intent(in) :: x
  real :: y

  y = 2*x
end function

当函数结果的形状(或某些其他属性)无法通过简单的规范表达式来描述时,我通常使用延迟形状可分配函数结果。可分配函数结果:

  • 至少需要写入 Fortran 2003 标准;

  • 可能需要超出严格要求的额外堆内存分配/释放对,这可能(或可能不会)影响性能;

  • 可能不需要与自动结果情况相同的堆栈使用,这可能(或可能不会)避免在执行时出现堆栈溢出问题。

编译器实现细节(包括编译器选项)会影响比较。特别是,编译器如何管理临时内存的差异可能会使这两种方法在堆栈和堆分配的要求方面趋于一致。

避免显式形状数组伪参数,除非您有特殊要求。

【讨论】:

  • 谢谢,我不知道你可以将输出的形状指定为 size(x),但我知道我也会使用它。我说的是非元素的,还是谢谢你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-23
  • 1970-01-01
相关资源
最近更新 更多