Arrays 初始化参数序列和参数数组之间有区别吗?

Arrays 初始化参数序列和参数数组之间有区别吗?,arrays,fortran,Arrays,Fortran,如果我要用嵌套括号来计算多项式,那么单独声明每个常量和将它们声明为数组之间是否有区别 例如,两者之间有区别吗 real(kind = c_double), parameter :: & P0 = .5, & P1 = .8, & P2 = -.1, & P3 = -.7, & P4 = -.4,

如果我要用嵌套括号来计算多项式,那么单独声明每个常量和将它们声明为数组之间是否有区别

例如,两者之间有区别吗

real(kind = c_double), parameter  :: &
            P0 =  .5,     &
            P1 =  .8,     &
            P2 = -.1,     &
            P3 = -.7,     &
            P4 = -.4,     &
            P5 = -.6, &
            P6 = -.2
和计算

x = ((((((P6 * a + P5) * a + P4) * a + P3) * a + P2) * a + P1) * a + P0)

和计算

x = ((((((P(7) * a + P(6)) * a + P(5)) * a + P(4)) * a + P(3)) * a + P(2)) * a + P(1))

是的,存在差异,但这些差异在您的使用中并不重要

不同之处在于,鉴于(与问题略有不同的)声明

real, parameter :: P1=0.1, P2=0.2, P(2)=[0.1,0.2]
P1
P2
是常数,但
p(1)
p(2)
不是常数
P
是一个常数,但这不是一回事。因此,
P1
可以在
P(1)
不能使用的某些情况下使用

然而,在以下表达式中:

((((((P6 * a + P5) * a + P4) * a + P3) * a + P2) * a + P1) * a + P0)
常量性质并不重要,
p
的元素也同样容易使用

在诸如复杂文字常量和文字常量中(对于整数)种类参数的情况下会出现差异。另外,由于
P(1)
是一个数组元素,它可以以一些不适合
P1
的方式使用


对于这个问题,我会注意到一些具体的事情:

  • 如果使用了
    P0
    ,数组可以从
    0
    索引:
    实数、参数、维度(0:6)::P=[…]
  • 该数组的一个优点是可以暗示元素的数量(在当前的Fortran中,不是F90):
    real,parameter,dimension(0:::P=[…]

我想指出,在常数表达式部分,标准说

常量表达式是…
(1) 常数常数或常数的子对象

那么在
p(1)
不能使用的地方,哪里可以使用
P1
?当然
P(1)
可以在
P1
不能使用的地方使用

在我看来,数组方法非常有吸引力,因为它更容易理解数组表达式——嵌套表达式中可能有一些不规则之处,读者可能会错过,但数组公式中没有:

program polyval
   use ISO_C_BINDING, only:C_DOUBLE
   implicit none
   integer, parameter :: wp = C_DOUBLE
   real(wp), parameter :: P(0:*) = &
      [0.5_wp,0.8_wp,-0.1_wp,-0.7_wp,-0.4_wp,-0.6_wp,-0.2_wp]
   real(wp) a, x
   integer i
   a = 10
   x = sum([(a**i*P(i),i=0,ubound(P,1))])
   write(*,*) x
end program polyval
编辑:我认为现在Fortran编译器可能足够聪明,可以识别上述多项式求值习惯用法,但显然我错了。我本以为

function poly1(x)
   use ISO_FORTRAN_ENV, only: wp=> REAL64
   real(wp) x
   real(wp) poly1
   real(wp), parameter :: P0 = 0.5_wp, P1 = 0.8_wp, P2 = -0.1_wp, &
      P3 = -0.7_wp, P4 = -0.4_wp, P5 = -0.6_wp, P6 = -0.2_wp
   poly1 = (((((P6*x+P5)*x+P4)*x+P3)*x+P2)*x+P1)*x+P0
end function poly1

将产生类似的代码,但是
gfortran-S-O3-ffast math-funroll循环poly2.f90
ifort/Fa/c/fast/Qipo-poly2.f90
计算
x
和有效的
DOT\u乘积的幂,而不是使用有效的方法。因此,为了在这种情况下获得合理的性能,可能需要编写类似于汇编的表达式,而不是编写高级语言

编辑:好的,似乎有一个上下文可以使用实数命名常量,但不能使用实数常量表达式

program test2
   use ISO_FORTRAN_ENV, only:wp=>REAL64
   implicit none
   complex(wp) x
   real(wp), parameter :: P1 = 4*atan(1.0_wp)
   real(wp), parameter :: P(1) = exp(1.0_wp)
   x = (P1,0)
   write(*,*) x
!   x = (P(1),0) ! Fails because literal or named constant is required
   write(*,*) x
end program test2
但是搜索标准我认为这是唯一的情况。是在f2003中,命名常量首先被允许出现在复杂的文字常量中吗?为完整起见,我提供了一个示例,其中常量表达式可以工作,但命名常量不能工作:

module mymod
   use ISO_FORTRAN_ENV,only:wp=>REAL64
   implicit none
   contains
      subroutine sub(x)
         real(wp) x(*)
         write(*,*) x(1)
      end subroutine sub
end module mymod

program test3
   use mymod
   implicit none
   real(wp), parameter :: P1 = 4*atan(1.0_wp)
   real(wp), parameter :: P(1) = exp(1.0_wp)
!   call sub(P1)  ! Fails because array actual argument required
   call sub(P(1)) ! Succeeds due to sequence association
end program test3

注意常量值的精度:您应该编写例如.1d0或.1_c_double,而不是。1@FrancoisJacq非常感谢。我在我的实际代码中这样做了。我不知道你是否真的在问
P(1)
不能使用的地方可以使用
P1
(它读起来是一个反问句,但你以后似乎没有提到),但是
P1
是一个常数,而
P(1)
不是。常量可用于常量表达式不可用的位置(如在
complex::z=(P1,0)
)中)。关于使用嵌套括号而不是幂运算符,它的实现比使用求幂或幂运算更有效。@francescalus我想有一个上下文需要实名常量,而不是常量表达式。然而,我似乎找不到另一个。当然,还有更多这样的上下文,其中需要一个名为常量的整数,而不是常量表达式,例如文本中的kind参数。如果我考虑过这一点,我可能已经得出了复杂的文字情况。@Avraham我的猜测是,现代Fortran编译器可以识别给定的用于计算多项式的习惯用法并进行相应的优化,但我无法让ifort或gfortran来支持我。TT
program test2
   use ISO_FORTRAN_ENV, only:wp=>REAL64
   implicit none
   complex(wp) x
   real(wp), parameter :: P1 = 4*atan(1.0_wp)
   real(wp), parameter :: P(1) = exp(1.0_wp)
   x = (P1,0)
   write(*,*) x
!   x = (P(1),0) ! Fails because literal or named constant is required
   write(*,*) x
end program test2
module mymod
   use ISO_FORTRAN_ENV,only:wp=>REAL64
   implicit none
   contains
      subroutine sub(x)
         real(wp) x(*)
         write(*,*) x(1)
      end subroutine sub
end module mymod

program test3
   use mymod
   implicit none
   real(wp), parameter :: P1 = 4*atan(1.0_wp)
   real(wp), parameter :: P(1) = exp(1.0_wp)
!   call sub(P1)  ! Fails because array actual argument required
   call sub(P(1)) ! Succeeds due to sequence association
end program test3