Fortran 函数 returns 数组时的最佳做法是什么?
What is the best practice when a Fortran function returns an array?
假设我想编写一个函数,将一维数组 x 和 returns 另一个数组 y[=22= 作为输入] 基于它的相同维度(为了说明它,我使用了一个将它乘以 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 中哪种方法比较好?
可能两者都不是,尽管与这些事情一样,答案取决于具体情况。
假设一个非基本操作,我倾向于编写这样一个函数(在模块中):
function times2(x) result(y)
real, intent(in) :: x(:)
real :: y(size(x))
y = 2*x
end function
上面有一个假设的形状虚拟参数,带有自动函数结果。它:
写入Fortran 95标准时可用;
在源代码中明确指定函数结果大小对函数参数的依赖性,这可能(或可能不会)帮助您的 reader 代码理解正在发生的事情(其中一个 reader 是编译器本身,这可能有助于优化);
可能(或可能不会)避免数组值的中间副本;
可能(或可能不)要求 space 作为函数结果或堆栈上的等效临时值。
如果操作是基本的(即每个元素上的相同操作,根据给出的实际示例),我会编写一个基本函数。此类函数的源采用标量参数并提供不可分配的非指针标量结果。
elemental function times2(x) result(y)
real, intent(in) :: x
real :: y
y = 2*x
end function
当函数结果的形状(或某些其他属性)无法用简单的规范表达式描述时,我通常使用延迟形状可分配函数结果。可分配函数结果:
要求写入至少符合 Fortran 2003 标准;
可能需要额外的堆内存 allocation/deallocation 对,超出绝对必要,这可能(或可能不会)对性能产生影响;
可能不需要像自动结果情况一样使用堆栈,这可能(也可能不会)避免执行时出现堆栈溢出问题。
编译器实现细节(包括编译器选项)影响比较。特别是,编译器如何管理临时内存的差异可能会使这两种方法在堆栈和堆分配的要求方面趋于一致。
避免显式形状数组虚拟参数,除非您有特殊要求。
假设我想编写一个函数,将一维数组 x 和 returns 另一个数组 y[=22= 作为输入] 基于它的相同维度(为了说明它,我使用了一个将它乘以 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 中哪种方法比较好?
可能两者都不是,尽管与这些事情一样,答案取决于具体情况。
假设一个非基本操作,我倾向于编写这样一个函数(在模块中):
function times2(x) result(y)
real, intent(in) :: x(:)
real :: y(size(x))
y = 2*x
end function
上面有一个假设的形状虚拟参数,带有自动函数结果。它:
写入Fortran 95标准时可用;
在源代码中明确指定函数结果大小对函数参数的依赖性,这可能(或可能不会)帮助您的 reader 代码理解正在发生的事情(其中一个 reader 是编译器本身,这可能有助于优化);
可能(或可能不会)避免数组值的中间副本;
可能(或可能不)要求 space 作为函数结果或堆栈上的等效临时值。
如果操作是基本的(即每个元素上的相同操作,根据给出的实际示例),我会编写一个基本函数。此类函数的源采用标量参数并提供不可分配的非指针标量结果。
elemental function times2(x) result(y)
real, intent(in) :: x
real :: y
y = 2*x
end function
当函数结果的形状(或某些其他属性)无法用简单的规范表达式描述时,我通常使用延迟形状可分配函数结果。可分配函数结果:
要求写入至少符合 Fortran 2003 标准;
可能需要额外的堆内存 allocation/deallocation 对,超出绝对必要,这可能(或可能不会)对性能产生影响;
可能不需要像自动结果情况一样使用堆栈,这可能(也可能不会)避免执行时出现堆栈溢出问题。
编译器实现细节(包括编译器选项)影响比较。特别是,编译器如何管理临时内存的差异可能会使这两种方法在堆栈和堆分配的要求方面趋于一致。
避免显式形状数组虚拟参数,除非您有特殊要求。