情報処理概論
第１０回

情報基盤研究開発センター

関数

谷本 輝夫

1

今回の内容

前回の課題 解答例



関数：台形積分2先週の課題プログラム例（1/3）
program Score_management
implicit none
integer :: i, j, total, number, kamoku
integer, dimension(:,:), allocatable :: score
integer, dimension(:), allocatable :: k_total
intrinsic dbleopen(10, file='score.dat')read(10, *) number, kamoku
allocate(score(number, kamoku))
allocate(k_total(kamoku))! Input score data
do i = 1, number
read(10, *) score(i, 1:kamoku)
end doclose(10)3先週の課題プログラム例（2/3）! Calculate total and averagek_total = 0
do i = 1, numberwrite(*,'(A3,I3,2X)', advance="NO") "No.",itotal = 0
do j = 1, kamoku
total = total + score(i, j)write(*,'(I4,3X)', advance="NO") score(i,j)
k_total(j) = k_total(j) + score(i,j)
end dowrite(*,'(I4,3X)', advance="NO") total
write(*,'(F6.1,1X)') total/dble(kamoku)
end dowrite(*,'(A7,1X)', advance="NO") "Average"
do j = 1, kamoku
write(*,'(F6.1,1X)', advance="NO") k_total(j)/dble(number)end dowrite(*,*)
stop4
end program Score_management

先週の課題プログラム例（3/3）$ cat score.dat
5 3
10 20 30
20 30 40
30 40 50
40 50 60
50 60 70
$ gfortran -o score score.f90$ ./score
No. 110203060
No. 2
2030
4090
No. 3
30
4050
120
No. 4
40
50
60
150
No. 5
50
60
70
180
Average
30.0
40.0
50.0
$

20.0
30.0
40.0
50.0
60.0

5

今回の内容

前回の課題 解答例

関数：台形積分6

今日の予習プログラム（1/3）
program sample3
implicit none
integer :: number1, number2
integer, dimension(:), allocatable :: english, mathreal(8), external :: average
intrinsic dbleopen(10, file="eng.dat")read(10, *) number1
allocate(english(number1))
call input_data(10, number1, english)
close(10)write(*, '(A20, F6.2)') "Ave. of English = ", &average(number1, english)open(11, file="math.dat")read(11, *) number2
allocate(math(number2))
call input_data(11, number2, math)close(11)7今日の予習プログラム（2/3）
write(*, '(A20, F6.2)') "Ave. of Math = ", &average(number2, math)stop
end program
subroutine input_data(file, n, a)
implicit none
integer, intent(IN) :: fileinteger, intent(IN) :: ninteger, dimension(n), intent(OUT) :: ainteger :: i
do i = 1, nread(file, *) a(i)end doend subroutine
8今日の予習プログラム（3/3）
function average(n, a)
implicit none
integer, intent(IN) :: ninteger, dimension(n), intent(IN) :: areal(8) :: average
integer :: i, total
intrinsic dble
total = 0
do i = 1, n
total = total + a(i)end doaverage = dble(total) / dble(n)end function9関数の定義
function 関数名(引数)implicit none
変数,関数の宣言（引数やこの関数自身の宣言も行う）... 計算 ...
関数名 = 式
end function

主プログラムの外で function ～ end function により定義



関数自身も変数として宣言する

関数と同名の変数に格納された値が「返り値」として呼び出し側に返される．

10

関数定義の例
名前

引数

function average(n, a)
implicit none
integer, intent(IN) :: ninteger, dimension(n), intent(IN) :: areal(8) :: average
integer :: i, total
intrinsic dble
total = 0
do i = 1, n
total = total + a(i)end do関数（の返り値）の宣言

関数内で用いる変数や関数の宣言

average = dble(total) / dble(n)end function

引数の宣言

返り値の計算,代入
11

関数の利用法

使用する関数の宣言
データ型名, external :: 関数名

関数の呼び出し

通常の関数と同じ

引数の順番に注意

関数からさらに他の関数を呼び出しても良い

