跳轉到內容

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
華夏公益教科書