言語要素の概要2(cont'd)

配列(1次元)

配列(array)は,番号で添え字がつけられた,変数の列や行列のこと(perlやawkなどでは,添え字が数値でない連想配列というものも使える)

原理的には,あらゆる型の変数を配列にできる.

配列の宣言

いろいろなやり方があって混乱するかもしれないが,サイズ100の一次元配列を宣言するには次のようなやり方がある.

  !pattern1 : fortran90 only
real, dimension(1:100):: data1
real, dimension(100):: data1_b

  !pattern2 : fortran90 only
real :: data2(1:100)
real :: data2_b(100)

  !pattern 3
real data3(1:100)
real data3_b(100)

  !pattern 4
real data4
dimension(100) data4

FORTRANでは,配列の添え字の下限は,何も指定しなければ1である(Cの場合は0である.この辺の「文化」の違いは,移植に当たってずいぶんと大きな障壁になる).宣言に当たっては,添え字の範囲を「変数名(添字下限:同上限)」のように書くのだが,よほどのことがない限り下限は1なので「変数名(添字上限)」と書くことが多いであろう.

配列を構成するそれぞれの値を配列要素という.添え字下限が1のarrという配列の場合,最初の要素がarr(1),次がarr(2)...となる.n番目の要素は,変数nを用いてarr(n)とあらわせる.

配列の初期化

配列では,宣言と同時に値を与えてしまうことがよくある.これを初期化という.これまた実に多数のやり方がある.

  ! pattern1 : fortran90 only
integer, dimension(6) :: d = (/ 1, 2, 4, 8, 16, 32  /)

  ! pattern2 : fortran90 only
  !   so-called "do-type sequence"
  !   n_3_no_retsu and m_3_no_retsu will have same values
integer :: n_3_no_retsu(6) = (/ ( n, n = 3, 18, 3 )  /)
integer :: m_3_no_retsu(6) = (/ 3, 6, 9, 12, 15, 18  /)
  !  and also o_3_no_retsu will have the same
integer :: o_3_no_retsu(6) = (/ (3*n, n = 1, 6 ) /)

  ! another example of do-sequence
integer :: minus(-5:3) = (/ ( 100 - i * 4, i = 1, 9 /)

  ! pattern4 : classic type
integer beki(6)/ 1, 2, 4, 8, 16, 32 /
integer onaji(5)/5* 10 /             ! onaji(1)...onaji(5) has same

character*1 chara(10)/ 3*'1', 4*'2', 3*'A' /
logical     honto_uso(10)/ 5*.TRUE., 5*.FALSE. /

  ! pattern5 : classic type
real data1(10)
data data1 / 3* 4.0, 4* 3.14, 3* 2.718 /

一次元配列定数は,「(/」から「/)」の間に数字をずらずらと並べるか,次に述べるDO型並びを書く.

Do型並びというものが↑の例で始めて登場した.これは「(式,変数=初期値,終値[, ステップ値])」という形の表現で,変数をDO文の時と同じようにそれぞれ変えながら式の値を次々と計算していったその結果の値の並びを意味する.FORTRAN特有の表現方法である.

DATA文は昔からFORTRANにある変数の値指定方法で,スラッシュ(「/」)で囲んで変数の値の列をずらずらと書く.ただし「4*値」のように繰り返し回数を指定することもできる.

配列と代入:1

配列の各要素(a(4)など)への代入は,ただ単純に「a(4)=4.」のように行えばよい.この点では普通の変数と何ら変わりはない.

逆の代入もまた然り.「print *, 'value=', a(n)」「b(5)=c(3)

配列と代入:2

しかしながら配列には配列特有の代入方式がある.

部分配列について説明する.これは他の配列の一部分を取り出したものである.

部分配列の表現方法は「配列名(添字最初:添字最後:ステップ)」である.ただし最初も最後も省略することもでき,その場合は元の配列の添字下限・同上限となる.ステップも省略可能.

たとえば,a(5) = (/ 1, 2, 3, 4, 5 /)のとき,

これが一体どのように使われるかというと,このようになる.
integer:: a(10), b(5), c(20)

! all arrays is supposed to be already initialized

! all items in a = 0

a = 0

! copy b to part of a

a(2:6)  = b
a(6:10) = b(5:1:-1)

! copy part of b to part of a

b(2:4) = a(3:5)

! set 1 into odd number items in c

c(1:20:2) = 1

このように柔軟な配列の扱いができるのがFORTRANの特徴.

配列の演算

FORTRANの華は配列演算にあると言っても過言ではない.配列の演算はかなり楽である.また,コンパイラさえ性能がよければ並列演算時のパフォーマンスはかなり上がる.もっともこのコンパイラ任せというところが,パワープログラマに嫌われるところでもあるが…

配列要素間の演算は次のように行なう

real, dimension(10)    :: x, y, add, sub, div, mul, pow
real, dimension(5)     :: part
logical, dimension(10) :: logi

! x, y is supposed to be initialized here

add = x + y
sub = x - y
div = x / y
mul = x * y
pow = x ** 2.0

part = x(1:5) + y(3:7)

logical = ( x > 3.14 )

ただし一つ注意.積は行列積ではなくて単に配列の要素どうしをかけたその積である.

最後の式はちょっと面白くて,配列xのうち3.14より大きな要素について,logicalのその番号番目要素が.TRUE.になり,そうでない番号について.FALSE.になる.右辺を「マスク式」という.うまく使えばかなり強力.

配列の入出力

配列もreadprintで入出力できる.しかも,あまりDOループを使わなくても可能である.

まずは出力.

real    :: a(5)
integer :: i

! print all values in one line

print '(5F6.3)', a       !! all of a 
print '(3F6.3)', a(1:3)  !! a(1) to a(3)
print '(3F6.3)', ( a(i), i = 1, 3) !! ditto

print '(5F5.3)', ( a(i), i = 5, 1, -1) !! reverse order

このように,配列全体・部分配列・DO型並びを駆使すればDO文をつかわずにprintすることが可能である.

書式指定文字列を工夫すれば全ての要素を改行しながら出力することも可能.しかしそういう場合は無理せずDOループを使ったほうがみやすいことが多い.

do i = 1, 5
	print '(F5.3)', a(i)
end do

次に,入力.これは少し配慮が必要.

real    :: a(5)
integer :: i

! read some values

read *, a      ! 5 values

read *, a(1:3) ! 3 values

read *, ( a(i), i=1, 5) ! 5 values

このように書くと,例えば5個の数値を読むとき,一行に5個の数値を区切って書いて入力してもよいし,一行に1つの数値×5行でもよい.

ところが次のようにやると少し変わってくる.

do i = 1, 5
	read *, a(i) ! single value
end do

この場合は一回の読み込みでは一行だけ読み込まれる.その一行の最初の数値だけがa(i)に入る.二つ目以降は無視される.結構気づかないバグの温床.

このあたりの事情を,次のプログラムで試してみよう.


実行例(末尾部分)

read *, ( a(i), i=1, 5) : input as you like...
1 2 3 4 5 6 7
 1.000 2.000 3.000 4.000 5.000
 read a(1). input as you like...
1
 read a(2). input as you like...
2 3
 read a(3). input as you like...
4
 read a(4). input as you like...
5
 read a(5). input as you like...
6
Array is:
 1.000 2.000 4.000 5.000 6.000

の入力のところで(早まって?)入れた「3」が一切反映されていないことに注意.


AGATASHI