Fortran 中的隐式实数-复数转换

问题描述 投票:0回答:1

Fortran的新标准对于调用和过程定义之间的不匹配更加严格。然而,有很多遗留代码,例如,复数数组被视为实数的集合。通过将此类错误降低为警告,仍然可以正确编译。在

gfortran
中,它是通过
-fallow-argument-mismatch
实现的。这提供了一个临时的工作解决方案,但从长远来看并不令人满意。

program polymorphic_types_wrk
  use Maux_wrk
  implicit none
  integer, parameter       :: dp = kind(1.d0), dim = 10
  real(dp)                 :: wd(2 * dim)
  complex(dp)              :: wz(dim)

  call random_number(wd)
  call copy_real_complex_nonconformant(dim, wd, wz)
  
end program polymorphic_types_wrk

module Maux_wrk

contains
    subroutine copy_real_complex_nonconformant(dim, wd, wz)
    implicit none
    integer, parameter :: dp = kind(1.d0)
    integer, intent(in)     :: dim
    real(dp), intent(in)    :: wd(*)
    complex(dp), intent(out):: wz(*)

    call zcopy(dim, wd, 1, wz, 1)

  end subroutine copy_real_complex_nonconformant
  
end module Maux_wrk

在此示例中,

zcopy
标准 BLAS 子例程。目标是将实数数组复制到复数数组(假设数据是连续的)。根据
gfortran
文档,可以使用符合标准的解决方案:

强烈建议不要使用此选项。可以提供 符合标准的代码,允许不同类型的参数 使用显式接口和 TYPE(*)。

因此,我分别修改了代码,但它无法编译(假设类型参数

wd
需要显式接口):

program polymorphic_types
  use Maux
  implicit none
  integer, parameter       :: dp = kind(1.d0), dim = 10
  real(dp)                 :: wd(2 * dim)
  complex(dp)              :: wz(dim)

  call random_number(wd)
  call copy_real_complex(dim, wd, wz)
  
end program polymorphic_types

module Maux

contains
  subroutine copy_real_complex(dim, wd, wz)
    implicit none
    integer, parameter :: dp = kind(1.d0)
    integer, intent(in)     :: dim
    type(*), intent(in)     :: wd(..)
    complex(dp), intent(out):: wz(..)

    call zcopy(dim, wd, 1, wz, 1)

  end subroutine copy_real_complex
      
end module Maux

这让我很困惑,因为所有模块子例程都已经有一个显式接口。需要什么样的接口?

types fortran polymorphism
1个回答
0
投票

没有标准的一致方法将真实的实际参数与复杂的虚拟参数关联起来。 45 年前也是如此。

45 年来发生的变化是开发人员可以使用的工具来提供不合格参数不匹配的替代方案:首先是泛型,然后是多态性和 C 互操作性。编译器还降低了对故意违规的容忍度,并改进了对无意违规的诊断。

假定类型 (

type(*)
) 虚拟参数是 Fortran 2018 形式的多态性,特别适合 C 互操作性。这不是一种允许真正的实际参数与复杂的虚拟参数相关联的多态性形式。

首先回答一下缺少显式接口的错误。模块

copy_real_complex
中的子例程
Maux
确实在引用它的主程序中具有可用的显式接口(通过使用关联)。

但是,子例程

zcopy
中引用的子例程
copy_real_complex
在子例程中没有可用的显式接口。编译器抱怨 this 缺少显式接口。1

您需要将声明的复合体

wd
传递给
zcopy
。假定类型变量不是声明的复杂变量,即使它是动态复杂变量(如果其动态类型完全不同,当然也不是)。

如果您想让所有参数关联都兼容,那么您需要(以某种方式)将

wd
转换为复杂实体。这个答案是关于显式接口的需求/投诉,但您可以找到其他问题,例如this one关于如何进行该转换。有一些方法不会在类型匹配方面向编译器撒谎,但您可能会认为
-fallow-argument-mismatch
是可以接受的。

编译器文档关于使用

type(*)
允许编写符合标准的代码的注释是关于在这种情况下如何编写
zcopy
的。这不是关于应该如何编写 calls
zcopy
的内容。

有关实际示例,请参阅 MPI 的 Fortran 2008 绑定如何利用

type(*)
dimension(..)
。这些允许单个特定过程(例如
MPI_SEND
)获取任何类型和等级的缓冲区,并且不需要每个引用中具有相同的特征。

最后,对于问题的情况,类型不匹配对默认实数和复数如何存储进行了假设。 Fortran 标准对此存储提供了一些保证,但对非默认实数和非默认复数的存储的保证却少之又少。

如果你想避免

-fallow-argument-mismatch
,你将需要编写一致的代码,并且该一致的代码将需要 BLAS 的
zcopy
的实际参数变得复杂且不真实。一致使用复杂实体可能是一种方法,注意

call random_number(wz%Re)
call random_number(wz%Im)

不需要任何技巧。 CBLAS 还提供了一个对类型匹配不太挑剔的语言的接口。


1 虽然当我们查看 BLAS

zcopy
的定义时,没有任何东西 在引用时需要显式接口,但编译器不知道
zcopy
是什么样子。回想一下,“显式”和“隐式”接口不是过程本身的属性,而是关于引用该过程的地方已知的内容。

相反,编译器知道一致的调用意味着

zcopy

 具有多态虚拟参数:作为实际参数的变量 
wd
 是多态的,并且多态性的方式是它只能与默认参数关联,是多态的。多态虚拟参数需要显式接口。

模块

copy_real_complex_nonconformant

中的子程序
Maux_wrk
zcopy
的引用不会得出需要显式接口的类似结论。

© www.soinside.com 2019 - 2024. All rights reserved.