【问题标题】:Initialization of a Fortran parameter with intent(in) argument使用 intent(in) 参数初始化 Fortran 参数
【发布时间】:2019-07-20 20:21:37
【问题描述】:

考虑以下程序:

Subroutine foo(p,v)
  implicit none
  integer,                         intent(in)  :: p
  double precision,  dimension(p), intent(in)  :: v 

  !local variables
  integer,parameter :: n=floor(par(p))
  double precision  :: z(2*n)

[...]
End Subroutine

我收到以下错误:

Error: Array ‘v’ at (1) is a variable, which does not reduce to a constant expression

这很明确,但我想知道是否有办法管理这种情况:将子例程的 intent(in) 参数分配给参数变量?

【问题讨论】:

    标签: arrays fortran initialization parameter-passing


    【解决方案1】:

    不,那是不可能的。参数是一个编译时 常量。它的值不能来自任何参数或变量。

    也不清楚您为什么要这样做(请参阅https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。你确实需要一个参数来声明一个数组

    double precision :: z(2*floor(par(p)))
    

    因为在自动数组中,边界可以是过程参数。

    【讨论】:

    • 这样做是有原因的:告诉编译器某些依赖于函数参数的变量一旦设置就不允许修改。这是对编译器的提示,并导致更好的编程实践。毫不奇怪,这个exists in Ada
    【解决方案2】:

    您可以使用零长度变量来保存可以通过规范查询从中提取的中间结果。举个例子:

    module mod_par
       implicit none
       contains
          pure function par(x)
             double precision par
             integer, intent(in) :: x
             par = 1+sqrt(real(1,kind(par))+x)
          end function par
    end module mod_par
    
    module mod_foo
    !   use mod_par
       implicit none
       double precision par
       contains
          subroutine foo(p,v)
             implicit none
             integer p
             double precision v
             character(0) sv_i(floor(par(p)))
             character(floor(par(p))) sv_j(0)
             logical sv_k(floor(par(p)),0)
             type t
             ! Intentionally empty
             end type t
             type(t) sv_L(floor(par(p)))
             type u(len)
                integer, len :: len
             ! intentionally empty
             end type u
             type(u(floor(par(p)))) sv_m
             double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
    !         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
             write(*,*) shape(z)
          end subroutine foo
    end module mod_foo
    
    program bar
       use mod_par
       use mod_foo
       implicit none
       call foo(10,1.0d0)
    end program bar
    

    这在 ifort 和 gfortran 上都失败了,因为规范函数,这里是 par,必须是 PURE,并且它的接口必须是显式的。这里par,虽然PURE 有一个隐式接口,所以它被拒绝了。事实上,这两个编译器似乎都感到困惑:

    specvar.f90:21:25:
    
              character(floor(par(p))) sv_j(0)
                             1
    Error: Function 'par' at (1) has no IMPLICIT type
    

    对于 gfortran,ifort 说

    specvar.f90(31): error #6404: This name does not have a type, and must have an e
    xplicit type.   [PAR]
             type(u(floor(par(p)))) sv_m
    ----------------------^
    

    所以我们修复了这个编程错误...

    module mod_par
       implicit none
       contains
          pure function par(x)
             double precision par
             integer, intent(in) :: x
             par = 1+sqrt(real(1,kind(par))+x)
          end function par
    end module mod_par
    
    module mod_foo
       use mod_par
       implicit none
    !   double precision par
       contains
          subroutine foo(p,v)
             implicit none
             integer p
             double precision v
             character(0) sv_i(floor(par(p)))
             character(floor(par(p))) sv_j(0)
             logical sv_k(floor(par(p)),0)
             type t
             ! Intentionally empty
             end type t
             type(t) sv_L(floor(par(p)))
             type u(len)
                integer, len :: len
             ! intentionally empty
             end type u
             type(u(floor(par(p)))) sv_m
             double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
    !         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
             write(*,*) shape(z)
          end subroutine foo
    end module mod_foo
    
    program bar
       use mod_par
       use mod_foo
       implicit none
       call foo(10,1.0d0)
    end program bar
    

    但现在 gfortran 说

    specvar.f90:32:73:
    
              double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%l
    en,0)
                                                                             1
    Error: Variable 'sv_m' cannot appear in the expression at (1)
    

    还有:

    specvar.f90(31): error #6279: A specification expression object must be a dummy
    argument, a COMMON block object, or an object accessible through host or use ass
    ociation.   [SV_M]
             type(u(floor(par(p)))) sv_m
    --------------------------------^
    

    所以我没有足够新的编译器版本来支持类型参数查询。真可惜。所以我们摆脱了最后一点......

    module mod_par
       implicit none
       contains
          pure function par(x)
             double precision par
             integer, intent(in) :: x
             par = 1+sqrt(real(1,kind(par))+x)
          end function par
    end module mod_par
    
    module mod_foo
       use mod_par
       implicit none
    !   double precision par
       contains
          subroutine foo(p,v)
             implicit none
             integer p
             double precision v
             character(0) sv_i(floor(par(p)))
             character(floor(par(p))) sv_j(0)
             logical sv_k(floor(par(p)),0)
             type t
             ! Intentionally empty
             end type t
             type(t) sv_L(floor(par(p)))
             type u(len)
                integer, len :: len
             ! intentionally empty
             end type u
             type(u(floor(par(p)))) sv_m
    !         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
             double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
             write(*,*) shape(z)
          end subroutine foo
    end module mod_foo
    
    program bar
       use mod_par
       use mod_foo
       implicit none
       call foo(10,1.0d0)
    end program bar
    

    现在两个编译器都生成了很好的代码。所以你可以看到有很多方法可以在零长度自动变量的规范中保存一个临时整数变量,这些变量可以在进一步的规范表达式中使用。请注意,如果您对这种语法过于花哨,您会导致编译器崩溃很多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-24
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 2015-11-23
      • 1970-01-01
      • 2015-04-08
      相关资源
      最近更新 更多