编译实值数组时出现类型错误。 Fortran 错误 #7113

Type error when compiling a real valued array. Fortran error #7113

我编写了以下函数来接收六个实值参数和 return 一个一维数组。

FUNCTION G(a, b, c, d, e, f)

    IMPLICIT NONE

    ! SPECIFICATION SECTION
    REAL,                 INTENT(IN)  :: a
    REAL,                 INTENT(IN)  :: b
    REAL,                 INTENT(IN)  :: c

    REAL,                 INTENT(IN)  :: d
    REAL,                 INTENT(IN)  :: e
    REAL,                 INTENT(IN)  :: f

    REAL, DIMENSION(1:3)              :: G
    REAL, DIMENSION(3,3)              :: T       
    REAL, DIMENSION(1:3)              :: H

    ! EXECUTION SECTION
    T = RESHAPE( (/1, 0, -sin(b), &
                   0, cos(a), sin(a)*cos(b), &
                   0, -sin(a), cos(a)*cos(b)/), &
                   (/3,3/) )
    H = (/d, e, f/)
    G = someOtherUnimportantFunction(H,T)

    ! SUBPROGRAM SECTION

END FUNCTION G

此函数无法编译并导致调用 RESHAPE 函数的行出现错误:

error #7113: Each ac-value expression in an array-constructor must have the same type and type parameters.   [COS]

此错误与上述文本共出现 5 个错误,但最后 4 个错误的末尾没有 [COS]。这个错误似乎表明 1s 和 0s 被解释为与三角函数不同的类型,事实上,如果我将 1s 更改为 1.0s 并将 0s 更改为 0.0s,函数编译正确。然而,这令人困惑,因为我在这个函数之上有许多类似的函数,它们具有类似的 RESHAPE 调用,除了角度的正弦和余弦之外,还有 1 和 0 的整数类型表达式。那些 RESHAPE 函数调用编译得很好。为什么这个 RESHAPE 调用有什么不同?

据我了解,之前的 RESHAPE 命令是将整数隐式类型转换为 REAL 值变量。为什么这种类型转换现在没有发生?

使用混合整数和 REAL 数据类型正确编译 RESHAPE 调用的示例:

U = RESHAPE( (/cos(j), 0,  sin(j), 0, 1, 0, -sin(j), 0, cos(j)/),(/3, 3/) )

U 是一个实数 3x3 数组,j 是一个实数角度。

从一些实验来看,上面观察到的 reshape(或更准确地说,在 reshape 函数内创建的临时数组)的行为似乎是某些特定版本的编译器的供应商扩展(也许是 ifort14?)。请比较下面 BC 的结果,这取决于所使用的编译器和版本。

! [compilers used]
! ifort 14 and 16 (both with an option '-standard-semantics')
! gfortran 4.8 and 7.1
! Oracle studio fortran 12.5
! PGI Fortran Community Edition 2017.4

program main
    implicit none
    real :: A( 3 ), B( 3 ), C( 3 )

    !-------------------------
    ! RHS = uniform integer array

    A = [ 1, 2, 3 ]    !! an integer temporary array is created for RHS and assigned to A (with integer -> real conversion)
    print *, [ 1, 2, 3 ]
    print *, "A = ", A

    ! gfortran: PASS
    ! ifort16 : PASS
    ! ifort14 : PASS
    ! oracle  : PASS
    ! pgi     : PASS

    !-------------------------
    ! RHS = [ real, integer, integer ]

    B = [ 1.1, 2, 3 ]
    print *, [ 1.1, 2, 3 ]
    print *, "B = ", B

    ! gfortran: Error: Element in REAL(4) array constructor at (1) is INTEGER(4)
    ! ifort16 : Error: If type specification is omitted, each element
    !                  in an array-constructor must have the same type
    !                  and kind type parameters. 
    ! ifort14 : PASS (*)
    ! oracle  : Error: All ac-value expressions in an array constructor
    !                  must have the same type and type parameters.
    ! pgi     : PASS (*)

    !-------------------------
    ! RHS = [ integer, real, integer ]

    C = [ 1, 2.2, 3 ]
    print *, [ 1, 2.2, 3 ]
    print *, "C = ", C

    ! gfortran: Error: Element in INTEGER(4) array constructor at (1) is REAL(4)
    ! ifort16 : Error: (same message as for B)
    ! ifort14 : Error: Each ac-value expression in an array-constructor
    !                  must have the same type and type parameters.
    ! oracle  : Error: (same message as for B)
    ! pgi     : PASS (**)

    ! The error message from ifort-14 is the same as that shown in the question.

end

结果:

!-------------------------
gfortran, ifort-16, oracle

      1         2         3
 A =  1.000000  2.000000  3.000000

 ! B and C => error

!-------------------------
ifort-14

      1         2         3
 A =  1.000000  2.000000  3.000000

      1.100000  2.000000  3.000000   (*)
 B =  1.100000  2.000000  3.000000   (*)

 ! C => error

!-------------------------
PGI
      1         2         3
 A =  1.000000  2.000000  3.000000    

      1.100000  2.000000  3.000000    
 B =  1.100000  2.000000  3.000000    

      1         2         3           (**)
 C =  1.000000  2.000000  3.000000    (**)

因此,在数组构造函数中不混合不同类型的元素可能更便于移植(即使某些编译器允许...)。

另一方面,如果我们将数组构造函数的(统一)元素类型指定为 [ real :: ... ](如评论中所建议),我们可以混合不同类型的元素,例如:

B = [ real :: 1.1, 2, 3 ]
print *, [ real :: 1.1, 2, 3 ]
print *, "B = ", B

C = [ real :: 1, 2.2, 3 ]
print *, [ real :: 1, 2.2, 3 ]
print *, "C = ", C

这给出(对于上面的所有编译器):

      1.100000  2.000000  3.000000
 B =  1.100000  2.000000  3.000000

      1.000000  2.200000  3.000000
 C =  1.000000  2.200000  3.000000

(*) 这种模式似乎只是宽松的并且没有什么害处,因为 integer 被转换为 real.

(**) 但我认为这种模式可能有问题(视情况而定),因为 real 隐式地 "down-converted" 到 integer (这可能不是程序员...)