呼び出し側の関数の中で，呼び出される側の関数の宣言が必要

12

関数利用の例
program sample3
implicit none
integer :: number1, number2
integer, dimension(:), allocatable :: english, mathreal(8), external :: average
intrinsic dble

使用する関数の宣言...

write(*, '(A20, F6.2)') "Ave. of Math = ", &average(number2, math)stop
end program

関数の呼び出し

引数13

intrinsic 関数と external 関数
intrinsic関数


Fortranの規格で定義されている組み込み関数



sin, cos, sqrt, dble 等

https://gcc.gnu.org/onlinedocs/gcc3.4.6/g77/Table-of-Intrinsic-Functions.html

external関数


プログラマが定義した関数

14

関数を使ったプログラム例：
台形積分のプログラム


台形積分

h = (b – a) / n
区間 [xi, xi+1) の積分を台形で近似

f(x)af(xi)

f(xi+1)f(xi+2)bn等分
x0 ... xi ... xn
xi = a + h × i

sixi

si+1
xi+1 xi+2
15

台形積分


1区間の面積si = (f(xi)+f(xi+1)) × h / 2


全区間の面積S = s0 + s1 + ... + sn-1
= (h / 2) × (f(x0)+f(x1)+f(x1)+f(x2)+f(x2)+f(x3)... +f(xn-1)+f(xn))= (h / 2) × (f(x0) + f(xn) + 2 ×(f(x1) + ... + f(xn-1))= (h / 2) × ( f(a) + f(b) + 2×(f(x1) + ... + f(xn-1) )16

台形積分プログラム（1/3）
program trapezoid
implicit none
integer, parameter :: n = 1000
integer :: ireal(8) :: start, end, s1, s2, hreal(8), external :: f, ff
write(*, *) "Start point? "read(*, *) start
write(*, *) "End point? "read(*, *) end
h = (end - start) / dble(n)s1 = 0.0D0
do i = 1, n-1
s1 = s1 + f(start + h * i)end dos1 = (s1 * 2.0D0 + f(start) + f(end)) * h / 2.0D017

台形積分プログラム（2/3）
write(*, '(A, F15.12)') 'Trapezoid: ', s1s2 = ff(end) – ff(start)
write(*, '(A, F15.12)') 'Integral:stop
end program

', s2

18

台形積分プログラム（3/3）
function f(x)implicit nonereal(8), intent(IN) :: xreal(8) :: fintrinsic sin
f = sin(x)end function
function ff(x)implicit nonereal(8), intent(IN) :: xreal(8) :: ff
intrinsic cos
ff = -1d0 * cos(x)end function

19

求根プログラム方程式を解くプログラム







＝求根プログラム

解析的な方法では解けない方程式がある。例えば
2𝑓𝑓 𝑥𝑥 = −𝑒𝑒 − 𝑥𝑥−1 + log 𝑥𝑥 + 𝑥𝑥
区間 (𝑎𝑎, 𝑏𝑏) に 𝑓𝑓(𝑥𝑥)=0 の解が1つあると考える。
すると𝑓𝑓(𝑎𝑎)と𝑓𝑓(𝑏𝑏)の極性（正負）が異なる。

𝑎𝑎と𝑏𝑏の中央を考える。𝑓𝑓 𝑥𝑥 = 0 の極性から解がどちらにあるか分かる
新しい（より狭い）区間 (𝑎𝑎, 𝑏𝑏) を決める事ができる区間が充分に狭くなるまで、繰り返すと解が求まる

20

課題


方程式を数値計算で解くプログラムを作成する

繰り返しは do while が向いている

𝑎𝑎と𝑏𝑏の区間が充分に小さくなったら終了
例えば |𝑎𝑎−𝑏𝑏| が0.01以下

絶対値の計算は関数 abs で解く方程式を関数として定義して用いる
関数の例

区間 (0, 1) で解を持つ
𝑓𝑓 𝑥𝑥 = 𝑥𝑥 3 + 𝑥𝑥 − 121