Fortran/语言扩展
与其他几种语言一样,Fortran 90 及更高版本支持根据传递的参数从例程列表中选择适当的例程。此选择在编译时完成,因此不受运行时性能损失的影响。此功能可以通过使用模块和接口块来访问。
在以下示例中,指定了一个模块,该模块包含一个接口函数 f
,它可以处理各种类型的参数。
module extension_m
implicit none
private
public f ! Only the interface f is accessable outside the module.
interface f ! The overloaded function is called "f".
module procedure f_i ! "f(x)" for integer argument "x" will call "f_i"
module procedure f_r ! "f(x)" for real argument "x" will call "f_r"
module procedure f_z ! ... complex .... "f_z"
end interface
contains
integer function f_i(x) result (y)
integer, intent (in) :: x
y = x**2 - 1
end function
real function f_r(x) result(y)
real, intent (in) :: x
y = x**2 - 1.0
end function
complex function f_z(x) result(y)
complex, intent (in) :: x
y = x**2 - 1.0
end function
end module
现在,使用此模块的程序可以访问单个接口函数 f
,该函数接受整数、实数或复数类型的参数。函数的返回类型与输入类型相同。这样,该例程很像 Fortran 标准中定义的许多内在函数。下面给出一个示例程序
program main
use extension_m
implicit none
complex :: xz, yz
integer :: xi, yi
real :: xr, yr
xi = 2
xr = 2.0
xz = 2.0
yi = f(xi)
yr = f(xr)
yz = f(xz)
end program
可以扩展内在函数。这类似于重载运算符。
这里我们将通过扩展 sqrt
函数来演示这一点。内在函数没有为整数类型的参数实现。这是因为没有明确的想法如何定义非整数类型的结果(例如 ,但如何定义 )。我们在这里实现了一种方法,其中结果始终是最接近的整数。
module sqrt_int_m
implicit none
private
public sqrt
! use intrinsic sqrt for data types which are not overloaded
intrinsic :: sqrt
! extend sqrt for integers
interface sqrt
module procedure sqrt_int
end interface
contains
pure integer function sqrt_int(i)
integer, intent (in) :: i
sqrt_int = nint(sqrt(real(i)))
end function
end module
program main
use sqrt_int_m
implicit none
integer :: i
! sqrt can be called by real and integer arguments
do i = 1, 7
print *, "i, sqrt(i), sqrt(real(i))", i, sqrt(i), sqrt(real(i))
end do
end program
Fortran 90 及更高版本支持创建新的数据类型,这些数据类型是现有类型的组合。在某些方面,这类似于数组,但组件不必全部是相同类型,并且它们是通过名称而不是索引引用的。这种数据类型必须在该类型变量之前声明,并且声明必须在范围内才能使用。下面给出了一个简单二维向量类型的示例。
type :: vec_t
real :: x,y
end type
可以像声明其他任何变量一样声明此类型的变量,包括变量特征,如指针或维度。
type (vec_t) :: a,b
type (vec_t), dimension (10) :: vecs
使用派生数据类型,Fortran 语言可以扩展为表示比原始类型表示的更多样化的数据类型。
运算符可以重载,以便派生数据类型支持标准操作,从而有可能扩展 Fortran 语言,使其具有行为类似于本机类型的新类型。
赋值运算符 = 可以重载。我们将通过以下示例来演示这一点。这里,我们定义了如何在左侧逻辑类型和右侧整数之间执行赋值。
module overload_assignment_m
implicit none
private
public assignment (=)
interface assignment (=)
module procedure logical_gets_integer
end interface
contains
subroutine logical_gets_integer(tf, i)
logical, intent (out) :: tf
integer, intent (in) :: i
tf = (i == 0)
end subroutine
end module
program main
use overload_assignment_m
implicit none
logical :: tf
tf = 0
print *, "tf=0:", tf ! Yields: T
tf = 1
print *, "tf=1:", tf ! Yields: F
end program
可以重载内在运算符,如 +,-,*
。
在以下示例中,我们将重载 *
运算符以用作逻辑 .and.
。
module overload_asterisk_m
implicit none
private
public operator (*)
interface operator (*)
module procedure logical_and
end interface
contains
pure logical function logical_and(log1, log2)
logical, intent (in) :: log1, log2
logical_and = (log1 .and. log2)
end function
end module
program main
use overload_asterisk_m
implicit none
logical, parameter :: T = .true., F = .false.
print *, "T*T:", T*T ! Yields: T
print *, "T*F:", T*F ! Yields: F
print *, "F*T:", F*T ! Yields: F
print *, "F*F:", F*F ! Yields: F
end program
可以创建新的自创建运算符。
我们通过以下示例来演示这一点:我们创建了一个一元运算符 .even. <int>
,它在给定的 integer
为偶数时输出一个 logical
,以及一个二元运算符 <reals> .cross. <reals>
,它执行两个 real
向量的标准叉积。
module new_operators_m
implicit none
private
public operator (.even.)
public operator (.cross.)
interface operator (.even.)
module procedure check_even
end interface
interface operator (.cross.)
module procedure cross_product
end interface
contains
pure logical function check_even(i)
integer, intent (in) :: i
check_even = (modulo(i, 2) == 0)
end function
function cross_product(x, y) result(z)
real, intent (in) :: x(3), y(3)
real :: z(3)
z(1) = x(2)*y(3) - x(3)*y(2)
z(2) = x(3)*y(1) - x(1)*y(3)
z(3) = x(1)*y(2) - x(2)*y(1)
end function
end module
program main
use new_operators_m
implicit none
integer :: i
real :: x(3), y(3)
do i = 1, 6
print *, "i:", i, "even?", .even. i
end do
print *
x = [ 1, 2, 3]
y = [-1, 2, -3]
print *, 'x', x
print *, 'y', y
print *, 'x cross_product y', x .cross. y
end program