• 沒有找到結果。

Chapter 7 Subroutine ( 副程式 ) and Function Fortran

N/A
N/A
Protected

Academic year: 2022

Share "Chapter 7 Subroutine ( 副程式 ) and Function Fortran"

Copied!
23
0
0

加載中.... (立即查看全文)

全文

(1)

1

Fortran

Chapter 7 Subroutine (副程式) and Function

7-1 subroution

主程式:程式碼在程式一開始就自動會去執行。

副程式:不會自動執行自己的程式碼,它需要別人來”呼叫”它後,才會執行屬於自己的程式碼。

The general form of a subroutine is

subroutine subroutine_name ( argument_list)

……

(Declaration section)

……

(Execution section)

……

retrun

end subroutine_name

To call a subroutine, the calling program places a CALL statement in it’s code. The form of a call statement is

call subroutine_name ( argument_list)

where the order and type of the actual arguments in the argument list must match the order and type of the dummy argunemts declared in the subroutine.

Remark:副程式獨立地擁有屬於自己的變數宣告,若主程式與副程式用了同樣的變數名稱,那 它們仍然互不相關的,彼此之間不會有任何的關係。

(2)

Example:

Program ex0803 Implicit none integer :: A=1, b=2 call sub1()

write(*,*) ‘In main program:’

