fortran - 编写一个接受任何两个数字(任何实数或任何整数)的函数
问题描述
我有一个接受两个数字的函数,我不在乎它们是整数、实数还是 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
解决方案
不是泛型的解决方案,而是“将选择类型块转换为函数”,以下代码似乎有效(如果包含一些非平凡的转换(?),这可能很有用)。
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
推荐阅读
- c++ - 无法通过 Linux 和 C++ 在串行通信中通过 read() 从设备接收消息
- java - 使用 xmlMapper (java) 反序列化 xml 时的问题
- elasticsearch - 应用排序字段后,弹性搜索结果得分为 0
- matrix - Power Bi 计算上个月的增长并在矩阵中显示
- swift - arkit 3d bodytracking 镜子倒置
- docker - 从 PgAdmin4 5.7 中的存储管理器下载文件时出错
- elasticsearch - 如何防止elasticsearch模糊搜索对重复词给出高分
- typescript - 将值数组映射到 Typescript 中的泛型类型
- python - 使用 jinja 2 变量更新 Yaml
- ruby-on-rails - Bundler 不会在 docker 上加载 puma