Fortran 虚拟过程中的接口不匹配';f';将函数传递给子例程时
我试图编写一个具有两个参数的子程序(用于最小化):Fortran 虚拟过程中的接口不匹配';f';将函数传递给子例程时,fortran,fortran90,Fortran,Fortran90,我试图编写一个具有两个参数的子程序(用于最小化): 任意长度的数组x 一种函数f,它接受该长度的数组并返回标量 示例模块: module foo contains subroutine solve(x, f) real, dimension(:), intent(inout) :: x interface real pure function f(y) import x real, dimension(size(x)), i
- 任意长度的数组
x
- 一种函数
,它接受该长度的数组并返回标量f
module foo
contains
subroutine solve(x, f)
real, dimension(:), intent(inout) :: x
interface
real pure function f(y)
import x
real, dimension(size(x)), intent(in) :: y
end function
end interface
print *, x
print *, f(x)
end subroutine
end module
测试程序:
use foo
real, dimension(2) :: x = [1.0, 2.0]
call solve(x, g)
contains
real pure function g(y)
real, dimension(2), intent(in) :: y
g = sum(y)
end function
end
gfortran在以下情况下失败:
call solve(x, g)
1
Error: Interface mismatch in dummy procedure 'f' at (1): Shape mismatch in dimension 1 of argument 'y'
如果我更改size(x)=>2
,那么它可以很好地编译(并运行)。如果我更改:=>2,它也可以正常工作。但这两种解决方案都不能满足我的需求
有什么办法可以做到这一点吗 那么:
interface
real pure function f(y)
real, dimension(:), intent(in) :: y
end function
end interface
当您将solve
参数传递给函数时,将自动传递数组的大小。您不需要将此部分作为界面的一部分。您有解决方案,但它值得一个解释。。。如果伪参数有一个显式接口(这里就是这样),那么就要求作为实际参数传递的过程的特征必须与伪参数的特征相匹配,除了纯粹性和基本本质之外。程序的特性包括其伪参数的特性,以及其他特性
伪参数的特征包括其形状等。如果该形状不是一个常数表达式,则特征包括“表达式中实体的精确依赖性”
伪参数f
的接口块声明数组的大小为size(x)
。x是一个与主机相关的假定形状变量-其大小在运行时可能会有所不同,因此size(x)
不是一个常量。因此,表达式及其实体成为伪参数的特征
模块过程g
声明数组的大小为2
。这显然是一个常数
不管f伪参数大小的非常量表达式的值是多少,这些数组大小特征(某种表达式与常量)都不匹配,因此会出现错误
用常数2替换SIZE(x)
时,特征明显匹配。当您将假定的形状x
更改为常量大小2时,那么size(x)
将成为值2的常量表达式-因为它是常量表达式,所有相关的都是它的值-因此两个参数的特征将匹配。当您将f
的伪参数和g
的伪参数都更改为假定形状(:)
,则特征匹配。如果您希望获得在您的解决方案注释中指出的安全性,您应该使用-fcheck=bounds
,编译器将为假定和延迟的形状数组生成运行时检查。有关-fcheck
的更多信息,请参阅gfortran手册页。但是,您将失去一些速度。下面是一个示例,演示如何传递可分配数组
一些提示:
- 使用模块避免繁琐的接口李>
- 将数组传递给实际函数时,添加额外的矩阵大小信息。例如
f(y,sizeinfo)
以便在实际函数中可以正确声明输入矩阵的大小。可分配数组可以传递给子例程solve
,因此可以使用子例程solve
中的大小(mat)获得大小
因此,更正后的版本如下所示:
module foo
contains
subroutine solve(x, f)
real, dimension(:), intent(inout) :: x
real,external::f
integer::sizeinfo
print *,'x=', x
sizeinfo = size(x)
print *, 'f(x)=',f(x,sizeinfo)
end subroutine
real function g(y,sizeinfo)
integer::sizeinfo
real, dimension(sizeinfo) :: y
g = sum(y)
end function
end module
以下是主要程序:
program main
use foo
real, dimension(2) :: x = (/1.0, 2.0/)
call solve(x, g)
end program
结果是:
x= 1.000000 2.000000
f(x)= 3.000000
恐怕也没有编译,有一个类似的错误:error:dummy procedure'f'中的接口不匹配(1):参数'y'中的形状不匹配
所有维度都应该是:
,同样在g(y)
函数中(否则你将混合显式和假定的形状数组),我想问题已经解决了!我希望通过在g(y)
中明确显示数组的大小来获得安全性,但这可能不太可能。这与另一个答案有相同的问题。传递子例程的意义在于可以传递任何子例程。外部设备陈旧、过时且容易出错。对同一模块中的函数使用external
来保存几行代码确实是一种糟糕的风格。更多信息,请参阅我之前的评论。但是,在这种情况下,您能举一个例子说明为什么外部容易出错,以及如果您有大量的子例程要调用该怎么办?你需要写很多的接口吗?为什么?编写一个接口,这些子例程都符合该接口。这就是重点!您编写一个库,库的用户编写传递的子例程。因此,它们不能在一个模块中,因为其他人编写了它们(即使最后两个人碰巧都是您)。如果有一个或几个callsub(sub,arg1,arg2)
,则您是对的。对不起,我不清楚,因为我真正想问的是如果有大量的callsubs
调用其他sub
s怎么办。此外,我仍然想知道为什么使用模块容易出错。我想知道是否有一个例子表明使用接口确实是一个好的实践。不,使用模块不容易出错,使用external
是!!!正如我告诉过你的,你可以很容易地用过程(sub)
替换外部
。一旦你这样做了,你就会意识到sub
作为一个接口,你可以在模块中有一个abstract interface
,而不是sub
,你就回到了以前的位置。