計算機プログラミング 後半組) - hiroshima universitycomputer programming(2nd half...
TRANSCRIPT
計算機プログラミング (後半組)
担当:城﨑知至
Instructor: Tomoyuki JOHZAKI
第7,8配列データ配列と配列の演算、動的割り付け等Lesson 7、8 Array data, operation, dynamic allocation
Computer Programming (2nd half group)
1
教科書6章
配列1
これまでの変数:スカラー型の変数(変数と数値や⽂字列が1対1対応)
数値計算やデータ処理では、多数(数百万 or more)のデータを使⽤する。すべてのデータに対して個別の変数を定義するのは現実的ではない。
配列型の変数• 数学における数列が変数に添え字をつけて区別
{a} = (a1, a2, a3, ・・・, an)するように、数字で区別した変数
• ⼀つの変数で多数のデータを扱うことができる。1次元配列: a = a(1), a(2), a(3), a(4),・・・, a(n)※ 変数名は⼀つであるが、その個々の要素 a(1)・・・a(n) が数値や
⽂字列を持つ。 ベクトル(1次元⾏列)や⾏列、x座標と関数値などなど・・
配列2
例1:3次元空間でのP点の座標(xp, yp, zp)1次元配列p(1:3)を⽤いて、
p = (p(1), p(2), p(3)) = (xp, yp, zp)
例2:3x3の正⽅⾏列
2次元配列A(1:3,1:3)を⽤いて、
333231
232221
131211
aaaaaaaaa
A
333231
232221
131211
aaaaaaaaa
aa(3,3)a(3,2)a(3,1)a(2,3)a(2,2)a(2,1)a(1,3)a(1,2)a(1,1)
配列データ1
4
配列:同じ型の1つまたは複数の配列要素=スカラー変数から構成されるデータ構造。同じ型の⼤量のデータ系列を扱う際に使⽤する。
• Fortranでは、配列名のままでのベクトル演算や、配列演算機能が豊富
配列の宣⾔
• 1つの配列名のデータ(配列要素=スカラー変数)はすべて同じ型となる。• 配列の添え字の範囲を ([下限:] 上限) で表す。• 上限 ≧ 下限• 上限・下限は整数型定数(or値の定まった名前付き整数定数)で与える。• 下限は省略可で、省略した場合は 1 となる。• ※ 例外的に変数で与えることができる場合もある text 6.3, 8.4章• ⼀次元配列では、配列要素の個数を⼨法という。• 多次元配列では、各次元の要素数を⼨法、総要素数を⼤きさという。
⼨法 = 上限値 ‒ 下限値 + 1
型, dimension([下限:] 上限) :: 配列名リスト型, :: 配列名([下限:] 上限), ・・・
配列データ2
5
配列 a は倍精度実数型の⼀次元配列で、下限は省略値1、上限は5、⼨法5各配列要素: a(1), a(2), a(3), a(4), a(5)
つまり、配列 a は5つの配列要素(スカラー変数)で構成される、倍精度実数型変数列である。
配列ch は、⻑さ3⽂字の⽂字型の⼀次元配列で、下限 0 , 上限 3 ⼨法 4各配列要素:ch(0), ch(1), ch(2), ch(3)
つまり、配列chは4個の配列要素(スカラー変数)で構成される、⽂字数3の⽂字型変数列である。
real(8), dimension(5) :: acharacter(LEN=3) :: ch(0:3)
⼀次元配列の具体例
配列データ3
6
配列 m は、整数型の三次元配列で、⼀次元⽬(⼀番左):下限 0 上限 3 ⼨法 3-0 + 1 = 4⼆次元⽬(⼆番⽬):下限 1 上限 2 ⼨法 2-1 + 1 = 2三次元⽬(三番⽬):下限 1 上限 2 ⼨法 2-1 + 1 = 2⼤きさ 4×2×2 = 16
つまり、配列mは36個の配列要素からなる整数型変数列である。配列要素 m(0,1,1), m(1,1,1), m(2,1,1), m(3,1,1),
m(0,2,1), m(1,2,1), m(2,2,1), m(3,2,1), m(0,1,2), m(1,1,2), m(2,1,2), m(3,1,2), m(0,2,2), m(1,2,2), m(2,2,2), m(3,2,2)
配列要素の⼀つ⼀つがスカラー変数で、それらをまとめた⼀つのデータ列が配列である。
integer, dimension(0:3, 1:2, 2) :: m
多次元配列の具体例
配列関数16.6 配列関数(text p. 80-82)
配列特有の組み込み関数が⽤意されている。必要に応じて参照してください。Program mainimplicit noneinteger,dimension(2,4) :: aa(1,:) =(/ 2, 3, 5, 1/)a(2,:) =(/ 0,-1, 4, 3/)
print ʻ(4i3)ʼ,a(1,:) ! 1次元⽬(ランク1)の値を出⼒print ʻ(4i3)ʼ,a(2,:) ! 2次元⽬(ランク2)の値を出⼒
!... size(配列名)配列aの”⼤きさ”をスカラー変数として出⼒print ʻ(“size1 =“,i3)ʼ,size(a)
!... size(配列名, 次元番号)配列aの指定した次元(ランク)のサイズ=⼨法をスカラー変数出⼒print ʻ(“size2 =“,i3,i3)ʼ,size(a,1),size(a,2)
!... shape(a)配列aの各次元(各ランク)の⼨法を配列として出⼒print ʻ(“shape =“,i3,i3)ʼ,shape(a)
stop ; end program main 実⾏結果
⼀次元配列
一次元配列データ1
9
配列の初期値設定
integer, dimension(5) :: m1 = (/1,2,3,4,5/)Integer :: m2(5) = [0,1,2,3,4]Integer :: n, m3(5)=(/(n**2,n=1,5,1)/)real(8) :: r8(5) = (/(sqrt(2.d0**n),n=0,8,2)/)character(LEN=5) :: ch(0:4) = (/”num01”,”num02”,”num03”, &
“num04”,”num05”/)
配列定数: (/定数1, 定数2, ・・・/) or [定数1, 定数2, ・・・] ※ 上記の⾓括弧は省略可の意味ではなく、この⾓括弧を使って定義する。
DO型反復: (/(データリスト, do変数=開始値、限界値 [, 増分値])/)※ 上記の⾓括弧は省略可の意味。増分値の省略値は1※ DO型反復記述を⾏う前に、do変数の整数型宣⾔をする必要がある。
※ 組み込み関数の利⽤も可能。
一次元配列データ2
10
配列の初期値設定
integer, dimension(5) :: m1 integer :: ninteger :: m2(5), m3(5)real(8) :: r8(5) character(LEN=5) :: ch(0:4)
m1 = (/1,2,3,4,5/) m2 = [0,1,2,3,4] m3 =(/(n**2,n=1,5)/)r8 = (/(sqrt(2.d0**n),n=0,8,2)/)ch = (/”num01”,”num02”,”num03” &
, “num04”,”num05”)
配列構造⼦: (/データリスト/)配列構造⼦を⽤いて型宣⾔後の本⽂中の代⼊⽂に配列構造⼦を使うことで定義することもできる。規則性がある場合は、doループでも可能。
integer, dimension(5) :: m1 integer :: ninteger :: m2(5), m3(5)real(8) :: r8(5)
do n=1,5m1(n) = n m2(n) = n-1m3(n) = n**2r8(n) = sqrt(2.d0**((n-1)*2))
end do
一次元配列演算1
11
部分配列:実⾏⽂中で、配列の⼀部分を宣⾔無しで配列として使⽤すること
配列名([添え字の開始値] : [添え字の限界値] [:添え字の刻み幅])
具体例integer :: m(1:5) = (/2,4,6,8,10/)
m(4: ) ! m(4:5:1)と同意で m(4), m(5)を参照 (/8,10/)
m( :2) ! m(1:2:1)と同意で m(1), m(2)を参照 (/2,4/)
m(1:5:2) ! m(1), m(3), m(5)を参照 (/2,6,10/)
m(5:1:-1) ! 逆順 m(5),m(4),m(3),m(2),m(1) (/10,8,6,4,2/)
m(3:3) ! m(3:3:1)と同意 (/6/)
※ m(3:3)は 配列 m の要素 m(3)を意味するのではなく、要素が1つの配列(/6/)である。
※ []を省略した場合、開始値は下限値、限界値は上限値、刻み幅は1となる。※ 刻み幅が負値の場合は、逆順に参照する。この場合、開始値≧限界値
ある配列の開始値から限界値まで刻み幅毎の配列要素で構成される配列
一次元配列演算2
12
単純変数(スカラー変数)と配列
integer :: m=0 ,n(0:2)=(/1,2,3/)具体例
上限と下限が等しい場合、a(3:3)、⼨法(要素数)1の⼀次元配列であって、配列要素(スカラー変数) ではない。
スカラー変数に配列を代⼊することは許されない。m = n(1:1)⽂法上の誤り
mはスカラー変数、n(1:1)は配列データの形状が異なるので代⼊できない。スカラー変数に配列を代⼊する場合は、配列要素 n(1)を⽤いる。
m = n(1) (両辺ともスカラー変数なのでOK)配列にスカラー変数を代⼊するのはOK
配列にスカラー変数を代⼊する場合は、その配列の配列要素すべてにスカラー変数を代⼊することになる。
n(1:1) = m OK 配列nの部分配列n(1:1)にm=0を代⼊するこの代⼊により、配列nはn(0:2)=(/1,0,3/)となる。
n = m n(0:2)=(/0,0,0/)n(0:2:2) = m n(0:2)=(/0,2,0/)
一次元配列演算3
13
配列型添え字
配列名 (添え字配列)
具体例
ある配列の要素を不規則に取り出す部分配列を、取り出す位置の添え字の値を要素とする別の配列(添え字配列)で指定することができる。
配列 a の要素a(-2), a(-1), a(2)を部分配列として取り出したい場合、開始値、限界値、刻み値では定義できないので、取り出したい要素位置(添え字)を要素とする配列 b を定義して、それにより部分配列を定義する。
直接数値を書き込んで定義することもできる。
重複指定 a((/-2, 0, -2/))は⽤いないようにする
integer :: a(-2:2) = (/1, 2, 3, 4, 5/)integer :: b(3) =(/-2,-1,2/) !添え字配列
a(b) = (/1, 2, 5/)
a((/-2, -1, 2/)) = (/1, 2, 5/)
一次元配列演算4
14
配列代⼊⽂
具体例
• 配列へのスカラー変数代⼊は、参照している配列要素全体にスカラー変数値が代⼊される。
• 配列同⼠の代⼊は、次元、⼨法のそろったもの同⼠でのみ可能
integer :: a(-2:2) = (/1, 2, 3, 4, 5/)integer :: b(3) =(/-2,-1,2/)Integer :: c = 0
a = c ! aの配列要素全部にc = 10を代⼊する a =(/0,0,0,0,0/)a(-2:0) = c ! aの部分配列a(-2:0:1)の要素にc=0を代⼊ a = (/0,0,0,4,5/)b = a(0:2) ! b(1)a(0), b(2)a(1), b(3)a(2) b = (/3,4,5/)a(-2:2,2)=0 ! a(-2)0, a(0)0, a(2)0 a = (/0,2,0,4,0/)
一次元配列演算5
15
配列演算式
具体例
• スカラー変数の場合と同様に、四則演算が可能。• 配列同⼠の演算は、次元、⼨法のそろったもの同⼠でのみ可能• 組み込み関数も利⽤可
Integer :: a(-2:2) = (/1,2,3,4,5/),b(5)=(/1,2,3,4,5/)
integer,dimension(5):: wa,sa,seki,sho,beki
real(8),dimension(5):: root
wa = a+b ! wa=(/ a(-2)+b(1), a(-1)+b(2), a(0)+b(3), a(1)+b(4), a(2)+b(5)/)=(/2,4,6,8,10/)
sa = a-b ! sa =(/0,0,0,0,0/)seki = a*b ! seki =(/1,4,9,16,25/)sho = a/b ! seki =(/1,1,1,1,1/)beki = a**b ! beki =(/1,4,27,256,3125/)root = sqrt(real(a)) ! root=(/1.000, 1.414, 1.732, 2.000, 2.236/)
※ wa = a+b <-> wa(:) = a(:) + b(:); 同意。 後者の⽅が配列演算であることが明確なので、⼈が⾒た際にわかりやすい
一次元配列演算6
16
ベクトル演算
具体例
• ベクトル演算ではすべての演算が⾒かけ上、同時に⾏われる。• Doループによる逐次(繰り返し順に、順番に⾏われる)演算とは異なる。
Integer :: a(1:5) = (/1,2,3,4,5/)
a(2:5) = a(1:4)do i=2,5
a(i) = a(i-1)end do
⼀⾒同じ演算のように⾒えるが結果は異なる。
a(1) a(2) a(3) a(4) a(5)
a(1) a(2) a(3) a(4) a(5)
各要素への代⼊が同時的に⾏われる。
a=(/1,1,2,3,4)
a(1) a(2) a(3) a(4) a(5)
① i=2 ② i=3 ③ i=4 ④ i=5
i = 2,3,4,5の順に代⼊が逐次的に⾏われる。
a=(/1,1,1,1,1/)
一次元配列演算7
17
配列の⼊出⼒
出⼒
Integer :: a(1:5) = (/1,2,3,4,5/)
print ‘(5I5)’, a(i),i=1,5 ! 1⾏に5個、整数型5⽂字幅でprint ‘(5I5)’, a ! 同上print ‘(5I5)’, a(i),i=5,1,-1 ! 逆順でprint ‘(5I5)’, a(1:5:2) ! 部分配列を出⼒print ‘(5I5)’, a(5:1:-2) ! 上の逆順で
do i = 1,5,1 ! i=1~5まで順に。1⾏に1要素ずつprint ‘(5I5)’, a(i)
end do
一次元配列演算8
18
配列の⼊出⼒
⼊⼒
Integer :: a(1:5) = (/1,2,3,4,5/)
read *,a
read *, (a(i),i=1,5)
• ⼊⼒は、1⾏に5個並べてもよいし、1⾏に1個でもよい。配列要素がすべて読み込まれるまで⾏われる。
• 要素数よりも多く書いた場合は、過剰分は無視される。
do i = 1,5
read *,a(i)
end do
• 1⾏につき1要素ずつ読み込む。• 複数個の数値を⼊⼒した場合は、最初の⼊⼒値のみが読み込まれ、
後ろのものは無視される。
複数個を1⾏に⼊⼒する場合は、⼊⼒値をスペースもしくはカンマで区切る
配列の動的割り付け1
19
動的割り付け:型宣⾔の段階では、配列の⼤きさを設定せず、プログラム本⽂中で配列サイズを指定する⽅法。
integer, allocatable :: a(:),b(:,:)
• 必要な配列サイズが事前に決まらない場合、型宣⾔でサイズ指定するには、想定される最⼤の配列サイズを指定する必要がある。不必要なメモリを確保することになる。
• これを避けるために、計算の中で必要なサイズを設定して必要メモリを確保し、計算が終わったら解除することで確保したメモリを開放する。
型宣⾔では、”allocatable”を加え、配列サイズは指定せず(:), 次元のみ定義する(上記の例では、aは⼀次元配列、bは2次元配列)
allocate(a(i1:i2:i3), b(j1:j2;j3,k1;k2;k3))
プログラム本⽂中で配列サイズが確定し、必要になったところでallocate⽂でサイズ指定する。Deallocate(a,b)
a, bの使⽤が終われば、割付を解除して領域開放する。
配列の動的割り付け2
20
動的割り付け:型宣⾔の段階では、配列の⼤きさを設定せず、プログラム本⽂中で配列サイズを指定する⽅法。
integer, allocatable :: a(:)Integer :: inum
・・・read(*,*) inumallocate(a(inum))read(*,*) a・・・deallocate(a)・・・
具体例事前にサイズが決まっていないデータ列を配列に読み込んで計算するような場合に使⽤できる。
サンプルプログラム:三角形の面積を求める
(線形代数 ベクトル演算の復習 3⾓形の⾯積を求めるプログラム)3次元x,y,z座標系における3点の座標をA(-1.0,0.0,1.5), B( 1.0, 0.5,-1.0), C(2.0,2.5,2.0)とし、この3点で囲まれた三⾓形の⾯積を求める。まず計算の⼿順を考える
1. 上記の3点の座標を⼨法3の1次元倍精度実数配列A, B, Cで定義する。2. ベクトルAB(AからBに向かうベクトル,以下同じ), ACを求め、⼨法3の1次元倍精度
実数配列AB, ACに代⼊する。3. 三⾓形の⾯積 =||AB×AC||/2 を計算し、スカラー倍精度実数Sに代⼊。
つぎにプログラムの流れを考える。Program⽂暗黙型宣⾔の無効化必要変数の型宣⾔ A, B, C, AB, AC, S (+ doループ変数 i)実⾏⽂
座標A, B, Cの定義配列A, B, C の初期値設定出⼒A, B, Cを⽤いてベクトルAB, ACを計算し、配列AB, ACに代⼊出⼒||AB×AC||/2を計算し、スカラー変数Sに代⼊出⼒
End program⽂プログラムの作成、コンパイル、実⾏・・・
Program Triangle ! Program⽂implicit none ! 暗黙の型宣⾔の無効化real(8),dimension(1:3) :: A,B,C,AB,ACreal(8) :: Sinteger :: i
!... 座標点の定義(⼨法3の1次元倍精度実数配列)A=(/-1.0d0, 0.0d0, 1.5d0/)B=(/ 1.0d0, 0.5d0,-1.0d0/C=(/ 2.0d0, 2.5d0, 2.0d0/)print ’(“ A =“,3(1x,1f7.1))’), Awrite(*,’(“ B =“,3(1x,1f7.1))’) Bwrite(*,’(“ C =“,3(1x,1f7.1))’)(C(i),i=1,3)
!... ベクトルAB, ACの定義(⼨法3の1次元倍精度実数配列)AB = B – A ! 配列演算AC = C – A ! 配列演算print *,write(*,’(“ AB =“,3(1x,1f7.1))’) ABwrite(*,’(“ AC =“,3(1x,1f7.1))’) AC
!... ||AB×AC||/2による⾯積の計算(倍精度実数スカラー変数)S = 0.5d0*sqrt( (ab(2)*ac(3)-ab(3)*ac(2) ) **2 &
+(ab(3)*ac(1)-ab(1)*ac(3) ) **2 &+(ab(1)*ac(2)-ab(2)*ac(1) ) **2 )
print *,write(*,’(“ S =“,1x,1f10.4)’) S
End program Triangle ! End program⽂
実行結果
演習
(線形代数 ベクトル演算の復習 4⾯体の体積を求めるプログラムの作成)3次元x,y,z座標系における4点の座標をA(-1.0,0.0,1.5), B( 1.0, 0.5,-1.0), C(2.0,2.5,2.0), D(3.0, 2.5, 3.0)とする。4点を頂点とする4⾯体の体積を求めるプログラムを作成&実⾏する。1. ⼨法3の1次元倍精度実数配列A, B, C, Dを準備し(型宣⾔)、上記4点の座標を初期値とし
て代⼊する。代⼊後、A,B,C,Dの値を1⾏毎に出⼒する。書式は、各点の名前を先頭に書き、x,y,zの3つの座標値を⼩数点以下3桁の実数形式(F型)で1列に並べて表⽰させる。
出⼒例 : A =␣␣-1.000␣␣␣0.000␣␣␣1.500
2. ベクトルAB(AからBに向かうベクトル,以下同じ), AC, ADを求め、⼨法3の1次元倍精度実数配列AB, AC, ADに代⼊し、その値を画⾯に出⼒させる(書式は1と同じ)。
3. ベクトルの外積AB×ACを求め、⼨法3の1次元倍精度実数配列ABCに代⼊し、その値を画⾯に出⼒させる(書式は1と同じ)。
余裕があれば、 AC×AD, AD×AB を求め、 , (AC×AD)・AB, (AD×AB)・AC による計算も⾏い、3次元ベクトルa,b,cに対して、(a×b)・c = (b×c)・a = (c×a)・b となることを確認せよ。
4. 4点A, B, C, Dを頂点とする4⾯体の体積を求めよ。求める4⾯体の体積は、ベクトルAB, AC, ADで張られる6⾯体の体積の1/6である2で求めたAD と3で求めたABCを⽤いて、(AB×AC)・ADの計算(6⾯体の体積)を⾏い、それを4⾯体の体積値に直し、倍精度スカラー変数V1に代⼊し、画⾯に出⼒させる(書式は1と同じ) 。
A
B
C
D
多次元配列1
25
多次元配列:
具体例
型, dimension(下限:上限, 下限:上限, ・・) :: 配列名リスト型:: 配列名(下限:上限, 下限:上限, ・・)のリスト
integer, dimension(0:3, 1:2, 2) :: m, nReal :: a(1:3,1:3), b(0:4,1:4, 1:4)
多次元配列要素の順番と構造多次元配列は、メモリ上には左の次元から順番に1次元的に記憶される。
3次元配列 a(3,3,3)の場合a(1,1,1)a(2,1,1)a(3,1,1)a(1,2,1)a(2,2,1)a(3,2,1)a(1,3,1)a(2,3,1)a(3,3,1)a(1,1,2)a(2,1,2)a(3,1,2)a(1,2,2)a(2,2,2)a(3,2,2)a(1,3,2)a(2,3,2)a(3,3,2)a(1,1,3)a(2,1,3)a(3,1,3)a(1,2,3)a(2,2,3)a(3,2,3)a(1,3,3)a(2,3,3)a(3,3,3)
1次元⽬ 2次元⽬・・最⼤7次元まで“rank”ともいう
多次元配列2
26
多次元配列要素の順番と構造多次元配列は、メモリ上には左の次元から順番に1次元的に記憶される。したがって、多重do ループによって多次元配列を使⽤する場合は、最内側のループに左の次元の変数を⽤い、外側に⾏くにつれ、右側の次元を回すようにした⽅が、⼀般にメモリアクセスが早い。
a(1,1,1) a(2,1,1) a(3,1,1) a(1,2,1)・・・a(1,1,2) a(2,1,2) a(3,1,2) a(1,2,2) ・・・a(1,1,3) a(2,1,3) a(3,1,3) a(1,2,3) ・・・
メモリ上データへの連続アクセス(早い)メモリ上データへの不連続アクセス(遅い)
do k = 1,3do j = 1,3do i = 1,3a(i,j,k) = ・・・sum = sum + a(i,j,k)
end doend do
end do
速いdo i = 1,3do j = 1,3do k = 1,3a(i,j,k) = ・・・sum = sum + a(i,j,k)
end doend do
end do
遅い
多次元配列3
27
a(3,3,3)に1,2,3,4,5,6・・・を⼊⼒する場合
do ループ⼊⼒:do k=1,3 ; do j=1,3 ; do i=1,3
a(i,j,k) = i + (j-1)*3 + (k-1)*9end do ; end do ; end do
多次元配列要素への数値の代⼊• 規則性がある場合は、1次元の場合と同様にdo ループによる⼊⼒が可能。• 1次元の場合と異なり、単純な配列構造⼦による⼊⼒はできない。 text p.78• 特定の次元のみに⾏うことは可能。
k=1, j=1 a(1,1,1) = 1, a(2,1,1) = 2, a(3,1,1) = 3k=1, j=2 a(1,2,1) = 4, a(2,2,1) = 5, a(3,2,1) = 6k=1, j=3 a(1,3,1) = 7, a(2,3,1) = 8, a(3,3,1) = 9k=2, j=1 a(1,1,2) = 10, a(2,2,2) = 11 a(3,2,2) = 12・・・
i が+1 1 増加
k が+1 9 増加j が+1 3 増加
多次元配列3
28
a(3,3,3)に1,2,3,4,5,6・・・を⼊⼒する場合
a(:,1,1) = (/1,2,3/) a(:,2,1) = (/4,5,6/)a(:,3,1) = (/7,8,9/)
多次元配列要素への数値の代⼊• 規則性がある場合は、1次元の場合と同様にdo ループによる⼊⼒が可能。• 1次元の場合と異なり、単純な配列構造⼦による⼊⼒はできない。 text p.78• 特定の次元のみに⾏うことは可能。
1次元的に配列構造⼦による⼊⼒
:: 2,3次元目を固定し、1次元目のみの部分配列に代入している。
多次元配列4
29
real::a(3,3),x(3),y(3),z(3)x = a(1,1:3) or a(1,:)y = a(2,1:3) or a(2,:)z = a(3,1:3) or a(3,:)
同次元、同⼨法の配列間演算• 配列の次元・⼨法がそろった配列間では、1次元の場合と同様に四則演算代⼊が可能。
2次元配列の部分配列を1次元配列に代⼊
異なる次元、⼨法を有する配列間の演算や代⼊• 部分配列を⽤いることで代⼊できる。
real :: a(3,3), b(3,3)real :: c = 1.0a = 10.b = a + a ; b = a – a ; b = a*a ; b = a/a; b = a**ab = a + c
real::a(3,3),x(3),y(3),z(3)x = a(1,:)+a(2,:)y = a(1,:)*a(3,:)/a(2.:)z = a(3,:)-a(:,3)
where, forall・・・割愛
6.5 WHERE⽂とFORALL⽂(text p.76-80)where⽂選別式によって分岐する。If⽂やif構⽂の配列バージョン。
配列に対して同時的に⾏う。( do ループ+if⽂を使った場合は逐次的になる)
real::a(100)・・・where (a < 0.0)a = 10.d0elsewhere (a > 1.0)a = -10.0end where
forall⽂ whereに対して、添え字範囲式が加えられたもの。配列に指標を書く必要がある。配列に対して同時的に⾏う。
real::a(100,100)・・・forall (i=10:90,j=40:50[, a(i,j)<0.0])a(i,j) = 0.d0
End forall判別式省略可
指標を必ず⼊れる
サンプルプログラム:転置行列を求める
332313
322212
312111
333231
232221
131211
,aaaaaaaaa
aaaaaaaaa
tAA
987654321
A
(線形代数 3×3の正⽅⾏列の転置⾏列を求めるプログラム)
• 3×3⾏列Aの転置⾏列を求め、配列B(3,3)に代⼊する。
• 整数変数を使⽤する。
計算の⼿順配列A(3,3)に3×3⾏列の各要素の値を代⼊する。Aの転置⾏列の各要素を配列B(3,3)に代⼊する。
プログラミングの⼿順Program⽂暗黙型宣⾔の無効化必要変数の型宣⾔ A, B + doループ変数 i,j実⾏⽂
⾏列Aの定義配列Aの初期値設定出⼒⾏列Aの転置⾏列の各要素を求め配列B代⼊出⼒
End program⽂プログラムの作成、コンパイル、実⾏・・・
Program transpose ! Program⽂implicit none ! 暗黙の型宣⾔の無効化integer,dimension(3,3) :: A,Binteger :: i,j
!... ⾏列Aの要素の配列Aへの代⼊A(1,:)=(/1,2,3/)A(2,:)=(/4,5,6/)A(3,:)=(/7,8,9/)print '(" A(1,:)=",3(1x,I1))', A(1,:)write(*,'(" A(2,:)=",3(1x,I1))') A(2,:)write(*,'(" A(3,:)=",3(1x,I1))') (A(3,i),i=1,3)
!... 転置⾏列の計算do j=1,3do i=1,3b(j,i) = a(i,j)end doend do
!... 結果の出⼒print *,print '(" B(1,:)=",3(1x,I1))', B(1,:)write(*,'(" B(2,:)=",3(1x,I1))') B(2,:)write(*,'(" B(3,:)=",3(1x,I1))') (B(3,i),i=1,3)
End program transpose ! End program⽂
332313
322212
312111
333231
232221
131211
,aaaaaaaaa
aaaaaaaaa
BA
添え字(i,j)を⼊れ替えたものが転置⾏列B⾏列の要素
実行結果
配列関数2
6.6 配列関数(text p. 80-82)配列特有の組み込み関数が⽤意されている。必要に応じて参照してください。
Program mainimplicit noneinteger,dimension(2,4) :: aa(1,:) =(/ 2, 3, 5, 1/)a(2,:) =(/ 0,-1, 4, 3/)
print '(4i3)',a(1,:)print '(4i3)',a(2,:)
print '("maxval =",i3)',maxval(a) ! 配列aの最⼤値 a(i,j)の値print '("maxloc =",i3)',maxloc(a) ! 配列aの最⼤値の位置(⼀⾏め i, ⼆⾏⽬ j)print '("minval =",i3)',minval(a) ! 配列aの最⼤値 a(i,j)の値print '("minval =",i3)',minloc(a) ! 配列aの最⼤値の位置(⼀⾏め i, ⼆⾏⽬ j)print *print '("maxval(1) =",i3)',maxval(a,1) !配列a(i,j)の各jに対する最⼤値(j=1,4まで4⾏)print '("maxloc(1) =",i3)',maxloc(a,1) !配列a(i,j)の各jに対する最⼤値の位置(⼀⾏めj=1、⼆⾏⽬j=2・・)print *print '("maxval(2) =",i3)',maxval(a,2) !配列a(i,j)の各iに対する最⼤値(i=1,2まで2⾏)print '("maxloc(2) =",i3)',maxloc(a,2) !配列a(i,j)の各iに対する最⼤値の位置(⼀⾏めi=1、⼆⾏⽬i=2・・)
print '(" sum =",i3)',sum(a) ! 配列の総和print '(" sum(1) =",i3)',sum(a,1) ! 第1次元⽅向の総和(j=1,2,3,4に対してi⽅向の総和)四⾏出⼒print '(" sum(2) =",i3)',sum(a,2) ! 第2次元⽅向の総和(i=1,2に対してj⽅向の総和)2⾏出⼒
stop ; end program main
a(1,:) =(/ 2, 3, 5, 1/)a(2,:) =(/ 0,-1, 4, 3/)
最大値の位置 i最大値の位置 j
最小値の位置 i最小値の位置 j
i j
i 方向の最大値(j=1)i 方向の最大値(j=2)i 方向の最大値(j=3)i 方向の最大値(j=4)i 方向の最大値の位置(j=1)i 方向の最大値の位置(j=2)i 方向の最大値の位置(j=3)i 方向の最大値の位置(j=4)
j 方向の最大値(i=1)j 方向の最大値(i=2)j 方向の最大値の位置(j=i)j 方向の最大値の位置(j=i)配列aの総和i 方向の和(j=1)i 方向の和(j=2)i 方向の和(j=3)i 方向の和(j=4)j 方向の和(i=1)j 方向の和(i=2)
配列組み込み関数を用いたプログラム例
テスト受験者の人数とスコアを入力し、平均値、標準偏差、偏差値
を求めるプログラム。
動的割り当てを使用
組み込み関数sumと配列演算を使用
Program average ! Program⽂implicit none ! 暗黙の型宣⾔の無効化integer :: num,ninteger,allocatable,dimension(:) :: Areal(8),allocatable,dimension(:) :: B,dvinteger :: totalreal(8) :: ave,sgm
!... ⼈数の⼊⼒write(*,*) " ⼈数は? Num ≦100"read(*,*) num
!... 配列サイズの設定(動的割り当て)allocate(A(num), B(num), dv(num))
!... 点数の⼊⼒do n=1,numwrite(*,*)n,"番⽬の⼈の点数を⼊⼒してください"read(*,*)A(n)
end do!... 合計、平均値の計算
total = sum(A)ave = total/num
!... 標準偏差の計算B(:) = (A(:)-ave)**2sgm = sum(B)sgm = sqrt(sgm/num)
write(*,'(" ⼈数=",I3," 平均=",1f7.2," 標準偏差=",1f7.2)') num,ave,sgm!... 偏差値の計算と、各⼈の点数と偏差値の出⼒
do n=1,numdv(n) = 10.*(A(n)-ave)/sgm + 50.write(*,'(1x,i3,"番⽬ 点数=",I3," 偏差値=",1f8.2)') n,A(n),dv(n)
end doEnd program average ! End program⽂
配列Bを⽤いなかった場合sgm = 0.d0do n=1,numsgm = sgm + (A(n) – ave)**2
end do
~N1i
iNA1
平均値
標準偏差
~N1i
iN2)(1 A
偏差値
50)(10
i
iAT
組み込み関数sumを⽤いなかった場合total = 0.d0do n=1,numtotal = total + A(n)
end do
演習
(線形代数 3×3⾏列の⾏列積を求めるプログラムの作成)3×3の⾏列A, Bの⾏列積ABを求め、3×3⾏列Cに代⼊し、結果を表⽰するプログラムを作成&実⾏する。
1. 3×3の2次元整数配列A, Bで定義し、上記の⾏列要素を初期値として代⼊する。代⼊後、Aの1⾏⽬、Aの2⾏⽬、Aの3⾏⽬、Bの1⾏⽬、Bの2⾏⽬、Bの3⾏⽬の値を1⾏毎に出⼒する。書式は、名前(”A(1,:)=”等)を先頭に書き、各⾏の3つの要素値を3桁の整数形式(I型)で1列に並べて表⽰させる。
出⼒例 : A(1,:) =␣␣1 ␣␣2␣␣3
2. do ループ(i,j,kの3重ループ)を⽤いて、A×Bの各要素(i,j)を計算し、3×3の3次元整数配列Cの要素(C(i,j))に代⼊する。
3. 代⼊後、Cの1⾏⽬、Cの2⾏⽬、Cの3⾏⽬の値を1⾏毎に出⼒する。書式は、1に同じ。
312131232
,432253321
BA
333231
232221
131211
333231
232221
131211
333231
232221
131211
bbbbbbbbb
aaaaaaaaa
ccccccccc
ABC
1,3kkjik
3ji32ji21ji1ij
ba
bababac
プログラム提出要領
38
前半(4⾯体の⾯積を求める)、後半(⾏列積を求める)演習で作成したプログラムを、メールに添付して城崎まで提出すること。• 講義時間内に終わらない場合は、どこまでできたのか、何が困難だったのか、
をメール本文に記載し、できたところまでで提出すること。
• きちんとした日本語で書くように心がける。
• 友人と相談した場合は必ず
「学籍番号b12**** の○○君と相談して取組みました。」
などをメール本文に書くこと。
• 同様に、ウェブサイトや書籍を参照した場合は、参考文献としてメール本文に提示すること。
課題提出期限:次回講義の前日まで
課題提出先: e‐mail: tjohzaki@hiroshima‐u.ac.jp課題提出時のメール件名 「計プロ180629_06_広大太郎」
出題日(西暦の”20”は省略すること)
氏名番号
講義で割り振られた2桁の個人番号