【问题标题】:Function return type mismatch函数返回类型不匹配
【发布时间】:2013-05-24 18:17:27
【问题描述】:

我正在尝试在 Fortran 中重新编码一个旧的 C++ 程序以使用 LAPACK(我知道 C++ 确实有 LAPACK++,但我在安装它时遇到了很多麻烦,所以我放弃了)。

我最初在编译时没有任何问题,但那时我将所有变量都声明为REAL。当我开始编写需要 LAPACK 的程序部分时,我发现传递给DSYEV 的所有参数都需要为DOUBLE PRECISION。所以我尝试将所有内容更改为双精度(包括将所有硬编码数字更改为双精度对应项,即 0.0 -> 0.0D0)现在当我尝试编译时,我得到的所有函数和子例程都出现以下错误写过:

    Error: Return type mismatch of function <function> at (1) (REAL(4)/REAL(8))

我不确定这是从哪里来的,因为程序中的所有内容都已更改为双精度。

例如,我声明了以下内容:

double precision :: alpha(3),d(3),zeta1,zeta2
double precision :: A1(3),A2(3),D1(3),D2(3)
double precision :: PI
PI = 3.14159265359D0
alpha = (/0.109818D0, 0.405771D0, 2.22766D0/)
d = (/0.444635D0, 0.535328D0, 0.154329D0 /)

do 10 i=1,3

A1(i) = alpha(i)*zeta1**2.0D0
A2(i) = alpha(i)*zeta2**2.0D0
D1(i) = d(i)*(2.0D0*A1(i)/PI)**(3.0D0/4.0D0)
D2(i) = d(i)*(2.0D0*A2(i)/PI)**(3.0D0/4.0D0)

10  continue

以及功能:

subroutine createS(S,A1,A2,D1,D2,r)
double precision A1(3),A2(3),D1(3),D2(3) 
double precision r
double precision S(2,2)
integer :: i,j
S(1,1) = 1.0D0
S(2,2) = 1.0D0
do 80 i=1,3
do 90 j=1,3

S(1,2) = S(1,2) + getS(A1(i),A2(j),r)*D1(i)*D2(j)

 90 continue
 80 continue
S(2,1) = S(1,2)
return
end

double precision function getS(a,b,r)
double precision :: PI
double precision a,b,r
double precision :: S
PI = 3.14159265359D0
S = (PI/(a+b))**1.5D0
S = S*dexp(-(a*b*r*r)/(a+b))
getS = S
return
end

然后我得到错误

  HFSTO3G.f:85.28:

  S(1,2) = S(1,2) + getS(A1(i),A2(j),r)*D1(i)*D2(j)                 
                        1
  Error: Return type mismatch of function 'gets' at (1) (REAL(4)/REAL(8))

我正在使用 gfortran 进行编译。这可能是问题吗?我对编程并不陌生,但对 Fortran 并不陌生。不使用 Fortran 进行编程不是一种选择。

【问题讨论】:

  • 还有其他用于 C++ 的库可以进行线性代数,只是提一个替代方案 :)

标签: fortran gfortran lapack double-precision


【解决方案1】:

你有没有把你的子程序和函数放到一个模块和use那个模块中?否则,可能发生的情况是您在子例程 createS 中将 getS 的隐式键入作为单精度实数,但它实际上返回双精度。另一个建议:总是使用implicit none 来查找未声明的变量。如果您忘记在源代码中包含implicit none,gfortran 会提供编译器选项-fimplicit-none。隐式输入是有害的,并且可能会在 Fortran 中继续支持遗留代码。

附: double precision 也已过时,但比隐式键入的风险要小得多。如果您有最新版本的 gfortran,您可以使用以下内容:

use ISO_FORTRAN_ENV
real (real64) ::

请参阅 gfortran 手册。

编辑:implicit none 将 getS 的类型从 real(4)(通过隐式键入)更改为 unknown(未声明类型,禁用隐式键入)。如果将过程放入模块中,它们将“知道”彼此的类型:函数返回和参数类型。这将修复此错误。它还可以帮助编译器找到其他错误,但使其能够检查调用和过程参数之间的参数的一致性。有关示例,请参见 Correct use of modules, subroutines and functions in fortranComputing the cross product of two vectors in Fortran 90

【讨论】:

  • 我确实在我的一个子例程中使用了隐式 none,但我只是将它添加到所有子例程和函数中,现在它给了我同样的错误,但不是 REAL(4)/REAL( 8) 关于错误,它给了我 UNKNOWN/REAL(8)
  • 我希望您现在遇到第二个错误,即 getS 在子例程 createS 中未声明。这是问题的线索。它需要输入为双精度......您可以通过将例程放入模块中自动获得。
【解决方案2】:

您没有将getS 声明为子例程createS 中的函数。您需要在子例程createS 的变量声明中添加double precision, external :: getS

【讨论】:

  • 我的意见:最好不要在现代 Fortran 中使用 external。如果该函数在 Fortran 中并且您有源代码,请将其放入一个模块并 use 该模块。如果它是另一种语言或者它在一个库中并且你没有源代码,那么为它写一个interface 语句。接口和模块都将为您提供参数一致性检查。使用 Fortran >=90 的许多“高级”功能需要显式接口。
  • 我同意 modern Fortran 的这一点,但 OP 似乎使用的是 F77,所以我使用了常见的方法。 (不过,如果 OP 发布 F90+,我可能会在子例程 createS 中推荐一个简单的 contains)。
  • 感谢这些 cmets。为什么不建议使用外部?
  • @SimonDirmeier:我认为MSB的评论已经足够了,但是您可以查看this link了解更多详细信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多