write(*, ‘(2(A3,I3))’’ ‘A=’, A, ‘B=’, B stop

end program ex0803 subroutine sub1() implicit none integer :: A=3, B=4

write(*,*) ‘In subroutine sub1:’

write(*, ‘(2(A3,I3))’’ ‘A=’, A, ‘B=’, B return

end

執行結果:

In subroutine sub1:

A=3 b=4

In main program:

A=1 b=2

Example:Asimple subroutine to calculate the hypctenuse of a right triangle.

subtoutine calc_hypotenuse( side_1, side_2, hypotenuse ) inplicit none

real, intent(in) :: side_1, side_2 real, intent(out) :: hypotenuse real :: temp

temp = side_1 ** 2 + side_2 ** 2 hypotenuse = sqrt(temp)

return

end subroutine

(3)

3

A test driver program fot subroutine calc_hyponteuse Program test_hypotenuse

implicit none real :: S1, S2 real :: hypot

write(*,*) ‘Program to test suubroutine calc_hypotenuse:’

write(*,*) ‘Enter the hength of side 1’

read(*,*) S1

write(*,*) ‘Enter the hength of side 2’

read(*,*) S2

call calc_hypotenuse(S1, S2, hypot) write (*,10) hypot

10 Format(1X, ‘The length of the hypotenuse is “’, F10.4) stop

end program test_hypotenuse

(4)

7-1-1 variable passing in Fortran : The pass-by-reference scheme

Fortran 在傳遞參數時,是傳遞這個變數的記憶體位址

Program test real :: a, b(4) integer :: next

……

call sub1(a, b, next)

……

end program test

subroutine sub1(x, y, i) real, intent(out) :: x

real, dimension(4), intent(in) :: y integer :: i

……

end subroutine

Example:Illustrating the effects of a type mismatch when calling a subroutine.

Program bad_call Implicit none real :: x = 1.0

call bad_argument(x) end program bad_call subroutine bad_argument(I) implicit none

integer ::i write(*,*) ‘I=’, i end subroutine

執行結果:I=106535321.6

Memory address

Main program

name

Subroutine name

001 a x 002 b(1) y(1) 003 b(2) y(2) 004 b(3) y(3) 005 b(4) y(4) 006 nest i 007

(5)

5

7-1-2 Passing arrays to subroutines

There are two possible approaches to specify the length of a dummy array in a subroutine

(1) pass the bounds of each dimension of the array to the subroutine as arguments in the subroutine call and to declare the corresponding dummy array to be that length.

Example:

Subroutine process1(data1, data2, n, nvals) integer, intent(in) :: n, nvals

real, intent(in), dimension(n) :: data1 real, intent(out), dimension(n) :: data2 do i = 1, nvals

data2(i) = 3.0 * data1(i) end do

return

end subroutine process1

(2) Declare the length of each dummy array with an asterisk as an assumed-size dummy array.

Example:

Subroutine process2(data1, data2, nvals) real, intent(in), dimension(*) :: data1 real, intent(out), dimension(*) :: data2 integer, intent(in) :: nvals

do i = 1, nvals

data2(i) = 3.0 * data1(i) end do

return

end subroutine process2

Not Good. Complier 無法偵測運算時,array 的大小是否超過實際 size.

(6)

7-2 save

The values of all local variables and arrays in a procedure become indefined when we exist the procedure.

SAVE: guarantee the local variables and arrays to be saved unchanged between calls to a procedure.

Example:

Subroutine running_average(x, ave, nvals, reset) Implicit none

real, intent(in) :: x real, intent(out) :: ave integer, intent(out) :: nvals logical, intent(in) :: reset

! List of local variables:

integer, save :: n real, save :: sum_x if (reset) then

n = 0; sum_x = 0.0; ave = 0.0; nvals = 0 else

n = n+1

sum_x = sum_x + x ave = sum_x / real(n) nvals = n

end if return

end subroutine running_average

(7)

7

7-3 Sharing data rusing modules

Example:

Program main Implicit none type :: mytype

……

……

end type mytype

……

……

stop

end program main

subroutine sub1() Implicit none type :: mytype

……

……

end type mytype

……

return

end subroutine sub1()

宣告 type 的型態

再一次宣告 type 的型態內容

(8)

主程式與 subroutine 皆需使用 mytype 的資料型態,上述方法較為繁雜,可以使用 module 來簡化 之:

module typedef Implicit none type :: mytype

……

end type mytype end module typefef program main use type def

… stop

end program main subroutine sub1() use type def

… return

end subroutine sub1

以 module 來儲存”全域變數”

Example:

Module vars implicit none real, save :: a, b, c end module vars

(9)

9

在程式中,使用上面這個模組的主、副程式,都可以使用到一樣的變數 a, b, c

Example:

Module constants implicit none

real, parameter :: pi=3.14159 real, parameter :: g=9.81 end module constants program main

use constants

……

stop

end program main subroutine sub1() use constants

……

return

end subroutine sub1

(10)

7-4 Fortran Functions

Two different types of functions : intrinsic functions and User_defined functions Intrinsic functions are built into the Fortran language

e.q. sin(x) and log(x)

The general form of a user_defined Fortran function is Function name (argument_list)

……

(Declaration section must declare type of name)

……

(Execution section)

……

name = expr return

end function [name]

The type declaration of a user_defined Fortran function can take one of two equivalent forms:

integer function my_function (i, j) or

function my_function (i, j) integer :: my_function

在函數結束之前,記得要把“函數 名稱"設定一個數值,這個數值會 傳回呼叫處

(11)

11

Example:

A function to evaluate a quadratic polynomial of the form quad(x)=ax2+bx+c real function quadf(x, a, b, c)

implicit none

real, intent(in) :: x, a, b, c quadf = a * x ** 2 + b * x + c return

end function

program test_quadf implicit none real :: quadf real :: a, b, c, x

write(*,*) ‘Enter quadratic coefficients a, b and c :’

read(*,*) a, b, c

write(*,*) ‘Enter location at which to evaluate equation :’

real(*,*) x

write(*,100) ‘quadf(‘, x, ‘)=’, quadf(x, a, b, c) 100 format(A, F10.4, A, F12.4)

stop

end program test_quadf

The function should never modify its own imput arguments.

(12)

7-5 Passing user_definited functions as arguments.

Example:

program test

real, external :: fun_1, fun_2 real :: x, y, output

……

call evaluate(fun_1, x, y, output) call evaluate(fun_2, x, y, output)

……

end program test

subroutine evaluate(fun, a, b, result) real, external :: fun

real, intent(in) :: a, b real, intent(out) :: result result = b * fun(a) return

end subroutine evaluate

(13)

13

7-6 Procedure interfaces and interface blocks

Interface between the function/subroutine and a calling program unit The general form of an interface is

interface

interface_body_1 interface_body_2

……

end interface

Each interface_body consists of the initial subroutine or function statement of the corresponding external procedure, the type specification statemts associated with its arguments, and an end subroutine or end function statement.

(14)

Example:

Program ex0815 Implicit none real :: angle, speed interface

function get_distance(angle, speed) implicit none

real :: get_distance

real, intent(in) :: angle, speed end function get_distance

end interface

write(*,*) ‘Input shoot angle:’

read(*,*) angle

write(*,*) ‘Input shoot speed:’

read(*,*) speed:

write(*, ‘(T2, A4, F7.2, 1A)’) ‘Fly’, get_distance(angle, speed), ‘m’

stop

end program ex0815

function get_distance(angle, speed) implicit none

real :: get_distance

real, intent(in) :: speed , angle real :: rad

real, parameter :: G=9.81

interface

function angle_to_rad(angle) implicit none

real :: angle_to_rad real, intent(in) :: angle end function angle_to_rad(angle) end interface

rad = angle_to_rad(angle)

get_distance = (speed * cos(rad)) * (2.0 * speed * sin(rad) / G) return

end function get_distance

(15)

15

function angle_to_rad(angle) implicit none

real :: angle_to_rad real, intent(in) :: angle real, parameter :: pi=3.14159 angle_to_rad = angle * pi / 180.0 return

end function angle_to_rad

Fortran 90 的標準並沒有嚴格限制一定要寫作 interface,但是在下面的情況之下,寫作 interface 是 必要的:

(i) 指定參數位置來傳遞參數時

(ii) 所呼叫的函式參數數目不固定時

(iii) 傳入指標參數時

(iv) 陣列參數沒有設定大小時

(v) 函數傳回值為陣列時

(vi) 函數傳回值為指標時

(16)

7-7 不定個數的參數傳遞

Fortran 90 中,我們可以用optional這個敘述來表示某些參數是”可以忽略的”

Example

Program ex0817 implicit none

imteger :: a=10, b=>0 interface

subroutine sub(a, b) implicit none

integer, intent(in) :: a

integer, intent(in), optional :: b end subroutine sub

end interface

write(*,*) ‘Call sub with arg a’

call sub(a)

write(*,*) ‘Call sub with arg a, b’

call sub(a, b) stop

end program ex0817

subroutine sub(a, b) implicit none

integer, intent(in) :: a

integer, intent(in), optional :: b write(*,*) a

if (present(b)) write(*,*) b return

end subroutine sub

Output:

Call sub with arg a 10

Call sub with arg a, b 10

20

函數 present 可以查看宣告成 optional 的參數是否有傳入,函數 present 的傳回值是邏輯值,如果有 使用 optional 這個敘述來表示

後面所宣告的參數可以不一定要 傳入

使用函數 present 來檢查參數b是否有傳入

(17)

17

7-8 Recursive procedures

副程式或是函數自己呼叫自己來執行,叫做”遞迴”

3! = 3×2!

2!

2! = 2×1!

1!

1! = 1×0!

0!

0! := 1

Example:

program ex0818 implicit none integer :: n, ans interface

subroutine fact(n, and) ← function fact(n) result(ans) implicit none

integer, intent(in) :: n integer, intent(inout) :: ans end subroutine fact

end interface

write(*,*) ‘Input N:’

read(*,*) n

call fact(n, ans) ← 省略 for function fact write(*, ‘(t2, i2, a3, i10)’) n, ‘!=’, ans ← fact(n)

stop

end program ex0818

(18)

recursive subroutine fact(n, ans) implicit none

integer, intent(in) :: n integer, intent(inout) :: ans integer :: temp

if (n<0) then ans>0 return end if

if (n>=1) then call fact(n-1, temp) ans = n * temp else

ans = 1 end if return

end subroutine fact

上述副程式可改用以下函數來寫作:

recursive function fact(n) result(ans) implicit none

integer, intent(in) :: n

integer :: ans ←宣告”ans”變數的型態也就等於宣告函數傳回值的型態

select case(n) case(0)

ans = 1 case(1)

ans = n * fact(n-1) ←改用 ans,而非 fact 來設定函數的傳回值 case default

ans = 0 end select return end function fact

Result 是用來指定一個變數來當成傳回 函數值的”替身變數”,e.q. 改成使 用”ans”來傳回函數的結果

副程式 fact 的一開頭就以 recursive 來 起頭,表示這個副程式可以遞迴地來被自 己呼叫

(19)

19

7-9 Contains statement

定義某些函式或副程式只能被某個特定的函式(或副程式)、或是只能在主程式中被呼叫。

Example:

module module_example implicit none

real :: x = 100.0 real :: y = 200.0 end module

program scoping_test use module_example implicit none integer :: i = 1, j = 2

write(*, ’(A25, 2I7, 2f7.1)’) ‘Beginning:’, i, j, x, y call sub1(i, j)

write(*, ’(A25, 2I7, 2f7.1)’) ‘After sub1:’, i, j, x, y call sub2(i, j)

write(*, ’(A25, 2I7, 2f7.1)’) ‘After sub2:’, i, j, x, y

contains ←

subroutine sub2 real :: x

x = 1000.0 y = 2000.0

write(*, ‘(A25, 2F7.1)’) ‘In sub2:’, x, y end subroutine sub2

end program scoping_test

Appears after the last excutable statement in program scoping_test. Only program

scoping_test can use this subroutine sub2.

(20)

subroutine sub1(i, j) implicit none

integer, intent(inout) :: i, j integer, dimension(5) :: array

write(*, ‘(A25, 2I7)’) ‘In sub1 before sub2 :’, i, j call sub2

write(*, ‘(A25, 2I7)’) ‘In sub1 after sub2 :’, i, j array = (/(1000*i, i = 1, 5)/)

write(*, ‘(A25, 2I7)’) ‘After array def in sub2 :’, i, j, array contains

subroutine sub2 integer :: i i = 1000 j = 2000

write(*, ‘(A25, 2I7)’) ‘In sub1 in sub2 :’, i, j end subroutine sub2

end subroutine sub1

Module_example x, y

Use Association

Program scoping_test

i, j local x, y from module

local subroutine sub2

i, j calling arguments

Subroutine sub1

i, j dummy arguments

local subroutine sub2

(21)

21

執行結果

Beginning 1 2 100.0 200.0

In sub1 before sub2: 1 2 In sub1 in sub2: 1000 2000 In sub1 after sub2: 1 2000

After array def in sub2: 1 2000 1000 2000 3000 4000 5000 After sub1: 1 2000 100.0 200.0

In sub2: 1000.0 2000.0

After sub2: 1 2000 100.0 2000.0

module 中還可以容納副程式,函數的存在,結構如下:

module module_name ← 建立一個新的 module

use prher_module_name ← module 中也可以使用別的 module implicit none

integer :: i ← 宣告告屬於 module 的變數,這些變數可以被

…… module 中的副程式使用

……

type :: type_name ← 宣告自訂型態,這個型態可以直接被 module

…… 中的副程式來使用

end type :: type_name

contains ← 要先加上 contains,再開始寫 module 中的副

subroutine sub1(a) 程式式或函數

……

end subroutine sub1 function fun1(b)

……

end function fun1 end module module_name

(22)

Example:

module constants implicit none

real, parameter :: pi = 3.14159 real, parameter :: g = 9.81 end module constants module calculate_distance

use constants contains

function argle_to_rad(angle) implicit none

real :: angle_to_rad real, intent(in) :: angle

angle_to_rad = angle * pi / 180.0 return

end function argle_to_rad

function get_distance(speed, angle) implicit none

real :: get_distance

real, intent(in) :: speed, angle real :: rad

rad = angle_to_rad(angle)

get_distance = (speed * cos(rad)) * (2.0 * speed * sin(rad) / g) return

end function get_distance end module calculate_distance program ex0820

use calculate_distance implicit none

write(*,*) ‘Input shoot angle:’

read(*,*) angle

write(*,*) ‘Input shoot speed:’

read(*,*) speed

write(*, ‘(T2, A4, F7.2, 1A)’) ‘Fly’, get_distance(angle, speed), ‘m’

(23)

23

7-10 Intrinsic, external

Datatype, external :: Func1, Func2

宣告 Func1 及 Func2 是程式中的函式名稱,而不是變數。

Intrinsic 則是用來宣告某個名詞所指的是庫存的函式。

real, intrinsic :: sin, cos

在實際寫作程式時,這兩個宣告可以省略,不過當我們要把函式名稱當成參數來傳遞到其它函式中 時,external 及 intrinsic 就不能省略

Example:

program ex0821 implicit none real :: A = 30.0

real, intrinsic :: sin, cos real, external :: trig_func write(*,*) trig_func(sin, A) write(*,*) trig_func(cos, A) stop

end program ex0821

function trig_func(func, x) implicit none

real :: trig_func real, external :: func real, intent(in) :: x

trig_func = func(x * 3.14159 / 180.0) return

end function trig_func

參考文獻

相關文件

Tseng, Growth behavior of a class of merit functions for the nonlinear comple- mentarity problem, Journal of Optimization Theory and Applications, vol. Fukushima, A new

Then, we tested the influence of θ for the rate of convergence of Algorithm 4.1, by using this algorithm with α = 15 and four different θ to solve a test ex- ample generated as

Numerical results are reported for some convex second-order cone programs (SOCPs) by solving the unconstrained minimization reformulation of the KKT optimality conditions,

Particularly, combining the numerical results of the two papers, we may obtain such a conclusion that the merit function method based on ϕ p has a better a global convergence and

Then, it is easy to see that there are 9 problems for which the iterative numbers of the algorithm using ψ α,θ,p in the case of θ = 1 and p = 3 are less than the one of the

By exploiting the Cartesian P -properties for a nonlinear transformation, we show that the class of regularized merit functions provides a global error bound for the solution of

Define instead the imaginary.. potential, magnetic field, lattice…) Dirac-BdG Hamiltonian:. with small, and matrix

These are quite light states with masses in the 10 GeV to 20 GeV range and they have very small Yukawa couplings (implying that higgs to higgs pair chain decays are probable)..