根据子例程参数创建常量
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了根据子例程参数创建常量相关的知识,希望对你有一定的参考价值。
我有以下代码片段将矢量x
分成几个数组。
subroutine split(n, x, r, v, p, t)
implicit none
integer, intent(in) :: n
double precision, intent(in) :: x(n)
integer, parameter :: m = (n + 6) / 10
! problem here 1
double precision, intent(out) :: r(3, m - 1)
double precision, intent(out) :: v(3, m - 1)
double precision, intent(out) :: p(3, m)
double precision, intent(out) :: t(m)
! code
end subroutine split
此代码不会与消息一起编译
Error: Parameter 'n' at (1) has not been declared or is a variable, which does not reduce to a constant expression
如果我手动将所有m
更改为(n + 6) / 10
,但代码编译得很好,但我正在寻求更优雅的方法。
作为替代方法,我将代码重写为
subroutine splitcore(n, m, x, r, v, p, t)
implicit none
integer, intent(in) :: n, m
double precision, intent(in) :: x(n)
double precision, intent(out) :: r(3, m - 1)
double precision, intent(out) :: v(3, m - 1)
double precision, intent(out) :: p(3, m)
double precision, intent(out) :: t(m)
! code
end subroutine splitcore
subroutine split(n, x, r, v, p, t)
implicit none
integer, intent(in) :: n
double precision, intent(in) :: x(n)
integer :: m
double precision, intent(out) :: r(3, *)
double precision, intent(out) :: v(3, *)
double precision, intent(out) :: p(3, *)
double precision, intent(out) :: t(*)
m = (n + 6) / 10
call splitcore(n, m, x, r, v, p, t)
end subroutine split
子程序中数组声明的数组规范允许为规范表达式。
规范表达式可以包括对纯函数的引用。您可以使用这样的纯函数来分解m
的有效计算。
要在其使用范围内被认为是纯粹的,必须可以访问纯函数的显式接口。提供这种显式接口的最简单方法是将函数放在一个模块中(如果split
已经在这样的模块中,它可以是同一个模块)。
module m_mod
implicit none
contains
pure function m(n)
integer, intent(in) :: n
integer :: m
m = (n + 6) / 10
end function m
end module m_mod
subroutine split(n, x, r, v, p, t)
use m_mod
implicit none
integer, intent(in) :: n
double precision, intent(in) :: x(n)
double precision, intent(out) :: r(3, m(n) - 1)
double precision, intent(out) :: v(3, m(n) - 1)
double precision, intent(out) :: p(3, m(n))
double precision, intent(out) :: t(m(n))
...
就原始代码而言 - 变量,常量或类型参数的初始化程序必须是一个常量表达式 - 这是编译器在编译时可以评估的有效内容。常量表达式对它的限制比规范表达式更多 - 例如,它不能引用变量的值 - 因为变量不是常量。
split
子程序中的虚拟变量可能是假定的形状(用(:)
或(:,:)
声明,适用于等级而不是显式的形状数组。然后,数组的形状的规范取自“(假设”)实际参数的形状,根本不需要在子程序split
中进行形状计算。
使用具有假定形状伪参数的子例程需要显式接口,以便在引用过程的范围内访问过程。
这不可能。你只需要使用(n + 6) / 10
而不是m
。 Fortran不允许您在数组声明之前定义任何中间计算。
你甚至不需要一个常量(参数)只是一个变量就足够了。但这是不允许的。
事实上,这个问题与数组声明无关。以下简单的代码片段
subroutine split(n, x, r, v, p, t)
implicit none
integer, intent(in) :: n
double precision, intent(in) :: x(n)
integer :: m = (n + 6) / 10
end subroutine split
也不会编译。因此,即使将m
声明为变量,也无法通过(n + 6) / 10
表达式对其进行初始化。问题是(n + 6) / 10
不是一个常量表达式,因为它包含一个变量n
。
当然可以先声明变量m
,然后将(n + 6) / 10
表达式的值赋给它:
subroutine split(n, x, r, v, p, t)
implicit none
integer, intent(in) :: n
double precision, intent(in) :: x(n)
integer :: m
m = (n + 6) / 10
end subroutine split
例如,这可用于分配相应的数组(当然,必须声明为可分配的数组):
subroutine split(n, x, r, v, p, t)
implicit none
integer, intent(in) :: n
double precision, intent(in) :: x(n)
integer :: m
double precision, dimension(:, :), allocatable, intent(out) :: r
double precision, dimension(:, :), allocatable, intent(out) :: v
double precision, dimension(:, :), allocatable, intent(out) :: p
double precision, dimension(:), allocatable, intent(out) :: t
m = (n + 6) / 10
allocate (r(3, m-1))
allocate (v(3, m - 1))
allocate (p(3, m))
allocate (t(m))
! code
end subroutine split
以上是关于根据子例程参数创建常量的主要内容,如果未能解决你的问题,请参考以下文章