首页 > 解决方案 > 编写一个接受任何两个数字(任何实数或任何整数)的函数

问题描述

我有一个接受两个数字的函数,我不在乎它们是整数、实数还是 32 位或 64 位。对于下面的例子,我只是把它写成一个简单的乘法。在 Fortran 90 中,您可以使用接口块来执行此操作,但如果您想涵盖将两个数字相乘的所有可能交互,则必须编写 16 个(!)函数,每个数字可以是 int32、int64、real32 或真实64。

使用 Fortran 2003,您还有其他一些选项,例如class(*)多态性,我找到了一种方法,只需在相乘之前将所有输入转换为实数:

! compiled on linux with gfortran 4.8.5

program main

   integer,   target :: i = 2
   real(4),   target :: x = 2.0
   real(8),   target :: y = 2.0
   character, target :: c = 'a'

   print *, multiply(i,x)
   print *, multiply(x,i)
   print *, multiply(i,i)
   print *, multiply(y,y) 
   print *, multiply(c,c)

contains

function multiply(p,q)

   real :: multiply
   class(*) :: p, q

   real :: r, s

   r = 0.0 ; s = 0.0

   select type(p)

      type is (integer(4)) ; r = p
      type is (integer(8)) ; r = p
      type is (real(4)) ;    r = p
      type is (real(8)) ;    r = p

      class default ; print *, "p is not a real or int"

   end select

   select type(q)

      type is (integer(4)) ; s = q
      type is (integer(8)) ; s = q
      type is (real(4)) ;    s = q
      type is (real(8)) ;    s = q

      class default ; print *, "q is not a real or int"

   end select

   multiply = r * s

end function multiply

end program main

这似乎是一种改进。至少这里的代码量在类型数量上是线性的而不是二次的,但我想知道是否还有更好的方法来做到这一点?如您所见,我仍然需要编写select type两次代码,将“r”更改为“s”,将“p”更改为“q”。

我试图将选择类型块转换为一个函数,但无法让它工作。但我对可以进一步改进的任何和所有替代方案感兴趣。看起来这将是一个常见问题,但到目前为止我还没有找到任何比这更好的通用方法。

编辑添加: 显然,正如@SteveLionel 的评论中所述,未来有计划改进 Fortran 这个问题。@roygvib 进一步提供了一个特定提案的链接,该提案也很好地解释了这个问题: https ://j3-fortran.org/doc/year/13/13-236.txt

标签: fortranfortran2003

解决方案


不是泛型的解决方案,而是“将选择类型块转换为函数”,以下代码似乎有效(如果包含一些非平凡的转换(?),这可能很有用)。

program main
    implicit none
    integer      :: i = 2
    real*4       :: x = 2.0
    real*8       :: y = 2.0
    character(3) :: c = 'abc'

    print *, multiply( i, x )
    print *, multiply( x, i )
    print *, multiply( i, i )
    print *, multiply( y, y )
    print *, multiply( c, c )

contains

function toreal( x ) result( y )
    class(*) :: x
    real :: y

    select type( x )
        type is (integer)      ; y = x
        type is (real(4))      ; y = x
        type is (real(8))      ; y = x
        type is (character(*)) ; y = len(x)
        class default          ; stop "no match for x"
    endselect
end

function multiply( p, q ) result( ans )
    class(*) :: p, q
    real :: ans
    ans = toreal( p ) * toreal( q )
end

end program

! gfortran-8 test.f90 && ./a.out
   4.00000000    
   4.00000000    
   4.00000000    
   4.00000000    
   9.00000000  

另一种方法可能只是将实际参数转换为实数(尽管它可能对更实际的目的没有用......)

program main
    implicit none
    integer   :: i = 2
    real*4    :: x = 2.0
    real*8    :: y = 2.0
    character :: c = 'a'

    print *, multiply( real(i), real(x) )
    print *, multiply( real(x), real(i) )
    print *, multiply( real(i), real(i) )
    print *, multiply( real(y), real(y) )
    ! print *, multiply( real(c), real(c) )  ! error

contains

function multiply( p, q ) result( ans )
    real :: p, q
    real :: ans
    ans = p * q
end

end program

推荐阅读