【发布时间】:2010-04-01 12:13:13
【问题描述】:
在 Fortran 中,有没有办法确定变量的类型?
需要变量类型的可能用例如下。我们将变量的类型作为参数传递给函数,以便能够使用该函数调用特定于类型的代码,从而无需为每种数据类型使用单独的类似函数。
【问题讨论】:
-
什么年份的 fortran? 77? 9倍? 200 倍?
在 Fortran 中,有没有办法确定变量的类型?
需要变量类型的可能用例如下。我们将变量的类型作为参数传递给函数,以便能够使用该函数调用特定于类型的代码,从而无需为每种数据类型使用单独的类似函数。
【问题讨论】:
如果你弄乱了 KIND 内在函数和指针,你也许可以做你想做的事,但如果你只关心函数和子例程的签名,那就把它留给 Fortran。如果你定义
function calc8(arg1)
real(8), intent(in) :: arg1
...
和
function calc4(arg1)
real(4), intent(in) :: arg1
...
在一个模块中,并声明一个这样的接口
interface calc
module procedure calc8
module procedure calc4
end interface
(警告,我没有仔细检查语法,这是你的责任。)
然后 Fortran 会将调用匹配到正确版本的函数。当然,您必须编写函数的两个版本,但这确实是 Fortran 95 的做法。这可能很乏味,我倾向于编写一个通用版本并运行一个 sed 脚本来专门化它。这有点杂乱无章,但确实有效。
如果函数的代码除了参数的种类之外是相同的,我有时会为 real(8)(或其他)编写函数并为 real(4) 编写一个版本,它调用 real(8) 版本的包装在类型转换中。
在 Fortran 2003 中,改进了定义多态和泛型函数的方法,但我还没有真正了解它们。
【讨论】:
是的,有两种方法。
第一种方法确实需要您为每种变量类型编写单独的函数或子例程,但您不必调用不同的函数。这可能与您想要的足够接近,也可能不够接近。您编写单独的例程,然后编写一个接口来创建一个通用函数或包装这些特定子例程的子例程。您不必传递变量类型,或者在调用中做任何特殊的事情——这一切都是通过声明完成的,并且由编译器自动从变量本身完成,只要变量足够不同,编译器可以区分他们(有关于需要什么的规则)。这类似于内部函数的工作方式——您可以使用实参数、双精度实参数或复数参数调用 sin,编译器会调用正确的实际函数并返回匹配的结果。 High Performance Mark 沿着这些思路提出了一个解决方案。对于另一个问题,我发布了一个工作示例,其中变量的显着特征是数组等级:how to write wrapper for 'allocate'。这种方法的一个优点是它得到了 Fortran 编译器的广泛支持。
在 Fortran 2003/2008 中,有很多面向对象的特性。引用 Metcalf、Reid 和 Cohen 的“Fortran 95/2003 解释”,“要根据多态实体的动态类型执行替代代码并访问动态部分,select type 构造是假如。” select type 语句有点类似于 select case 语句。这是由更少的编译器支持的。同样,您不必传递类型,因为编译器可以根据变量本身来计算它。但它必须是多态类型......英特尔 ifort 和 gfortran 都列出了支持的类型和多态数据类型——后者在 gfortran 中具有一些实验性方面 (http://gcc.gnu.org/wiki/Fortran2003)。这些是这些编译器的最新添加。
【讨论】:
这是一段代码,它决定了事物的类型。该操作很简单,但您应该能够将其扩展到您的用例。
module element_to_datatype
use iso_fortran_env
use mpi_f08
implicit none
contains
function get_element_datatype(element) result(datatype)
class(*), intent(in) :: element
type(MPI_Datatype) :: datatype
select type(element)
! REAL types
type is ( real(kind=REAL32) )
datatype = MPI_REAL4
type is ( real(kind=REAL64) )
datatype = MPI_REAL8
! COMPLEX types
type is ( complex(kind=REAL32) )
datatype = MPI_COMPLEX8
type is ( complex(kind=REAL64) )
datatype = MPI_COMPLEX16
! INTEGER types
type is ( integer(kind=INT8) )
datatype = MPI_INTEGER1
type is ( integer(kind=INT16) )
datatype = MPI_INTEGER2
type is ( integer(kind=INT32) )
datatype = MPI_INTEGER4
type is ( integer(kind=INT64) )
datatype = MPI_INTEGER8
! OTHER types
type is ( logical )
datatype = MPI_LOGICAL
end select
end function
end module element_to_datatype
之前的答案显示了如何使用接口执行此操作,因此我不会重复。
【讨论】: