编写一个接受任何两个数字(任何实数或任何整数)的函数 [英] Writing a function that accepts any two numbers (any real or any integer)

查看:114
本文介绍了编写一个接受任何两个数字(任何实数或任何整数)的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a function that accepts two numbers and I don't care if they are integers or real or 32bits or 64bits. For the example below, I just write it as a simple multiplication. In Fortran 90 you could do this with an interface block, but you'd have to write 16 (!) functions if you wanted to cover all the possible interactions of multiplying two numbers, each of which could be int32, int64, real32, or real64.

对于Fortran 2003,您还有其他一些选项,例如class(*)用于多态,我发现了一种方法,可以通过简单地将所有输入转换为实数,然后乘以来实现这一目的.

With Fortran 2003 you have some other options like class(*) for polymorphism and I found one way to do this by simply converting all the inputs to reals, before multiplying:

! 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".

This seems like an improvement. At least the amount of code here is linear in the number of types rather than quadratic, but I wonder if there is still a better way to do this? As you can see I still have to write the select type code twice, changing 'r' to 's' and 'p' to 'q'.

我试图将选择类型块转换为函数,但无法正常工作.但是我对可以进一步改善这一点的所有替代方案都很感兴趣.看来这将是一个普遍的问题,但到目前为止,我还没有找到任何比这更好的一般方法.

I tried to convert the select type blocks into a function but couldn't get that to work. But I am interested in any and all alternatives that can further improve on this. It seems like this would be a common problem but I so far haven't found any general approach that is better than this.

编辑以添加:显然,有计划改进Fortranw.r.t.如@SteveLionel的评论中所述,将来会出现此问题. @roygvib进一步提供了指向特定提案的链接,该提案也很好地解释了该问题: https://j3-fortran.org/doc/year/13/13-236.txt

Edit to add: Apparently there are plans to improve Fortran w.r.t. this issue in the future as noted in the comment by @SteveLionel. @roygvib further provides a link to a specific proposal which also does a nice job of explaining the issue: https://j3-fortran.org/doc/year/13/13-236.txt

推荐答案

不是泛型的解决方案,而是对于将选择类型块转换为函数",以下代码似乎有效(如果有些琐碎的事情可能很有用)包含转换(?)).

Not a solution for generics, but for "converting the select type blocks into a function", the following code seems to work (which might be useful if some nontrivial conversion is included (?)).

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  

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

Another approach may be just converting the actual arguments to reals (although it may not be useful for more practical purposes...)

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

这篇关于编写一个接受任何两个数字(任何实数或任何整数)的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