Инициализация параметра Фортрана с аргументом intent (in) - PullRequest
0 голосов
/ 27 февраля 2019

Рассмотрим следующую программу:

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) аргумент подпрограммы переменной параметра?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Вы можете использовать переменные нулевой длины для хранения промежуточных результатов, которые можно извлечь из них с помощью запросов спецификации.Время для примера:

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)

И ifort:

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

И теперь оба компилятора выдают хороший код.Таким образом, вы можете видеть, что существует много способов сохранить временную целочисленную переменную в спецификациях автоматических переменных нулевой длины, которые можно использовать в дальнейших выражениях спецификации.Обратите внимание, что если вы слишком увлечетесь этим синтаксисом, вы будете часто ломать компилятор.

0 голосов
/ 27 февраля 2019

Нет, это невозможно.Параметр является константой времени компиляции .Его значение не может быть получено из какого-либо аргумента или переменной.

Также не совсем понятно, зачем вам это делать (см. https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem).Вы не нуждаетесь в параметре для объявления массива

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

, потому что в автоматических массивах границы могут быть аргументами процедуры.

...