Professional Documents
Culture Documents
FORTRAN95_2003.indd 3
23.4.2007 12:48:23
Fortran 95/2003
Juha Haataja
Jussi Rahola
Juha Ruokolainen
Tieteen tietotekniikan keskus CSC
Tmn teoksen tekijnoikeudet kuuluvat CSC Tieteellinen laskenta Oy:lle. Teoksen tai osia siit voi kopioida ja tulostaa vapaasti henkilkohtaiseen kyttn sek Suomen yliopistojen ja korkeakoulujen kurssikyttn edellytten, ett kopioon tai tulosteeseen liitetn tm ilmoitus teoksen tekijst ja tekijnoikeuksista. Teosta ei saa myyd tai sisllytt osaksi muita teoksia ilman
CSC:n lupaa.
Fortran 95/2003
Esipuhe
Fortran on trkein ja kytetyin ohjelmointikieli numeerisessa laskennassa.
Fortran 2003 on kielen uusin standardi. Koska uuden standardin kaikkia
piirteit ymmrtvi kntji ei viel ole markkinoilla, keskitymme uuden
standardin siihen osajoukkoon, joka sisltyy Fortran 95 -standardiin.
Fortran 95 ja sit edeltnyt Fortran 90 -standardi kuvaavat aikaisempia Fortranin versioita monipuolisemman ohjelmointikielen, joka sislt modernit
ohjaus- ja tietorakenteet. Koska Fortran koki monilta osin perusteellisen
muodonmuutoksen, on varsin aiheellista esitell Fortran 95 kokonaan uutena ohjelmointikielen. Tss teoksessa on ksitelty erillisess luvussa siirtymist FORTRAN 77:st uuteen standardiin. kaikkia ominaisuuksia, vaan
ppaino on trkeimmiksi katsomillamme piirteill. Vanha Fortran-kielen
standardi (FORTRAN 77) muodostaa Fortran 95:n osajoukon, joten kieli on
yhteensopiva vanhojenkin koodien kanssa.
Lukijalta ei edellytet Fortran-kielen aiempaa tuntemusta, vaikkakin ohjelmoinnin perusksitteet on syyt tuntea. Fortran-kntjn kyttesimerkit
on esitetty Unix-ympristss, mutta Unixiin liittyvt yksityiskohdat on pyritty minimoimaan.
Tmn teoksen ensimminen painos ilmestyi vuonna 1996 ja kertoi aiemmasta Fortran 90 -standardista. Tss kirjassa kerrotaan posin Fortran 95
-standardista eli uuden Fortran 2003 -standardin osajoukosta. Erillisess luvussa on tiivis kuvaus Fortran 2003:n uusista piirteist. Lisksi esittelemme
lyhyesti rinnakkaisohjelmointia High Performance Fortran -kielell (HPF) ja
OpenMP:ll.
Teoksen syntyyn ovat vaikuttaneet kokemuksemme tieteellisen ja teknisen
laskennan asiantuntijatehtviss. Olemme valinneet kyttmmme nkkulman ja esitystavan tieteen tietotekniikan keskuksen CSC:n asiakasprojekteista kertyneiden kokemusten perusteella. Oma vaikutuksensa teokseen on
ollut aiemmin tuottamistamme kursseista ja julkaisuista saadulla palautteella. Suurimman osan tekstist on kirjoittanut Juha Haataja, joka mys
toimitti kirjan painokuntoon.
Kiitmme kaikkia kirjan sisltn vaikuttaneita tytovereitamme. Janne
Kontkanen antoi hyvi kommentteja oppikirjan ensimmisest raakaversiosta. Yrj Leino, Esko Jrvinen, Jari Jrvinen ja Peter Rback oikolukivat
teosta, mist heille kiitokset. Lisksi Jukka Korpela, Raija Kukkonen ja Markku Lindroos TKK:n atk-keskuksesta antoivat palautetta oppikirjan sisllst
Fortran 95/2003
ja esitystavasta. Erityisesti Jukka Korpelan kommentit ja parannusehdotukset auttoivat selkeyttmn teoksen sislt.
HPF: ksittelev luku perustuu Jussi Heikosen ja Janne Kontkasen kirjoittamaan artikkeliin. OpenMP:n esittely perustuu Jussi Heikosen kirjoittamaan artikkeliin. Kari Vasko osallistui Fortran 2003: esittelevn tekstin
aiemman version kirjoittamiseen. Olemme ottaneet mys huomioon CSC:n
jrjestmilt Fortran-kursseilta tulleen palautteen.
Toista painosta oikolukivat Tiina Kupila-Rantala, Yrj Leino ja Ville Savolainen. Kolmanteen painokseen listtiin ja laajennettiin muutamia harjoitustehtvi, ja samalla erit kirjan esimerkkej muokattiin numeerisesti stabiilimmiksi. Neljnness painoksessa keskitytn Fortran 95:een ja hahmotellaan uuden Fortran 2003:n sislt. Samalla joitakin virheit on korjattu
ja teksti stilisoitu. Erityiset kiitoksemme ansaitsee Robert Pich, jonka jrjestm Fortran-kurssi TTKK:ssa tuotti runsaasti palautetta ja korjausehdotuksia. Lisksi Janne Ignatius, Jussi Rahola ja Satu Tissari antoivat arvokasta
palautetta teoksen kolmatta painosta valmisteltaessa.
Otamme mielellmme vastaan kaikki thn kirjaan liittyvt kommentit. Ne
voi osoittaa Juha Haatajalle shkpostiosoitteeseen Juha.Haataja@csc.fi.
Toivotamme teoksen lukijoille lytmisen iloa sek antoisia hetki Fortranin
parissa.
Espoossa 24.4.2007
Tekijt
Sislt
Sislt
Esipuhe
12
12
13
14
Ohjelmoinnin perusksitteet
2.1
Mihin tarvitaan ohjelmointia . . . .
2.2
Tietokoneet ja ohjelmointi . . . . .
2.3
Mit tarkoitetaan tietokoneella . .
2.4
Ohjelmoinnin eri vaiheet . . . . . .
2.5
Ohjelman kntminen ja linkitys
2.6
Yhteenveto . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
16
16
17
17
18
19
21
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23
23
24
25
25
26
27
28
29
29
30
32
33
35
35
37
38
40
42
42
Ohjelman perusrakenne
4.1
Lhdekoodin muoto . . . . . . . . . . . . . . . . . . . . . . . . .
4.2
Fortranin merkkivalikoima . . . . . . . . . . . . . . . . . . . . .
4.3
Muuttujien ja vakioiden nimet . . . . . . . . . . . . . . . . . . .
44
44
45
46
.
.
.
.
.
.
.
.
.
.
.
.
Fortran 95/2003
4.4
4.5
4.6
5
47
48
49
Perustyypit
5.1
Perustyypit ja vakiot . . . . . . . . . .
5.2
Muuttujien mrittely . . . . . . . . .
5.3
Nimetyt vakiot . . . . . . . . . . . . .
5.4
IMPLICIT NONE ja alkukirjainsnt
5.5
Perustyyppien lajimreet . . . . . .
5.6
Esimerkki: sarjan summa . . . . . . .
5.7
Yhteenveto . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
51
51
53
54
55
56
60
63
Lausekkeet ja sijoituslauseet
6.1
Aritmeettiset lausekkeet . . . . . . .
6.2
Numeeriset standardifunktiot . . . .
6.3
Merkkijonolausekkeet . . . . . . . . .
6.4
Merkkitiedon ksittelyfunktioita . .
6.5
Merkkitieto ja taulukot . . . . . . . .
6.6
Loogiset lausekkeet . . . . . . . . . .
6.7
Esimerkkej loogisista lausekkeista
6.8
Merkkijonojen vertailu . . . . . . . .
6.9
Esimerkki: merkkijonojen lajittelu .
6.10 Sijoituslauseet ja laskentajrjestys .
6.11 Funktioiden sivuvaikutukset . . . . .
6.12 Operaattorien sidontajrjestys . . .
6.13 Yhteenveto . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
67
67
69
73
74
75
76
77
78
80
81
83
83
83
Ohjausrakenteet
7.1
Mihin tarvitsemme ohjausrakenteita . . . . .
7.2
Ehdollinen suoritus: IF-rakenne . . . . . . . .
7.3
Tapausten ksittely: SELECT CASE -rakenne
7.4
Toisto: DO-rakenne . . . . . . . . . . . . . . .
7.5
Esimerkki: Euklideen algoritmi . . . . . . . .
7.6
Poikkeusten ksittely . . . . . . . . . . . . . .
7.7
Hyppylause: GOTO-lause . . . . . . . . . . . .
7.8
Tiedonsiirron erikoistilanteet . . . . . . . . .
7.9
Yhteenveto . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
86
86
86
88
90
93
94
95
95
96
Funktiot ja aliohjelmat
8.1
Tehtvn jakaminen osiin . . . . . . . . . . . . . . . . .
8.2
Proseduurit, funktiot ja aliohjelmat . . . . . . . . . . .
8.3
Mihin proseduureja kytetn . . . . . . . . . . . . . . .
8.4
Funktioiden mrittely ja kytt . . . . . . . . . . . . .
8.5
Funktion otsikkolauseen muodot . . . . . . . . . . . . .
8.6
Funktion sivuvaikutukset . . . . . . . . . . . . . . . . . .
8.7
Aliohjelmien mrittely ja kytt . . . . . . . . . . . . .
8.8
Todellisten ja muodollisten argumenttien vastaavuus
8.9
Tiedon vlittminen proseduureihin . . . . . . . . . . .
8.10 Paikallisten muuttujien silyminen . . . . . . . . . . . .
8.11 Sisiset ja ulkoiset proseduurit . . . . . . . . . . . . . .
8.12 Rekursio . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
99
99
100
100
100
102
103
104
105
106
107
108
111
Sislt
8.13
8.14
8.15
8.16
8.17
8.18
8.19
8.20
8.21
8.22
Proseduurit argumentteina . . . . . . . . . . . . .
PURE-mre . . . . . . . . . . . . . . . . . . . . . .
ELEMENTAL-mre . . . . . . . . . . . . . . . . . .
Kutsumuodon mrittely . . . . . . . . . . . . . .
Esimerkki: NAG-aliohjelmakirjaston kytt . . .
Valinnaiset ja avainsana-argumentit . . . . . . .
Esimerkki: keskiarvon laskeminen . . . . . . . .
Milloin tarvitsemme kutsumuodon mrittely
Nkyvyysalueet . . . . . . . . . . . . . . . . . . . .
Yhteenveto . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
113
115
115
116
117
118
118
121
121
123
Moduulit ja operaattorit
9.1
Modulaarinen ohjelmointi . . . . . . . . . . . . .
9.2
Ohjelmayksikkjen vliset suhteet . . . . . . . .
9.3
Esimerkki: vakioiden mrittely . . . . . . . . . .
9.4
Esimerkki: pituusyksikkjen muunnokset . . .
9.5
Moduulin kyttminen toisista moduuleista . .
9.6
Julkisuus ja yksityisyys . . . . . . . . . . . . . . .
9.7
USE-lauseen eri kytttavat . . . . . . . . . . . .
9.8
Esimerkki: muunnosohjelma . . . . . . . . . . . .
9.9
Esimerkki: nollakohdan haku . . . . . . . . . . .
9.10 Moduulissa mritellyt globaalit muuttujat . .
9.11 Esimerkki: normaalijakautuneet satunnaisluvut
9.12 Geneeriset proseduurit . . . . . . . . . . . . . . .
9.13 Operaattoreiden mrittely . . . . . . . . . . . .
9.14 Yhteenveto operaattoreiden mrittelyst . . .
9.15 Funktioiden ja operaattorien kytttavat . . . .
9.16 Muita moduulien kyttmahdollisuuksia . . . .
9.17 Yhteenveto . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
126
126
127
128
128
131
131
133
134
135
137
138
140
142
147
147
148
148
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
152
152
155
158
159
159
161
11 Taulukot ja osoitinmuuttujat
11.1 Taulukoiden mrittely ja kytt . . . . . . . . . .
11.2 Taulukon alkioiden ksittely . . . . . . . . . . . . .
11.3 Taulukkoalustin . . . . . . . . . . . . . . . . . . . .
11.4 Taulukon alkioiden jrjestys . . . . . . . . . . . . .
11.5 Esimerkki: funktion arvojen talletus taulukkoon
11.6 Taulukoiden vlitys aliohjelmiin . . . . . . . . . .
11.7 Taulukkoarvoiset funktiot . . . . . . . . . . . . . .
11.8 Taulukkojen ksittely kokonaisuuksina . . . . . .
11.9 Taulukkojen ksittely standardifunktioilla . . . .
11.10 FORALL-rakenne . . . . . . . . . . . . . . . . . . . .
11.11 Dynaaminen muistinvaraus . . . . . . . . . . . . .
11.12 Esimerkki: Erastotheneen seula . . . . . . . . . . .
11.13 Osoitinmuuttujat . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
164
164
166
168
169
169
170
173
174
174
177
178
182
183
10 Rakenteiset tietotyypit
10.1 Rakenteisten tyyppien mrittely . . . . . .
10.2 Esimerkki: vektorilaskentamoduuli . . . . .
10.3 NULL-funktio . . . . . . . . . . . . . . . . . .
10.4 Julkisuus ja yksityisyys . . . . . . . . . . . .
10.5 Esimerkki: vektorimoduulin jatkokehittely
10.6 Yhteenveto . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
10
Fortran 95/2003
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
192
192
193
194
196
197
202
204
204
209
210
210
211
13 Standardiproseduurit
13.1 Standardiproseduurien perusksitteit
13.2 Standardiproseduurien kuvauksia . . .
13.3 Esimerkki: kellonaika ja pivmr . .
13.4 Esimerkki: satunnaisluvut ja kellonaika
13.5 Esimerkki: bittienksittelyoperaatiot . .
13.6 Esimerkki: data pakkaaminen . . . . . .
13.7 Standardifunktioiden erityisnimet . . .
13.8 Listietoja . . . . . . . . . . . . . . . . . .
13.9 Yhteenveto . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
215
215
216
218
219
226
227
229
230
231
14 Esimerkkiohjelmia
14.1 Nelilaskin . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.2 Datan lajittelu . . . . . . . . . . . . . . . . . . . . . . . . . .
14.3 Sokkelon tekeminen . . . . . . . . . . . . . . . . . . . . . .
14.4 Yksiulotteinen soluautomaatti . . . . . . . . . . . . . . .
14.5 Life-soluautomaatti . . . . . . . . . . . . . . . . . . . . . .
14.6 Binripuu . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.7 Sukupuu . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.8 Optimointitehtvien ratkaiseminen: evoluutiostrategiat
14.9 Lineaaristen yhtlryhmien ratkaisu . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
234
234
237
243
247
253
256
261
263
269
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
275
275
276
276
279
281
283
284
287
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
16 Fortran 2003
291
16.1 Fortran 2003:n trkeimmt lisykset ja parannukset . . . . . 291
16.2 Fortran 2003 ja olio-ohjelmointi . . . . . . . . . . . . . . . . . 295
Sislt
16.3
16.4
11
299
299
299
305
Liite
309
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
310
310
310
311
311
311
311
312
312
313
313
314
317
ASCII-merkist
324
Sanasto
325
Kirjallisuutta
329
Hakemisto
331
12
Fortran 95/2003
Teoksen sislt ja
merkinnt
Kerromme tss luvussa oppikirjan tarkoituksesta ja annamme neuvoja lukijalle. Kappaleesta 1.2 lydt kirjassa kytetyt merkinttavat.
1.1
Oppikirjan sisllst
13
-0.9589243
Jos jokin mrittelyn osa voidaan jtt pois, kytmme hakasulkumerkint ([]) seuraavaan tapaan:
funktio([argumentti][, argumentti]...)
Kolme pistett (...) tarkoittaa tss nolla, yksi tai useampi kertaa toistettavaa osaa. Seuraavat ovat esimerkkej edellisen merkinnn kuvaamista funktiokutsuista:
h()
14
Fortran 95/2003
h(a)
h(a,b)
h(a,b,c)
Tekstiss esiintyvt lyhenteet ja erisnimet on yleens kirjoitettu kuten Fortran. Uusien termien esittelyyn ja muutenkin tekstin korostamiseen on kytetty kursiivia.
Tmn oppikirjan Fortran 90 -kielisten esimerkkiohjelmien kntmiseen ja
testaamiseen on kytetty NAGWareTM f90 -kntj, joka on aito Fortran 90
-kntj eik sisll standardin ulkopuolisia laajennuksia. Ohjelmat on testattu mys Macintoshissa kytten Absoftin Fortran 90 -kntj. Fortran 95 -piirteit sisltvt ohjelmat on testattu Digital Fortran 95 -kntjll.
Oppaan neljnness painoksessa on kytetty kntjn Sun Studio 9 Fortran 95 -kntjn versiota 8.0, joka ei tue Fortran 2003:n uusia piirteit.
1.3
Listietoja
Tarjolla on mm. oppikirjan esimerkkiohjelmien lhdekoodeja, harjoitustehtvien ratkaisuja, mahdollisten painovirheiden korjauksia sek tietoa CSC:n
tarjoamista palveluista. Annamme mys viitteit muihin Fortrania ja ohjelmointia ksitteleviin www-palveluihin.
CSC:n www-kotisivu on osoitteessa
http://www.csc.fi
Hydyllisi Fortran-kielen ksikirjoja ovat teokset Fortran 95/2003 Explained [MRC04], Fortran 95 Language Guide [Geh96] ja Fortran 95 Handbook
[ABM+ 97]. Johdatukseksi kieleen sek oppikirjaksi sopivat teokset Introduction to Programming with Fortran [CS06] ja Fortran 90 Programming [EPL94].
Teos Programmers Guide to Fortran 90 [BGA94] on hyvin laaja ja monipuolinen johdatus Fortran-ohjelmointiin. Teos Migrating to Fortran 90 [Ker93]
sopii ohjenuoraksi vanhojen Fortran-koodien muuntamiseen uuden standardin mukaisiksi. Fortran 90:een perustuvaa F-kielt ksitelln teoksessa The
F Programming Language [MR96]. Artikkelissa The New Features of Fortran
2003 [Rei] kuvataan tiiviiss muodossa Fortran 2003:n uudet piirteet.
Fortran-standardeihin liittyvi dokumentteja lydt www-osoitteesta
http://www.nag.co.uk/sc22wg5/
Tietokoneohjelmissa kytettyj algoritmeja on esitelty mm. teoksissa Introduction to Algorithms [CLR90] ja Algorithms [Sed84].
CSC on tmn Fortran 95/2003 -oppikirjan lisksi julkaissut mm. matemaattista mallintamista ja numeerisia menetelmi ksittelevi teoksia:
15
16
Fortran 95/2003
Ohjelmoinnin
perusksitteet
2.1
2. Ohjelmoinnin perusksitteet
17
keskusmuisti
nppimist
keskusyksikk
kuvaruutu
tiedostot
Kuva 2.1: Tietokoneen toiminnan periaate.
Tietokoneen keskusyksikk toimii ohjelmakoodin sisltmien kskyjen mukaisesti. Ohjelma lukee tavallisesti joukon sytttietoja, jotka vaihtelevat ohjelman ajokerrasta toiseen. Ohjelma lukee sytttiedot sisn esimerkiksi
18
Fortran 95/2003
tiedostoista tai kyttjn nppimistlt. Sytttietoja voisivat olla esimerkiksi shavaintopisteist kertyt mittausarvot kuten lmptila, ilmanpaine
ja kosteus. Sennusteen laskemiseen kehitetty ohjelma voisi niden sytttietojen perusteella laskea ja tulostaa ennusteen seuraavien 48 tunnin ajaksi.
Tietokoneen keskusyksikk ksittelee keskusmuistissa sijaitsevaa dataa. Esimerkiksi sennusteen laskennan eri vaiheissa tarvittava data voidaan pit
tietokoneen keskusmuistissa. Keskusyksikk voi mys kirjoittaa ja lukea
tiedostoja, jotka mahdollistavat tiedon silyttmisen ohjelman suorittamisen loppuessa: kun ohjelman suoritus pttyy, kytetn vapautunut keskusmuisti seuraavien ohjelmien ajamiseen. Tt ennen tulee laskentatulokset tallettaa tiedostoihin, sill pysyvien tiedostojen sislt silyy ohjelman
suorittamisen loputtuakin. Tiedostojen ksittely on yleens hitaampaa kuin
keskusmuistin kytt.
Keskusyksikk voi tiedostoihin tallettamisen lisksi tulostaa tietoa kyttjn laitteen (ptteen, mikron tai tyaseman) kuvaruudulle. Tekstimuotoisen
tulostuksen lisksi tietokoneeseen voi olla kytkettyn graasten kuvaajien
piirtmiseen kykenevi laitteita.
2.4
Kun kehitt ohjelmistoa annettuun tehtvn, pid mieless seuraavat ohjelmoinnin vaiheet:
1. tehtvn tavoitteen mrittely
2. tehtvn analyysi ja ohjelmakoodin suunnittelu
3. ohjelmakoodin kirjoittaminen
4. testaaminen ja virheiden korjaaminen
5. dokumentointi
6. ohjelmiston kytt ja yllpitminen.
Tehtvn mrittelyss selvitetn tarkkaan, mit ohjelman tulisi tehd.
Mrittely kannattaa tehd huolellisesti, jottei koodia kirjoitettaessa tai testattaessa tarvitsisi huomata, ettei ohjelmisto ratkaise annettua tehtv.
Ohjelmoinnin trkein vaihe on tehtvn analyysi ja ohjelmakoodin suunnittelu. Ennen ohjelmakoodin kirjoittamista tytyy selvitt mm. ohjelmassa kytetyt tietorakenteet ja algoritmit. Thn vaiheeseen kannattaa kytt
runsaasti aikaa pienesskin tehtvss. Suunnitteluun kytetty aika saadaan
yleens runsain mitoin takaisin ohjelmakoodin kirjoittamisessa ja testaamisessa. Tehokas ja luotettava ratkaisumenetelm mys vhent ohjelman
korjailemiseen tarvittavaa aikaa.
2. Ohjelmoinnin perusksitteet
19
20
Fortran 95/2003
f90 -c ali.f90
f90 -c ohj.f90
f90 -o ohj ali.o ohj.o -lnag
./ohj
lhdekoodi
INCLUDE-tiedostot
kntj
tarvittaessa
knnslistaus
moduulit
objektikoodi
aliohjelmakirjastot
linkittj
tarvittaessa
linkitystaulu
ajettava
ohjelma
Kuva 2.2: Ohjelman kntmisen ja linkittmisen vaiheet. Moduuleja esitelln
luvussa 9 ja INCLUDE-lausetta kappaleessa 4.5.
2. Ohjelmoinnin perusksitteet
21
2.6 Yhteenveto
Ohjelmointia tarvitaan tietokoneen kaikkien toimintojen ohjaamiseen.
Trkein ohjelmoinnin vaihe on tehtvn analyysi ja ohjelmakoodin suunnittelu.
Muista mys ohjelmakoodin testaaminen virheiden lytmiseksi.
22
Fortran 95/2003
Harjoitustehtvi
1. Mik on ohjelmointikielen kntjn tehtv?
2. Kokeile kappaleessa 1.2 (sivu 13) esitetyn ohjelmakoodin kntmist
ja ajamista kytettvisssi olevalla laitteistolla.
3. Muuta edellisen tehtvn ohjelmakoodia siten, ett se tulostaa luvun
x nelijuuren SQRT(x). Syt ohjelmalle negatiivinen luku. Mit tapahtuu?
23
Johdatus ohjelmointiin
Fortran 95:ll
Esittelemme trkeimmt Fortran 95 -ohjelmointikielen piirteet yksinkertaisten esimerkkien avulla. Alussa kerromme lyhyesti Fortran-kielen merkityksest ja historiasta. Luku kannattaa silmill lpi, vaikka Fortran-kielen vanhemmat versiot olisivat tuttuja. Esiteltvt asiat kydn yksityiskohtaisemmin lpi myhemmiss luvuissa.
24
Fortran 95/2003
3.2
25
Tm ohjelmakoodi koostuu kolmesta rivist, joista kullakin on yksi Fortranin lause. Lauseessa esiintyvt tunnukset erotetaan toisistaan vlilynneill.
WRITE-lauseen sisentmiseen on kytetty vlilyntej, jolloin koodi on selkempi lukea.
PROGRAM-lause antaa ohjelmalle nimen, ja END PROGRAM -lause lopettaa ohjelmayksikn suorituksen. WRITE-lausetta kytetn tulostukseen. Merkint
7*52 tarkoittaa kertolaskua ja merkki + yhteenlaskua. Lause WRITE (*,*)
7*52 + 1 tulostaa laskutoimituksen 7 52 + 1 tuloksen kuvaruudulle.
Kun olemme kirjoittaneet tmn ohjelmakoodin tiedostoon laskut.f90,
26
Fortran 95/2003
3.5
Tunnusten nimeminen
Edellisess esimerkiss aloitettiin pohjelma PROGRAM-lauseella. Ohjelmakoodi lopetettiin lauseella END PROGRAM. Jokaisessa ajokelpoisessa ohjelmassa on vain yksi pohjelma.
Ohjelman tunnus oli ensimmisess esimerkiss laskuesimerkki. Tunnuksen pituus saa olla korkeintaan 31 merkki, ja tunnukseen kelpaavat kirjaimet A . . . Z, alaviiva _ sek numerot. Nm snnt koskevat kyttjn
mrittelemien tunnusten lisksi mys Fortranin omia tunnuksia.
Tss oppaassa kytetn itse mritellyiss tunnuksissa pieni kirjaimia.
Fortran-kielen kannalta nimet lasku, Lasku ja LASKU ovat identtisi, mutta
pienet kirjaimet parantavat koodin luettavuutta. Fortran 95 -standardi ei
ehdottomasti vaadi, ett kntj hyvksyisi pienet kirjaimet, mutta kaikki
kntjt nyttvt sen tekevn.
Tunnusten nimien on syyt olla jrkevi ja helposti ymmrrettvi. Tunnusten nimeminen on osa ohjelman dokumentointia! Esimerkiksi jos tunnuksen nimi viittaa eri asiaan kuin mihin tunnusta kytetn, aiheuttaa tm
sekaannuksen vaaran.
27
Tietokone laskee rellisell tarkkuudella. Tss tapauksessa tuloksen tarkkuus on noin kuusi desimaalia, vaikka ohjelma tulostaa kahdeksan numeroa.
Reaalikuluvakiot erotetaan kokonaisluvuista desimaalipisteen avulla. Reaaliluvut voi esitt mys eksponenttiesityksen avulla:
WRITE (*,*) 0.52E2/0.7E1
tulostaa seuraavaa:
52.0/7.0 =
7.4285712 , 52/7 = 7
Siis kokonaislukujen jakolaskun 52/7 tulos on mys kokonaisluku, ja murtoosa jtettiin huomiotta. Tarkista siis aina jakolaskun argumenttien tyypit!
Jos jakolaskun argumenteista toinen on reaalilukutyyppi, on tuloskin reaaliluku. Siten lausekkeen 52.0/7 arvoksi saadaan 7.4285712.
Sulkumerkkej ( ja ) voi kytt laskutoimitusten ryhmittelyyn:
WRITE (*,*) 52.0/7.0 + 1.0, (52.0/7.0)+1.0, 52.0/(7.0 + 1.0)
8.4285717
6.5000000
Koska jakolasku suoritetaan ennen yhteenlaskua, ovat edell kaksi ensimmist lauseketta identtiset, joten sulkujen kytt ei siis ole vlttmtnt.
Kolmannessa lausekkeessa ovat sulut vlttmttmt, muuten lausekkeen
tarkoitus muuttuu.
Merkkijonovakiot voi esitt joko yksinkertaisilla lainausmerkeill (tyyliin
28
Fortran 95/2003
3.7
Muuttujat
Huutomerkill (!) alkavat rivit ovat kommentteja ja ne on tarkoitettu ohjeeksi ohjelman lukijalle ja kyttjlle. Mrittely IMPLICIT NONE parantaa
kntjn tekemi virheentarkistuksia. Se on syyt laittaa jokaiseen ohjelmayksikkn otsikkolauseen (PROGRAM tms.) jlkeen. Tm lause poistaa
kytst tunnuksen ensimmiseen kirjaimeen perustuvan tyyppimrittelyn, josta kerrotaan tarkemmin kappaleessa 5.4 (sivu 55).
Ohjelmassa mritelln kokonaislukumuuttujat i ja j rivill
INTEGER :: i, j
29
READ (*,*) i
Luku n: 3
3.9 Sijoituslauseet
Edellisess ohjelmassa luimme tietoa muuttujiin k, x ja n sek tulostimme lausekkeen k*x**n arvon. Yleens tarvitsemme tt monipuolisempia
lausekkeita.
30
Fortran 95/2003
Lopuksi ohjelma tulostaa muuttujan y arvon sek lausekkeen SQRT(y) arvon. Seuraavassa on esimerkki ohjelman kytst:
Syt luku x:
2.345
Luku x:
2.3450000
Arvo x**2 + 1:
6.4990253
Arvo SQRT(x**2 + 1):
2.5493186
3.10
Edell kytimme Fortranin standardifunktiota SQRT nelijuuren laskemiseksi. Mys omien funktioiden mritteleminen on mahdollista. Seuraavassa ohjelmakoodissa mrittelemme funktion f, joka vastaa matemaattista mritelm f (a) = a2 + 1:
PROGRAM funktio_esimerkki
! Ohjelma lukee reaaliluvun x ja tulostaa
! funktion f arvon tss pisteess.
31
IMPLICIT NONE
REAL :: x
WRITE (*,*) Syt luku x:
READ (*,*) x
WRITE (*,*) Luku x:, x
WRITE (*,*) Arvo f(x):, f(x)
CONTAINS
FUNCTION f(a) RESULT(f_arvo)
IMPLICIT NONE
REAL :: a, f_arvo
f_arvo = a**2 + 1
END FUNCTION f
END PROGRAM funktio_esimerkki
Funktion f arvo lasketaan funktiokutsulla f(x). Funktio f on mritelty pohjelman sisisen funktiona CONTAINS-lauseen jlkeen.
Funktioista kerromme lis luvussa 8 sivulta 99 alkaen.
Seuraavassa on ote funktion f mrittelyst:
FUNCTION f(a) RESULT(f_arvo)
REAL :: a, f_arvo
Funktion f muodollinen argumentti a on mritelty funktion otsikkorivill. Muodollinen argumentti saa arvokseen funktiokutsussa f(x) esiintyvn
todellisen argumentin x arvon.
Funktion f arvo lasketaan muuttujaan f_arvo seuraavasti:
f_arvo = a**2 + 1
Toisaalta funktiokutsut
y = f(1)
y = f(1,0)
32
Fortran 95/2003
piste olisi muuttunut vahingossa pilkuksi, huomataan virheellinen funktiokutsu f(1,0) jo knnsaikana. Tt ominaisuutta ei ollut FORTRAN 77:ss.
3.11
Toistorakenteet
Muuttuja x on mritelty REAL-tyyppiseksi, jolloin lausekkeessa 1/x vltetn kokonaislukujen jakolasku. Funktiokutsu REAL(2**i) muuttaa puolestaan kokonaislukulausekkeen 2**i reaalilukutyyppiseksi.
DO-silmukka mritelln seuraavasti:
DO silmukkamuuttuja = alaraja, ylraja
lauseet
END DO
2.0000000
2.2500000
4.0000000
2.4414062
8.0000000
2.5657845
16.0000000
2.6379285
32.0000000
2.6769900
64.0000000
2.6973450
1.2800000E+02
2.7077391
2.5600000E+02
2.7129917
arvot:
arvot:
5.1200000E+02
1.0240000E+03
33
2.7156320
2.7169557
Kun muuttujan x arvo kasvaa, lhestyy lausekkeen (1 + 1/x)**x arvo matemaattista vakiota e 2.71828.
3.12
Ksittelemme seuraavassa esimerkiss kurssille osallistujien nimi- ja arvosanatietoja. Sijoitamme merkkijonomuuttujiin nimi_1 . . . nimi_4 osallistujien nimet. Nimess saa olla korkeintaan 30 merkki. Arvosanat sijoitamme
muuttujiin arvosana_1 . . . arvosana_4.
CHARACTER (LEN=30) :: nimi_1, nimi_2, nimi_3, nimi_4
REAL :: arvosana_1, arvosana_2, arvosana_3, arvosana_4
REAL :: keskiarvo
nimi_1 = Iiro V.
arvosana_1 = 7.25
nimi_2 = Sauli N.
arvosana_2 = 7.0
jne.
Mrittelimme tunnuksen lkm kokonaislukutyyppisen nimetyn vakion tunnukseksi kyttmll mrett PARAMETER. Vakion lkm arvo on 120. Tmn jlkeen mrittelimme taulukot nimet ja arvosanat, joissa kummassakin on lkm alkiota. Taulukko nimet on merkkijonotyyppi, ja taulukko
arvosanat on reaalilukutyyppi.
Taulukkojen alkioille voimme antaa arvot seuraavasti:
nimet(1) = Iiro V.
arvosanat(1) = 7.25
nimet(2) = Sauli N.
arvosanat(2) = 7.0
jne.
34
Fortran 95/2003
Merkint tunnus(n) viittaa taulukon n:nteen alkioon. Tss esimerkiss taulukkojen indeksi n voi olla vlill 1, 2, . . . , 120.
Fortranin standardifunktio SUM laskee taulukon alkioiden summan. Taulukkoon arvosanat sijoitettujen arvosanojen keskiarvo voidaan siis laskea seuraavasti:
REAL :: keskiarvo
keskiarvo = SUM(arvosanat)/lkm
Edell kytimme erillisi taulukkoja nimille ja arvosanoille. Seuraavassa mrittelemme rakenteisen tyypin, joka sislt erilliset kentt oppilaan nimelle
ja arvosanalle:
TYPE kurssilainen
CHARACTER(LEN=30) :: nimi
REAL :: arvosana
END TYPE kurssilainen
Tss merkint oppilaat%arvosana viittaa kaikkien 120 oppilaan arvosanoihin. Merkin % ymprill saa kytt vlilyntej:
keskiarvo = SUM(oppilaat % arvosana)/lkm
3.13
35
Tulostuksen muotoilu
2.2500
2.4414
2.5658
2.6379
2.6770
2.6973
2.7077
2.7130
2.7156
2.7170
Merkkijonovakio tulostettiin kuuden merkin levyiseen kenttn (muotoilukoodi A6). Muuttujan x arvo tulostettiin seitsemn merkin levyiseen kenttn
siten, ett desimaalipisteen oikealla puolella oli yksi numero (F7.1). Lauseke
(1 + 1/x)**x tulostettiin siten, ett desimaalipisteen oikealla puolella oli
nelj numeroa (F7.4).
3.14
rL
,
1 (1 + r )m
miss
P = kuukausier
L = alkuperinen lainasumma
m = laina-aika kuukausina.
36
Fortran 95/2003
37
Lainasumma (mk):
1.0000000E+05
Laina-aika (kk): 36
Kuukausimaksu (mk):
3.1521265E+03
(*,(A20,
(*,(A20,
(*,(A20,
(*,(A20,
Tss kytmme merkin * sijaan muotoilukoodia (A20, F12.2), joka tulostaa merkkijonoja 20 merkin levyiseen kenttn (koodi A20) sek reaalilukuja 12 merkin levyiseen kenttn kahden desimaalin tarkkuudella (koodi
F12.2). Koodi I12 puolestaan tulostaa kokonaislukuja 12 merkin levyiseen
kenttn.
Seuraavassa on esimerkki muutetun ohjelman tulostuksesta:
Vuosikorko (%):
Lainasumma (mk):
Laina-aika (kk):
Kuukausimaksu (mk):
8.40
100000.00
36
3152.13
3.15
Ehtolauseet
38
Fortran 95/2003
ELSE
WRITE (*,*) Virhe: arvojen pit olla positiivisia!
END IF
3.16
Esimerkki: simulointitehtv
Seuraava tehtv liittyy komponenttien sijoitteluun shkpiirille. Ratkaisussa kytmme hyvksi edellisiss kappaleissa esiteltyj Fortran-kielen piirteit.
Sijoitamme yksikknelin kaksi satunnaista pistett a ja b. Pisteiden koordinaatit ovat a = (a1 , a2 ) ja b = (b1 , b2 ), joille siis ptevt epyhtlt
0 ai 1 ja 0 bi 1, i = 1, 2. Pisteiden vlimatka d on
d = (a1 b1 )2 + (a2 b2 )2 .
Tehtvn on arvioida, mik on etisyyden d odotusarvo E[d]. Kuva 3.1
havainnollistaa tehtv.
1
a
d = (a1 b1 )2 + (a2 b2 )2
d
b
0
1
Kuva 3.1: Simulointitehtvn geometrinen havainnollistus.
Voimme simuloida pisteiden sijoittamista ohjelmalla, joka sijoittaa satunnaisesti n pisteparia yksikknelin ja laskee keskiarvon pisteiden keskinisille etisyyksille:
39
PROGRAM pisteparit
! Ohjelma simuloi pisteparin sijoittamista
! yksikknelin.
IMPLICIT NONE
REAL, DIMENSION(2) :: a, b
REAL :: d, s = 0.0
INTEGER :: i, n
WRITE (*,*) Anna lukuparien lkm:
READ (*,*) n
WRITE (*,*) Pistepareja:, n, kpl
IF (n > 0) THEN
DO i = 1, n
CALL RANDOM_NUMBER(a)
CALL RANDOM_NUMBER(b)
s = s + SQRT(SUM((a - b)**2))
END DO
d = s/n
WRITE (*,*) Etisyyden keskiarvo:, d
ELSE
WRITE (*,*) Lukumr ei ole positiivinen!
END IF
END PROGRAM pisteparit
Aliohjelma RANDOM_NUMBER palauttaa argumentin muuttuja alkioissa tasajakautuneita satunnaislukuja vlilt [0, 1). Aliohjelman eroavat funktioista
siten, ett funktiolla on arvo, joka vlittyy kutsuvaan ohjelmayksikkn. Tavallisesti funktio vain laskee sille annetuista argumenteista jonkin tuloksen,
kun taas aliohjelman argumentit voivat olla sek lhttietoja ett muuttujia,
joiden kautta aliohjelma vlitt tuloksia kutsuvalle ohjelmayksiklle.
Rivill
s = s + SQRT(SUM((a - b)**2))
40
Fortran 95/2003
tio SQRT laskee nelijuuren. Taulukko-operaatioista kerromme enemmn luvussa 11 (sivu 164).
Silmukan jlkeen laskemme etisyyksien keskiarvon d sijoituslauseessa
d = s/n
3.17
1
1
ln(1 + 2) +
(2 + 2) 0.5214 . . .
3
15
Fortran-kielen moduulit
41
REAL :: pituus
INTEGER :: i
pituus = ABS(a-b)
jako = MIN(a,b) + (/ (i, i = 0, n) /)*pituus/n
END FUNCTION jako
END MODULE taulukko_operaatiot
Moduulin mrittely alkaa lauseella MODULE ja pttyy vastaavaan END-lauseeseen. Moduulin sisltm funktio jako kirjoitetaan CONTAINS-lauseen jlkeen.
Moduulissa on kytetty hyvksi Fortran 95:n uusia ominaisuuksia, jotka esitelln myhemmin luvuissa 9 (moduulit) ja 11 (taulukoiden ksittely). Funktion jako mrittelyss kytetty merkint
REAL, DIMENSION(n+1) :: jako
tarkoittaa, ett funktio palauttaa yksiulotteisen taulukon, jonka pituus riippuu argumentista n.
Voimme kytt edell mritelty moduulia seuraavasti:
PROGRAM jakaminen
USE taulukko_operaatiot
IMPLICIT NONE
INTEGER, PARAMETER :: n = 5
REAL, DIMENSION(n+1) :: arvot
REAL :: pii
pii = 4*ATAN(1.0)
arvot = jako(0.0, pii, n)
WRITE (*,*) arvot: , arvot
WRITE (*,*) SIN(arvot): , SIN(arvot)
END PROGRAM jakaminen
Tmn jlkeen knnmme pohjelman tiedostosta jakaminen.f90 ja linkitmme ohjelmaan kyttmmme moduulin:
% f90 jakaminen.f90 taulukko_operaatiot.o
42
Fortran 95/2003
SIN(arvot):
0.9510565
0.0000000E+00
0.5877852
0.5877852
0.9510565
-8.7422777E-08
3.18
Listietoja
Seuraavissa luvuissa kerromme tarkemmin tss luvussa esitellyist Fortran-kielen piirteist. Ksittelemme mm. funktioita ja aliohjelmia, moduuleita, taulukkoja sek rakenteisia tietotyypej. Luvussa 15 (sivu 275) kerromme
Fortranin vanhentuvista ja vltettvist piirteist.
3.19
Yhteenveto
Harjoitustehtvi
1. Kuinka vanha ohjelmointikieli Fortran on tll hetkell?
2. Jos tunnet ennestn Fortran-kielt, etsi kappaleen 1.2 (sivu 13) esimerkist Fortran-kielen uusia piirteit (verrattuna FORTRAN 77 -kieleen).
3. Kirjoita ohjelma, joka laskee sinifunktion SIN(x) arvot pisteiss
{0, /8, 2 /8, . . . , }.
43
j=1
dj
n
,
j=1
d2j n 2
n1
44
Fortran 95/2003
Ohjelman perusrakenne
Esittelemme tss luvussa Fortran 95 -ohjelmakoodin rakenteen ja perussyntaksin. Keskitymme esityksess Fortran 95 -standardin mukaiseen lhdekoodin esitystapaan.
4.1
Lhdekoodin muoto
Merkki & ksitetn rivin jatkamisen tunnukseksi vain rivin lopussa, joten
edellinen lause tulostaa ensimmisen &-merkin:
Tm on todella pitk & monimutkainen merkkijono.
Rivin lopussa ei tarvita puolipistett, koska rivin loppu automaattisesti lopettaa lauseen. Puolipisteen kytt kannattaa vltt, sill turha tiivistmi-
4. Ohjelman perusrakenne
45
46
Fortran 95/2003
Tunnuksissa kytettvien merkkien lisksi Fortran-kieleen kuuluu muutamia muita symboleita. Fortranin erikoismerkit on lueteltu taulukossa 4.1.
Taulukko 4.1: Fortranin erikoismerkit.
Merkki
Selitys
Merkki
Selitys
=
+
*
/
(
)
,
.
vlilynti
yhtlisyysmerkki
plusmerkki
miinusmerkki
asteriski
vinoviiva
oikea sulje
vasen sulje
pilkku
piste
heittomerkki
:
!
"
%
&
;
<
>
?
$
kaksoispiste
huutomerkki
lainausmerkki
prosenttimerkki
et-merkki
puolipiste
pienempi kuin -merkki
suurempi kuin -merkki
kysymysmerkki
dollarin merkki
4.3
Muuttujien ja vakioiden nimien tulee alkaa kirjaimella, ja nimen maksimipituus on 31 merkki. Seuraavassa on esimerkkej laillisista nimist: a, a2,
a_2 ja a_b_c. Sen sijaan seuraavat nimet eivt ky: 2a, _a ja a b.
Fortran-kieless ei ole ns. varattuja sanoja, joten mys Fortranin tunnukset
voi mritell vaikkapa omien muuttujien nimiksi. Tm ei kuitenkaan ole
suositeltavaa!
PROGRAM crazy
IMPLICIT NONE
REAL :: sin, max = 1.0, real = 1.23
INTEGER :: program, precision
sin = max + real
program = 12
precision = 10
END PROGRAM crazy
4. Ohjelman perusrakenne
47
FORMAT-lauseet
vakioiden mrittelyt
48
Fortran 95/2003
PROGRAM omaohjelma
! Ohjelma laskee lausekkeen a**i + b**j arvon.
IMPLICIT NONE
REAL :: a, b
INTEGER :: i, j
WRITE (*,*) Anna a ja b:
READ (*,*) a, b
WRITE (*,*) Anna i ja j:
READ (*,*) i, j
WRITE (*,*) f(x) = , f(a, i, b, j)
CONTAINS
FUNCTION f(x, x_potenssi, y, y_potenssi) RESULT(f_arvo)
IMPLICIT NONE
REAL :: x, y
INTEGER :: x_potenssi, y_potenssi
REAL :: f_arvo
f_arvo = x**x_potenssi + y**y_potenssi
END FUNCTION f
END PROGRAM omaohjelma
Pohjelman sisinen funktio f mritelln CONTAINS-lauseen jlkeen. Sisisill funktiolla ei voi olla omia sisisi funktioita tai aliohjelmia. Funktioiden mrittely ksitelln tarkemmin luvussa 8 (sivu 99).
4.5
INCLUDE-lause ja moduulit
4. Ohjelman perusrakenne
49
Moduuleissa voi mritell muuttujien ja vakioiden lisksi mm. proseduureja. Lyhyt esimerkki tst lytyy kappaleesta 3.17 sivulta 40. Kerromme
moduulien kytst enemmn luvussa 9 (sivu 126).
4.6 Yhteenveto
Voit kirjoittaa ohjelmakoodin 132 merkin pituisille riveille. Kytettviss on lisksi jatkorivit (&), kommentit (!) ja mahdollisuus sijoittaa useita
lauseita riville (;).
Tunnukset muodostuvat kirjaimista A, . . . Z, numeroista 0, 1, . . . , 9
sek alaviivasta _. Tunnuksen tulee alkaa kirjaimella. Pienten kirjainten
merkitys tunnuksissa on sama kuin isojen kirjainten.
Kyt vlilyntej erottamaan tunnukset ja lausekkeiden osat toisistaan.
Aloita ohjelmayksikk otsikkolauseella PROGRAM, MODULE, FUNCTION ja
SUBROUTINE. Pt ohjelmayksikk vastaavaan END-lauseeseen.
Kyt moduuleja ohjelmayksikkjen jsentelyyn.
Harjoitustehtvi
1. Mit seuraava koodirivi tekee?
a = 0.0 ; b = 370 ! Alustus ; c = 17.0 ; d = 33.0
50
Fortran 95/2003
7. Kokeile kappaleessa 4.5 esitetyn moduulin vakiot kytt. Lis moduuliin muita matemaattisia ja luonnonvakioita.
5. Perustyypit
51
Perustyypit
5.1.1 Kokonaisluvut
Kokonaislukutyypill esitetn positiivisia tai negatiivisia kokonaislukuja eli
joukon {. . . , 2, 1, 0, 1, 2, . . . } alkioita. Fortranin kokonaislukutyypill voi
esitt vain rellisen osajoukon kokonaisluvuista.
Ohjelmassa voi esiinty kokonaislukuvakioita, jotka koostuvat numeroista
0, 1, . . . , 9:
WRITE (*,*) 40 + 2
52
Fortran 95/2003
5.1.2 Reaaliluvut
Fortran-kielen reaaliluvut ovat kokonaislukutyypin tapaan vain rellinen
osajoukko todellisista reaaliluvuista.
Reaalilukuvakiot erotetaan kokonaislukuvakioista desimaalipisteen tai eksponenttinotaation avulla:
WRITE (*,*) 42.0, 0.42E2, 0.012345, 12345E-6
Yksinkertaisen desimaalinotaation lisksi reaalilukuvakiot voidaan siis esitt eksponenttimuodossa. Vakio 0.42E2 tarkoittaa reaalilukua 0.42 102 =
42.0 ja vakio 12345E-6 tarkoittaa reaalilukua 12345 106 = 0.012345.
Edellisen lauseen tulostus voisi olla
42.0000000
42.0000000
1.2345000E-02
1.2345000E-02
Reaalilukutyypist on vhintn kaksi eri lajia. Lajimreist kerrotaan kappaleessa 5.5 sivulla 56.
5.1.3 Kompleksiluvut
Kompleksilukutyyppi vastaa matemaattista kompleksiluvun ksitett. Siten
kompleksiluku
z koostuu reaaliosasta x ja imaginriosasta y eli z = x+iy,
miss i = 1.
Kompleksilukuvakiot kirjoitetaan sulkujen sisn:
WRITE (*,*) (0, -1)*(1.2345E-2, 8)
Jos kummatkin sulkujen sisss olevat luvut ovat kokonaislukutyyppi, vakio on oletuslajin kompleksiluku. Jos sulkujen sisll on reaalilukuja, on
kompleksiluku suuremman tarkkuuden reaaliluvun mukaista lajia.
5.1.4 Totuusarvot
Fortranissa voidaan esitt totuusarvot tosi ja eptosi vakioilla .TRUE. ja
.FALSE.. Vakioiden alussa ja lopussa olevat pisteet ovat tarpeen!
5. Perustyypit
53
5.1.5 Merkkijonot
Merkkijonotyypill voidaan esitt merkkijonoja. Merkkijonovakio sijoitetaan ohjelmakoodiin yksinkertaisten tai kaksinkertaisten lainausmerkkien
sisn:
WRITE (*,*) "kki ern pivn..."
WRITE (*,*) kki ern pivn...
Lainausmerkki voidaan sisllytt osaksi merkkijonoa sijoittamalla se toisentyyppisiin lainausmerkkeihin tai kahdentamalla se:
WRITE (*,*) "Yhtkki tuli pime."
WRITE (*,*) Yhtkki tuli pime.
54
Fortran 95/2003
Loogisen muuttujan tulosta arvoksi asetetaan tosi. Kompleksilukumuuttuja z sai alkuarvoksi luvun 0.5 + 1.0i.
Merkkijonomuuttujassa selitys on 20 merkki. Alustuslausekkeessa
CHARACTER (LEN=20) :: selitys = Kompleksiluku:
sijoituslauseen oikea puoli on lyhyempi, ja tllin kntj lis merkkijonon selitys loppuun tarpeellisen mrn vlilyntej.
Ohjelman tulostus voisi nytt tlt:
Kompleksiluku:
(0.5000000000,1.000000000)
5.3
Nimetyt vakiot
5. Perustyypit
55
Nimetyt vakiot erotetaan muuttujista mreen PARAMETER avulla. Seuraavassa kytmme hyvksi nimettyj vakioita kehote ja tuloste:
PROGRAM liittolainen
IMPLICIT NONE
CHARACTER (LEN=*), PARAMETER :: &
kehote = Syt kompleksiluku z:, &
tuloste = Luku z ja SIN(z):
COMPLEX :: z
WRITE (*,*) kehote
READ (*,*) z
WRITE (*,*) tuloste, z, SIN(z)
END PROGRAM liittolainen
Tss mrittelimme ohjelman tulostaman kehotteen ja selitteen merkkijonovakioiksi. Ohjelman kytt nytt seuraavalta:
Syt kompleksiluku:
(0.5, 1.0)
Luku z ja SIN(z): (0.5000000,1.000000) (0.7397923,1.031336)
Tss mritelty nimetty vakiota n voi kytt mys DO-silmukan toistokertojen mrmiseen:
INTEGER :: i, j
DO i = 1, n
DO j = 1, n
d(j,i) = 1.0 - c(j,i)
END DO
END DO
Jos haluamme muuttaa tmn esimerkin taulukkojen b, c ja d kokoa, selvimme tst muuttamalla nimetyn vakion n mrittely.
56
Fortran 95/2003
5.5
Perustyyppien lajimreet
Lajiparametri on Fortran-kntjst riippuva positiivinen kokonaislukuvakio, joka kannattaa selvitt tarkoitukseen varatuilla funktiokutsuilla (esimerkiksi SELECTED_INT_KIND).
5. Perustyypit
57
5.5.1 Kokonaisluvut
Kokonaislukujen lajiparametri mr luvun esitystarkkuuden. Funktiokutsu
SELECTED_INT_KIND(r)
5.5.2 Reaaliluvut
Reaalilukujen tarkkuuden voi valita samaan tapaan kuin kokonaislukujenkin. Tarkkuuden mrittelyss oletetaan, ett reaaliluvut esitetn kytten
eksponenttinotaatiota
d.ddddd 10e ,
miss mantissassa d.ddddd on p merkitsev desimaalia ja eksponentin e
vaihteluvli on r e r . Tllaista reaalilukuesityst kutsutaan liukulukuesitykseksi.
Liukulukujen lajiparametrin voi valita funktiokutsulla
SELECTED_REAL_KIND(p,r)
58
Fortran 95/2003
Saatu lajiparametrin arvo takaa, ett kyseisen lajin reaaliluvulla voidaan esitt vhintn halutun tarkkuuden ja eksponentin vaihteluvlin reaaliluvut.
Fortran-kntj tuntee ainakin kaksi eri lajia reaalilukuja. Oletuksena on
pienemmn tarkkuuden reaaliluvut. Reaalilukuvakion laji voidaan ilmoittaa
lismll vakion pern alaviiva ja lajiparametri samoin kuin kokonaisluvuillekin:
WRITE (*,*) 3.141592653589793_reaalilukulaji
Lisksi on kytettviss standardifunktio KIND, joka palauttaa tunnusta vastaavat tietotyypin lajiparametrin. Seuraavassa on esimerkki funktion kytst:
INTEGER :: i
REAL :: x
x = REAL(i, KIND=KIND(x))
Tss muutettiin kokonaislukumuuttujan i arvo muuttujan x lajia vastaavaksi reaaliluvuksi kyttmll funktiota REAL.
5.5.3 Kompleksiluvut
Kompleksiluvun lajimre ilmaisee sen reaali- ja imaginriosan lajin samoin
kuin reaaliluvuille:
INTEGER, PARAMETER :: tarkka = SELECTED_REAL_KIND(10,100)
COMPLEX (KIND=tarkka) :: z
Tss mriteltiin 80 merkin mittainen merkkijono, jonka lajiparametri annetaan mreess KIND=lajiparametri.
Merkkijonovakion laji annetaan ennen merkkijonovakiota:
lajiparametri_Merkkijono
Fortran-standardi mahdollistaa usean merkkijonolajin kytn, mutta ei standardoi tt milln tavalla. Sama ptee totuusarvoihin. Siten Fortranissa ei
ole helppoa tapaa saada selville merkkijonojen tai totuusarvojen lajiparametreja; parhaiten nm selvivt kunkin Fortran-kntjn ksikirjoista.
5. Perustyypit
59
Lajiparametria suuritarkkuus laskettaessa jtettiin eksponentin vaihteluvli antamatta, koska ainoastaan merkitsevien numeroiden lukumrll
(12) on esimerkiss merkityst. Kntj valitsee tllin sopivan vaihteluvlin eksponentille.
Ohjelma tulostaa esimerkiksi seuraavan:
pii:
pii:
3.141592653589793
3.141593
(3.141592653589793,0.0000000000000000E+00)
Tss kytetyll laitteistolla vastaavat ohjelmassa kytetyt reaalilukujen lajiparametrit suuritarkkuus ja pienitarkkuus eri tarkkuuden lajeja.
Toisella laitteistolla voisi laji suuritarkkuus olla pienin esitettviss oleva
reaalilukujen tarkkuus, jolloin suuritarkkuus ja pienitarkkuus esittisivt samaa lajia. Tllaisella koneella voisi olla kytettviss mys vaikkapa
28 desimaalin tarkkuuteen pystyv reaalilukulaji.
60
Fortran 95/2003
5.5.7 Kaksoistarkkuus
Aikaisemmassa Fortran-standardissa oli kytss kaksoistarkkuuden tyyppi
DOUBLE PRECISION, joka aiheutti suuria siirrettvyysongelmia: toisen koneen REAL-tyyppi saattoi vastata toisen koneen kaksoistarkkuutta. Kaksoistarkkuuden mrittelyt kannattaa korvata parametrisoiduilla tyypinmrittelyill.
Seuraavassa on esimerkki vanhasta Fortran-koodista:
DOUBLE PRECISION X, Y
X = 1.D0
Y = 2.D0*ACOS(X)
Tss merkint 1.D0 tarkoittaa kaksoistarkkuuden vakiota, jota vastaa yksinkertaisen tarkkuuden vakio 1.E0.
Edellinen ohjelmakoodi on parempi esitt vaikkapa seuraavassa muodossa:
INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(12)
REAL (KIND=dp) :: x, y
x = 1.E0_dp
y = 2.E0_dp*ACOS(x)
Nyt voimme olla varmoja siit, ett kytetty reaalilukulaji pystyy esittmn
lukuja 12 numeron tarkkuudella riippumatta kytetyn koneen ominaisuuksista.
Huomaa, ett Fortran-kntjt eivt pysty esittmn lukuja mielivaltaisella
tarkkuudella. Esimerkiksi reaalilukujen eri lajeja on tyypillisesti kaksi tai
kolme.
5.6
1
.
2
i
i=1
1
.
2
i
i=1
5. Perustyypit
61
INTEGER :: i, n
WRITE (*,*) Anna termien lukumr:
READ (*,*) n
WRITE (*,*) Termej: , n
DO i = 1, n
s = s + 1/(REAL(i)**2)
END DO
WRITE (*,*) Summa on:, s
END PROGRAM summaus
Funktiokutsu REAL(i) muuttaa kokonaisluvun i reaaliluvuksi, jotta jakolaskun tulos olisi mys reaaliluku. Seuraavassa on ajoesimerkki:
Anna termien lukumr:
100
Termej: 100
Summa on:
1.6349840
Miljoonalla termill lasketussa tuloksessa on vain 4 desimaalia oikein, samoin kuin 10000 desimaalin tapauksessa. Ohjelmakoodimme nyttisi siis
tuottavan eptarkkoja tuloksia.
Tulosten huonous johtuu siit, ett summauksessa hvi liikaa informaatiota pyristysvirheiden takia. Tm puolestaan johtuu kytetyn laskentamenetelmn ominaisuuksista.
DO-silmukassa lasketaan lauseessa
s = s + 1/(REAL(i)**2)
62
Fortran 95/2003
DO i = n, 1, -1
s = s + 1/(REAL(i)**2)
END DO
Lause
DO i = n, 1, -1
Tss mriteltiin reaalilukumuuttujan s vhimmistarkkuudeksi 12 desimaalia. Standardifunktio REAL muuttaa kokonaisluvun reaaliluvuksi. Huomaa, ett KIND-mre on syyt antaa mys funktiokutsun REAL argumenttina, koska lauseke REAL(i) tuottaa oletustarkkuuden reaaliluvun.
Ohjelma tulostaa seuraavaa:
Termej: 1000000
Summa on:
1.6449330668487263
1.6449330668487701
Eri jrjestyksess lasketut arvot poikkeavat nyt 15. desimaalissa. Jos laskujrjestyksen on parempi vaihtoehto eli DO i = n, 1, -1, saadaan viel
termej lismll seuraava tulos:
5. Perustyypit
63
Termej: 10000000
Summa on:
1.6449339668482315
1
1
+ .
2
i
n
i=1
5.7 Yhteenveto
Fortranissa on viisi perustyyppi: INTEGER, REAL, COMPLEX, LOGICAL ja
CHARACTER.
Mreell PARAMETER luodaan nimettyj vakioita, joiden arvoa ei voi
muuttaa ohjelman ajon aikana.
Perustyyppien lajimre kertoo, millaisen version tyypist haluamme
kyttn.
Kytetty laskentamenetelm sek laskutarkkuus voivat vaikuttaa ratkaisevasti tuloksiin.
Harjoitustehtvi
1. Ovatko seuraavat mrittelyt laillista Fortrania:
DOUBLE :: x
CHARACTER (LEN=*), PARAMETER :: "Nimi"
REAL :: pi = 22/7
REAL :: x = 2., y = -3
REAL :: pii = 22.0/7.0
REAL x = 1.0
64
Fortran 95/2003
PROGRAM tulostus
IMPLICIT NONE
INTEGER, PARAMETER :: reaali = SELECTED_REAL_KIND(10)
REAL(KIND=reaali) :: x
x = 314/1000_reaali
WRITE (*,*) X
END PROGRAM tulostus
1
1
ln(1 + 2) +
(2 + 2) 0.5214 . . .
3
15
arvo vhintn 6 desimaalin tarkkuudella. Kyt funktiokutsuja LOG ja
SQRT. Tulosta lausekkeen arvo lisksi suurimmalla kntjn tuntemalla
reaalilukujen tarkkuudella. Kyt hyvksesi edellisen tehtvn tuloksia.
7. Kappaleessa 3.11 sivulla 32 esiteltiin ohjelma, joka tulostaa arvoja lausekkeelle (1 + 1/x)**x.
Muuta ohjelmaa siten, ett se lukee arvon reaalimuuttujalle x ja tulostaa
lausekkeen (1 + 1/x)**x arvon. Kun muuttujan x arvo kasvaa, lausekkeen arvon pitisi lhesty arvoa e 2.71828. Kokeile ohjelmasi toimintaa syttarvoilla 103 , 106 , 1012 ja 1018 (siis 1E3, 1E6 jne.). Miten
ky?
Liukulukujen kone-epsilon on pienin positiivinen liukuluku, jolle ptee
epyhtl 1.0 + > 1.0. Reaalilukumuuttujan x lajia vastaavan koneepsilonin saa selville seuraavasti:
REAL :: x
REAL, PARAMETER :: eps = EPSILON(x)
5. Perustyypit
65
8. Kappaleen 3.16 (sivu 38) simulointiesimerkiss laskettiin yhteen pisteiden etisyyksi lauseessa
s = s + SQRT(SUM((a - b)**2))
(1)k1
.
k
k=1
Kokeile eri summausjrjestyksi sek lisksi positiivisten ja negatiivisten alkioiden summausta erikseen. Tulos on ln 2 0.69314718 . . . .
11. Ns. maagisessa summauksessa voidaan kytt pienemmn tarkkuuden
muuttujia, mutta tulos on silti varsin tarkka. Seuraavassa on esimerkki
tarvittavasta koodista:
66
Fortran 95/2003
Tss funktio f(i) laskee sarjan i:nnen alkion arvon. Kokeile summauksen tarkkuutta edellisess tehtvss.
6. Lausekkeet ja sijoituslauseet
67
Lausekkeet ja
sijoituslauseet
Lausekkeet ja sijoituslauseet ovat ohjausrakenteiden ohella tietokoneohjelmassa ne tykalut, joilla laskentatehtv saadaan ohjelmoitua. Tss luvussa esittelemme Fortran-kielen aritmeettiset, loogiset ja merkkijonolausekkeet. Sijoituslauseiden ksittelyn yhteydess puhumme lausekkeiden eri
osien laskentajrjestyksest. Taulukoita sisltvi lausekkeita ja sijoituslauseita ksittelemme luvussa 11 (sivu 164).
Luvussa -5 esiintyv miinusmerkki kuuluu lukuesitykseen eik siis ole etumerkin vaihto-operaatio. Siten seuraavassa lausekkeessa sulut voi jtt pois
luvun -5 ymprilt mutta ei lausekkeen -c ymprilt:
a**(-5) + a**(-c)
68
Fortran 95/2003
tulkitaan seuraavasti:
((a / b) / c) * d
Kntjll on oikeus jrjestll lausekkeita uudestaan tehokkuuden lismiseksi. Tten yll esitetyt lausekkeet saatettaisiin laskea seuraavassa jrjestyksess:
(a + d) - (b + c + e)
(a * d) / (b * c)
Kyt aritmeettisissa lausekkeissa vlilyntej ja ylimrisi sulkumerkkej selkeyden lismiseksi. Esimerkiksi lauseke
a ** (b ** (-2)) + d / (e * f * g)
Ole erityisen varovainen, kun lasket jakolaskua tai potenssiinkorotusta kokonaisluvuille. Kahden kokonaisluvun jakolaskun tulos katkaistaan nollaa
kohti kokonaisluvuksi. Siten esimerkiksi jakolaskun 2/3 tulos on 0 ja jakolaskun -5/3 tulos on -1.
Kun kokonaislukuja korotetaan negatiiviseen potenssiin, tulkitaan tulos ykksen ja vastaavan positiivisen potenssin jakolaskuna. Tm jakolasku tulkitaan kuten mik tahansa kokonaislukujen jakolasku, joten tuloksena on
useimmiten nolla. Lauseke 2**(-3) tulkitaan siis lausekkeeksi 1/(2**3)
eli 1/8, mist tulee tulokseksi nolla. Lauseke
2**(-1/2) tuottaa puolestaan
6. Lausekkeet ja sijoituslauseet
69
Eri tarkkuuden argumentit (KIND-parametri) muutetaan tarkimman argumentin mukaiseksi. Seuraavassa esimerkiss mrittelemme reaalilukujen
lajiparametrit t1 ja t2, joilla luvun esitystarkkuus on vhintn 6 ja 12 numeroa. Lisksi mrittelemme lajeja t1 ja t2 vastaavat muuttujat a ja b:
INTEGER, PARAMETER
INTEGER, PARAMETER
REAL(KIND=t1) :: a
REAL(KIND=t2) :: b
WRITE (*,*) a + b
:: t1 = SELECTED_REAL_KIND(6)
:: t2 = SELECTED_REAL_KIND(12)
= 3.5
= 4.2
70
Fortran 95/2003
= r * SIN(theta) * COS(phi)
= r * SIN(theta) * SIN(phi)
= r * COS(theta)
SUBROUTINE pallo_xyz
Kytimme esimerkiss standardifunktiota ATAN2(y,x). Tm funktio palauttaa kompleksiluvun x + i y argumentin eli luvun arctan(y/x). Otimme
lukujen x ja y etumerkit huomioon siten, ett kulma tulee samaan xy-tason
neljnnekseen kuin alkuperinen kompleksiluku.
6. Lausekkeet ja sijoituslauseet
71
F
1
1
1
-2
-2
-2
C
2
2
2
-1
-1
-1
I
1
1
1
-1
-1
-1
N
1
2
2
-1
-2
-2
72
Fortran 95/2003
(0.0000000E+00,3.141593)
(0.0000000E+00,1.175201)
Laskemme
ohjelmassa numeerisesti likiarvot matemaattisille lausekkeille
(6.1)
ratkaisukaavan
x=
b2 4ac
2a
(6.2)
kompleksiargumenteilla.
PROGRAM juuret
IMPLICIT NONE
COMPLEX :: a, b, c, juuri1, juuri2
WRITE (*,*) Anna toisen asteen yhtln kompleksiset &
&kertoimet
WRITE (*, (A), ADVANCE=NO) a:
READ (*,*) a
WRITE (*, (A), ADVANCE=NO) b:
READ (*,*) b
WRITE (*, (A), ADVANCE=NO) c:
READ (*,*) c
CALL toinenaste(a, b, c, juuri1, juuri2)
WRITE (*,*) Juuret ovat , juuri1, juuri2
CONTAINS
SUBROUTINE toinenaste(a, b, c, j1, j2)
IMPLICIT NONE
COMPLEX, INTENT(IN) :: a, b, c
COMPLEX, INTENT(OUT) :: j1, j2
COMPLEX :: diskr
diskr = SQRT(b**2-4*a*c)
j1 = (-b+diskr)/(2*a)
j2 = (-b-diskr)/(2*a)
END SUBROUTINE toinenaste
END PROGRAM juuret
Kyttj sytt ohjelmalle yhtln kertoimet kompleksilukuina, joissa reaali- ja imaginriosa kirjoitetaan sulkuihin. Sytss voi kytt joko kokonaisluku- tai reaalilukuesityst.
Anna toisen asteen yhtln kompleksiset kertoimet
a: (2, 3)
b: (-3, -1)
c: (1.0, 1.0)
Juuret ovat (0.4392123,-0.8573956) (0.2530954,0.3189341)
6. Lausekkeet ja sijoituslauseet
73
2c
.
b2 4ac
Tm on harjoitustehtvn.
6.3 Merkkijonolausekkeet
Tarvitsemme merkkijonolausekkeita sytn ja tulostuksen yhteydess sek
tekstimuotoista tietoa ksitteleviss sovelluksissa. Fortranissa on lukuisia
merkkijonoja ksittelevi standardifunktioita. Fortran 90 -standardin liitnnisstandardina (ISO/IEC 1539-2:1994) on olemassa tuki mys vaihtelevan
pituisille merkkijonoille.
Fortranin merkkijonomuuttujat mritelln lauseella CHARACTER. Ilman argumentteja lauseella voi mritell yhden merkin pituisia muuttujia, muuten
pituus on annettava LEN-parametrin avulla:
CHARACTER :: merkki
CHARACTER(LEN=10) :: merkkijono
Voimme poimia merkkijonosta alimerkkijonon tai yksittisi merkkej seuraavan ohjelman mukaisesti:
PROGRAM koe
IMPLICIT NONE
CHARACTER(LEN=10) :: merkkijono
merkkijono = Fortran
WRITE (*,*) merkkijono(2:4)
WRITE (*,*) merkkijono(6:6)
END PROGRAM koe
Jos sijoitettava merkkijono on pidempi kuin merkkijonomuuttuja, katkaistaan merkkej merkkijonon lopusta. Jos sijoitettava merkkijono on lyhyempi
kuin muuttuja, listn muuttujan loppuun vlilyntej.
Edellisen ohjelman tulostus nytt tlt:
ort
a
Merkkijonojen liitosoperaattori // muodostaa annetuista merkkijonoista uuden merkkijonon, joka on saatu liittmll nm kaksi perkkin. Tarkastelemme seuraavaa esimerkkiohjelmaa:
74
Fortran 95/2003
PROGRAM koe
IMPLICIT NONE
CHARACTER(LEN=30) :: etunimi = James
CHARACTER(LEN=30) :: sukunimi = Bond
CHARACTER(LEN=30) :: kone = @csc.fi
WRITE (*,*) Osoite: // TRIM(etunimi) // . &
// TRIM(sukunimi) // kone
END PROGRAM koe
Standardifunktio TRIM poistaa merkkijonon lopussa olevat vlilynnit. Ohjelma tulostaa merkkijonolausekkeen, joka saadaan liittmll nelj merkkijonolauseketta perkkin:
Osoite:James.Bond@csc.fi
6.4
Merkkitiedon ksittelyfunktioita
6. Lausekkeet ja sijoituslauseet
75
Seuraava esimerkkiohjelma lukee nppimistlt etu- ja sukunimi ja tulostaa niiden perusteella muodostetun osoitteen. Ohjelmassa poistetaan merkkijonon lopussa olevat vlilynnit kahdella eri tavalla.
PROGRAM osoite
IMPLICIT NONE
CHARACTER(LEN=30) :: etunimi
CHARACTER(LEN=30) :: sukunimi
CHARACTER(LEN=30) :: kone = @csc.fi
WRITE (*, (A), ADVANCE=NO) Etunimi:
READ (*,*) etunimi
WRITE (*, (A), ADVANCE=NO) Sukunimi:
READ (*,*) sukunimi
WRITE (*,(5A)) Osoite: // TRIM(etunimi) // "." &
// sukunimi(1:LEN_TRIM(sukunimi)) // kone
END PROGRAM osoite
WRITE-lauseissa kytetty mre ADVANCE=NO est tulostuksen siirtymisen seuraavalle riville, kuten muuten tapahtuisi. Ohjelman kytt nytt
tlt:
Etunimi:Jaska
Sukunimi:Jokunen
Osoite:Jaska.Jokunen@csc.fi
76
Fortran 95/2003
merkkijono = Fortran
merkkitaulukko = +
merkkijonotaulukko = Fortran
WRITE (*,*) merkkijono
WRITE (*,*) merkkitaulukko
WRITE (*,*) merkkijonotaulukko
WRITE (*,*) merkkijono(2:4)
WRITE (*,*) merkkitaulukko(2:4)
WRITE (*,*) merkkijonotaulukko(1:2)(4:6)
END PROGRAM taulut
ensimminen sulkulauseke valitsee taulukon alkiot 1 ja 2 ja toinen sulkulauseke nist alkioista merkit 4:st 6:een.
Ohjelman tulostus nytt tlt:
Fortran
++++++++++
Fortran
Fortran
ort
+++
tra
tra
Fortran
Fortran
Fortran
Huomaa, ett tulostus voi vaihdella koneesta toiseen, koska eri kntjt tulkitsevat muotoilukoodin * eli listan ohjaaman tulostuksen eri tavoin. Tst
kerrotaan lis kappaleessa 12.3 (sivu 194).
6.6
Loogiset lausekkeet
Loogisia lausekkeita kytetn IF-lauseen ja muiden ohjausrakenteiden yhteydess, ja niill siis toteutetaan ohjelman logiikka. Loogisiin lausekkeisiin
kuuluvat lukujen ja merkkijonojen vertailuoperaattoreiden lisksi loogiset
operaattorit.
Fortran-kielen vertailuoperaattorit on lueteltu taulukossa 6.1. Taulukossa
on annettu mys vanhat FORTRAN 77:n mukaiset operaattorit (.EQ. jne.).
Vertailuoperaattoreilla muodostettuja lausekkeita voi yhdistell loogisilla
operaattoreilla. Aritmeettiset operaatiot sitovat operandeja vahvemmin kuin
vertailuoperaattorit, jotka puolestaan ovat vahvempia kuin loogiset operaattorit. Loogisten operaattoreiden sidontajrjestys on taulukon 6.2 mukainen,
eli operaattori .NOT. suoritetaan ennen muita operaattoreita.
Loogisten operaattorien toimintaa on havainnollistettu taulukossa 6.3. Huomaa, ett operaattori .NEQV. on poissulkeva tai-operaattori (exclusive or).
6. Lausekkeet ja sijoituslauseet
77
Vertailuoperaattori
==
/=
<
>
<=
>=
.EQ.
.NE.
.LT.
.GT.
.LE.
.GE.
Yhtsuuruus
Erisuuruus
Pienempi kuin
Suurempi kuin
Pienempi tai yhtsuuri kuin
Suurempi tai yhtsuuri kuin
Operaattori
Selitys
.NOT.
.AND.
.OR.
.EQV.
.NEQV.
Looginen negaatio
Looginen ja
Looginen tai
Looginen ekvivalenssi
Looginen epekvivalenssi
78
Fortran 95/2003
a
F
F
T
T
b
F
T
F
T
a .AND. b
F
F
F
T
a .OR. b
F
T
T
T
a .EQV. b
T
F
F
T
a .NEQV. b
F
T
T
F
6.8
Merkkijonojen vertailu
6. Lausekkeet ja sijoituslauseet
79
80
Fortran 95/2003
6.9
Seuraava ohjelma lukee ptteelt rivien lukumrn ja lajiteltavat rivit. Rivit lajitellaan edell kuvattuun, koneen sisisen merkistn mukaiseen jrjestykseen kytten valintalajittelua (selection sort). Muuttuja sivu on taulukko, jonka kukin alkio on 80 merkki pitk merkkijonomuuttuja. Lauseke
sivu(1:rivit) viittaa taulukon riveihin 1-rivit ja lauseke sivu(j) tarkoittaa koko rivi j.
PROGRAM lajittele
! Ohjelma lukee sisn lajiteltavan tekstin
! sek tulostaa lajitellun tekstin.
IMPLICIT NONE
INTEGER, PARAMETER :: maxrivit = 100
CHARACTER(LEN=80), DIMENSION(maxrivit) :: sivu
CHARACTER(LEN=80) :: apu
INTEGER :: rivit, pienin, i, j
WRITE (*,*) Anna rivien lukumr:
READ (*,*) rivit
IF (rivit > maxrivit) THEN
WRITE (*,*) Liian monta rivi!
STOP
END IF
WRITE (*,*) Syt rivit:
READ (*, (A)) sivu(1:rivit)
DO i = 1, rivit-1
pienin = i
DO j = i+1, rivit
IF (sivu(j) < sivu(pienin)) pienin = j
END DO
apu = sivu(pienin)
sivu(pienin) = sivu(i)
sivu(i) = apu
END DO
WRITE (*,*) Lajiteltu taulukko:
WRITE (*,(A)) sivu(1:rivit)
END PROGRAM lajittele
6. Lausekkeet ja sijoituslauseet
81
sidewise
Jos haluat kytt edellisess lajitteluohjelmassa ASCII-merkistn perustuvaa vertailua, voit tehd sen seuraavalla IF-lauseella:
IF (LLT(sivu(j), sivu(pienin))) pienin = j
REAL
COMPLEX
INTEGER
b: INTEGER
=
katkaisu
reaaliosan otto ja
katkaisu
REAL
esitysmuodon
muunnos
reaaliosan otto
COMPLEX
esitysmuodon
muunnos
esitysmuodon
muunnos
82
Fortran 95/2003
COMPLEX :: c
i = 7.3
r = (1.618034, 0.618034)
c = 2.7182818
WRITE (*,*) i, r, c
END PROGRAM numerot
1.618034
(2.718282,0.0000000E+00)
Lausekkeen oikea puoli lasketaan aina kokonaan, ennen kuin sijoitusoperaatiota ruvetaan suorittamaan. Erityisen trke tm on merkkijonomuuttujia
ksiteltess ja myhemmin luvussa 11 esiteltvien taulukoiden ksittelyss.
Seuraavassa esimerkiss merkkijonon merkit alimerkkijonot menevt pllekkin, mutta sijoituksessa kytetn muuttujan vanhaa arvoa:
PROGRAM siirto
IMPLICIT NONE
CHARACTER(LEN=10) :: merkit = Raskas
WRITE (*,*) merkit
merkit(3:6) = merkit(4:7)
WRITE (*,*) merkit
END PROGRAM siirto
6. Lausekkeet ja sijoituslauseet
6.11
83
Funktioiden sivuvaikutukset
Kyttjn mrittelemien funktioiden sivuvaikutukset eivt vlttmtt tuota haluttua tulosta. Esimerkiksi voimme kirjoittaa funktion f, joka pit sisisell laskurilla kirjaa kutsukerroistaan. Kun ohjelmassa esiintyy lauseke
f(x) + f(x)
kntj voi optimoida tmn lausekkeeksi 2*f(x), jolloin laskuri toimii eri
tavalla.
Funktio ei saa muuttaa argumenttejaan, jos todellisia argumentteja kytetn muualla samassa lausekkeessa. Esimerkiksi lausekkeessa f(x) + f(x)
kytetty funktio f ei saa muuttaa argumenttia x.
Kntjn ei tarvitse laskea lausekkeen kaikkia osia, jos se pystyy pttelemn lausekkeen arvon muuten. Esimerkiksi ehtolauseessa
IF (x < 0 .AND. f(x) < 0) THEN
6.12
Operaattorien sidontajrjestys
6.13
Yhteenveto
Fortranin lausekkeissa voi esiinty vakioita, muuttujia, operaattoreita, standardifunktioiden kutsuja ja omien funktioiden kutsuja. Sijoituslausekkeen
oikea puoli lasketaan kokonaan ennen sijoitusta. Operaattorien sidontajrjestys on esitetty taulukossa 6.5.
Lausekkeiden suoritusjrjestys ei ole ennalta mrtty, vaan kntj voi
84
Fortran 95/2003
Operaattorin tyyppi
Operaattori
Numeerinen
Numeerinen
Numeerinen
Numeerinen
Merkkijono
Vertailu
Looginen
Looginen
Looginen
Looginen
Harjoitustehtvi
1. Mik on lausekkeen 2* -3-4** 2*3 arvo?
2. Mik on lausekkeen 2/3 * 2 arvo?
3. Paljonko on 1.0/2.0/3.0?
4. Miten seuraava lausekkeet poikkeavat toisistaan:
2 ** -3
2.0 ** -3
**
**
**
**
(-3)
-3
(-c)
-c
8. Ohjelmakoodissa on mritelty
CHARACTER(LEN=8) :: a = Helsinki
CHARACTER(LEN=8) :: b = juurekas
6. Lausekkeet ja sijoituslauseet
85
86
Fortran 95/2003
Ohjausrakenteet
7.1
7.2
IF-rakenteen avulla voimme antaa ehdon ohjelmalohkon lauseiden suorittamiselle. Taulukossa 7.1 on esitetty IF-rakenteen yleinen muoto.
7. Ohjausrakenteet
87
Jos haluamme tehd jotain muuta IF-rakenteen ehdon ollessa eptosi, voimme kytt ELSE-haaraa:
IF (x /= 0.0) THEN
y = 1.0/x
ELSE
WRITE (*,*) Nollalla jako
y = 0.0
END IF
Voimme sijoittaa IF-rakenteita mys siskkin. Lisksi voimme antaa IFrakenteelle tunnisteen, jolloin erityisesti siskkisten rakenteiden logiikka
voi tulla koodin lukijalle selkemmksi. Mys sisennyst kannattaa kytt, mutta se ei mr ohjelmakoodin logiikkaa. Seuraavassa on esimerkki
siskkisist IF-rakenteista:
ulompi: IF (x /= 0.0) THEN
sisempi: IF (y > 0.0) THEN
t = y/x
ELSE IF (y == 0.0) THEN sisempi
t = 0.0
ELSE sisempi
88
Fortran 95/2003
t = -y/x
END IF sisempi
END IF ulompi
IF-lause vie vhemmn rivej kuin IF-rakenne, mutta se soveltuu vain yksinkertaisiin tapauksiin:
IF (x /= 0.0) y = 1/x
7.3
SELECT CASE -rakenne on IF-lauseen vaihtoehto silloin, kun testaamme, kuuluuko annettu arvo tiettyyn joukkoon arvoja. Yleens testataan
kokonaisluku- tai merkkijonojoukkoja. Fortranin SELECT CASE -rakenne on
monipuolisempi kuin esimerkiksi Pascalin tai C-kielen vastaavat rakenteet.
Rakenteen yleinen muoto on esitetty taulukossa 7.2.
Taulukko 7.2: SELECT CASE -rakenteen yleinen muoto.
7. Ohjausrakenteet
89
Siis jos luku i on joukossa {2, 3, 5, 7}, saa muuttuja alkuluku arvon tosi.
Jos luku on joukossa {1, 4, 6, 8, 9, 10} saa muuttuja arvon eptosi. Muutoin
(lause CASE DEFAULT) lukua i tutkitaan kyttjn mrittelemss funktiossa testaa, joka selvitt, onko annettu luku alkuluku.
Mys merkkijonoja voi kytt SELECT CASE -rakenteen testeiss:
INTEGER, PARAMETER :: mies = 1, nainen = 2, &
tuntematon = -1
CHARACTER(LEN=20) :: nimi
INTEGER :: laji
...
SELECT CASE(nimi)
CASE (Juha, Jussi)
laji = mies
CASE (Maarit, Marita)
laji = nainen
CASE DEFAULT
laji = tuntematon
END SELECT
Esimerkiksi merkki b vastaa kumpaakin CASE-lauseen ehtoa: merkki kuuluu vlille a:z ja lisksi mys vlille aatami:eeva. Tuloksena on
knnsaikainen virheilmoitus.
90
Fortran 95/2003
7.4
Toisto: DO-rakenne
f (xi )
f (xi )
etsii funktion f (x) nollakohtaa ns. Newtonin menetelmll. Seuraavassa ohjelmakoodissa etsitn funktion f (x) = ex + x 5 nollakohtaa alkuarvauksena x0 = 0.
PROGRAM newt
IMPLICIT NONE
CHARACTER(LEN=*), PARAMETER :: muoto = (A,F9.6)
REAL :: x = 0.0
INTEGER :: i, n = 20
WRITE (*,(A,I3)) iteraatioita:, n
WRITE (*,muoto) x:n arvo alussa:, x
DO i = 1, n
x = x - (EXP(x) + x - 5)/(EXP(x) + 1)
WRITE (*,muoto) x:n arvo:, x
END DO
END PROGRAM newt
Toistorakenne aloitettiin DO-lauseella ja lopetettiin END DO -lauseeseen. Ohjelman tulostus voisi olla:
iteraatioita: 20
x:n arvo alussa: 0.000000
x:n arvo: 2.000000
x:n arvo: 1.476812
x:n arvo: 1.317715
x:n arvo: 1.306608
...
x:n arvo: 1.306559
Silmukkamuuttujan on syyt olla kokonaislukutyyppi, sill reaalilukutyyppinen silmukkamuuttuja oli mritelty vanhentuvaksi Fortran 90 -standardin
piirteeksi, ja Fortran 95 -standardista tm piirre on jo poistettu.
DO-rakenteessa voi silmukkamuuttujalle antaa mys erikseen askeleen, mink verran silmukkamuuttujaa muutetaan kullakin iteraatiokierroksella:
DO i = 20, 1, -1
7. Ohjausrakenteet
91
suoritetaan
loppu alku + askel
MAX 0, INT
askel
kertaa. Silmukkamuuttuja saa aluksi arvon alku, ja arvoa kasvatetaan lisyksell askel. Jos silmukkamuuttujan arvo ei ole vlill alku . . . loppu, silmukkaa ei en suoriteta.
Esimerkiksi silmukka DO i = 1, 32, 5 suoritetaan
32 1 + 5
MAX 0, INT
=7
5
kertaa ja silmukkaa DO i = 1, 32, -5 ei suoriteta kertaakaan.
Silmukkamuuttujaa ei saa muuttaa silmukan sisll. Silmukkamuuttujan arvoksi j viimeksi testattu arvo, esimerkiksi silmukassa
DO i = 1, 32, 5
lohko
END DO
92
Fortran 95/2003
d = (EXP(x) + x - 5)/(EXP(x) + 1)
x = x - d
WRITE (*,(A,I3,A,F9.6)) i:, i, , x:n arvo:, x
IF (ABS(d) <= toleranssi*ABS(x)) EXIT
END DO
END PROGRAM newt
arvo alussa:
1, x:n arvo:
2, x:n arvo:
3, x:n arvo:
4, x:n arvo:
5, x:n arvo:
0.000000
2.000000
1.476812
1.317715
1.306608
1.306559
Testi x > 0 suoritetaan ennen silmukan kutakin toistokertaa. Tm DOrakenne on identtinen aiemmin esitetyn DO-rakenteen kanssa, jossa kytettiin silmukan lopetusehtoa
IF (x <= 0) EXIT
7. Ohjausrakenteet
93
Taulukossa 7.3 on esitetty DO-rakenteen yleinen muoto. Monissa tapauksissa DO WHILE -rakenne on luonnollinen tapa esitt ohjelmalohkon toisto.
Toisinaan selvi kuitenkin helpommin kyttmll EXIT- ja CYCLE-lauseita
DO-rakenteen sisll.
Taulukko 7.3: DO-rakenteen yleinen muoto.
[tunniste:] DO
lohko
END DO [tunniste]
[tunniste:] DO muuttuja = lauseke, lauseke[, lauseke]
lohko
END DO [tunniste]
[tunniste:] DO WHILE (ehto)
lohko
END DO [tunniste]
94
Fortran 95/2003
Silmukan sisll lasketaan funktionkutsu MOD(m,n). Tuloksena on jakojnns, joka saadaan, kun m jaetaan n:ll. Sen jlkeen otamme vanhan jakajan
uudeksi jaettavaksi ja jakojnnksen (t) uudeksi jakajaksi. Toisto pttyy,
kun jakojnnkseksi saatu luku on nolla, jolloin viimeisin jakaja on alkuperisten lukujen suurin yhteinen tekij.
Seuraavassa on esimerkki ohjelman kytst:
Anna positiiviset kokonaisluvut m ja n:
88664400 223355000
m: 88664400 n: 223355000
Suurin yhteinen tekij: 2200
7.6
Poikkeusten ksittely
Ohjelmakoodissa tarvitaan toisinaan normaalista poikkeavaa lauseiden suoritusjrjestyst erikoistilanteiden ksittelemiseksi. Usein kyseess on virhetilanne, josta ohjelmakoodin normaali logiikka ei selviydy.
Esimerkiksi silmukoista psee ulos EXIT-lauseella. Voit ksitell erikoistilanteita yhdistmll loogisia muuttujia ja IF-rakenteita:
LOGICAL :: tilanne_ok = .TRUE.
lohko1
IF (tilanne_ok) THEN
! normaali tilanne
lohko2
ELSE
! erikoistilanne
lohko3
END IF
7. Ohjausrakenteet
95
Tss siis siirryttiin lauseeseen 99, jos ehto testi oli tosi. Huomaa, ett saman voi usein tehd IF-rakenteella. GOTO-lause voi olla kuitenkin joskus
tarpeen poistuttaessa siskkisten ohjausrakenteiden keskelt. Tsskin tapauksessa esimerkiksi DO-silmukan EXIT-lause on parempi ohjausrakenne
kuin GOTO, koska kntj pystyy optimoimaan DO-silmukkarakenteen suoritusta, mutta ei GOTO-lauseita.
Hyppylauseen normaalit muodot ovat
GOTO lausenumero
GO TO lausenumero
96
Fortran 95/2003
Usein selvimme kuitenkin kyttmll tilamuuttujaa. Seuraavassa on esimerkki syttoperaation erikoistilanteen ksittelyst:
INTEGER :: tila
tila = 0
READ (*,*,IOSTAT=tila) luku
IF (tila == 0) THEN
Tehdn normaali operaatio
ELSE
Virheen ksittely
END IF
7.9
Yhteenveto
Fortran-kieli sislt kattavan valikoiman ohjausrakenteita lauseiden suoritusjrjestyksen muuttamiseksi. Erityisesti IF- ja SELECT CASE -rakenteet sek DO-silmukka mahdollistavat monimutkaisenkin ohjelmalogiikan selken
toteuttamisen.
Harjoitustehtvi
1. Mit seuraava koodirivi tekee?
IF (x /= 0.0) y = 1/x; z = y/x
i
i
i
i
i
=
=
=
=
=
1, 5
5, 0, -1
10, 1, -2
0, 30, 7
3, 2, 1
7. Ohjausrakenteet
97
b2 4ac
.
2a
(7.1)
Tss a, b ja c ovat reaalilukuja. Jos ptee ehto b2 4ac = 0, on yhtlll vain yksi juuri, ja jos ptee ehto b2 4ac < 0, ei yhtlll ole
reaaliarvoisia juuria. Lue ohjelmassasi vakioiden a, b, c arvot ptteelt,
ja tarkista yhtln ratkaisujen lukumr ennen juurien laskemista.
Huomaa, ett termit b2 ja 4ac voivat aiheuttaa ylivuodon, jos kertoimet
ovat hyvin suuria. Ylivuodon voi vltt skaalaamalla yhtln suurimmalla kertoimella.
Termin b ja diskriminantin b2 4ac vlisess yhteen- tai vhennyslaskussa tapahtuvan pyristysvirheen voi minimoida kyttmll seuraavia ratkaisukaavoja:
diskr = SQRT(b**2-4*a*c)
q = -(b + SIGN(diskr,b))/2
j1 = q/a
j2 = c/q
Vertaile niden kaavojen ja yhtlss (7.1) esitetyn ratkaisukaavan tarkkuutta. Voit kytt esimerkkin yhtl x 2 bx + 1 = 0, kun kerroin
b
1.
8. Ns. Collatzin probleemassa tarkastellaan iteraatiota
ni+1 =
ni /2,
ni parillinen,
(3ni + 1)/2, ni pariton,
n2 = 8,
n3 = 4,
n4 = 2,
n5 = 1,
n6 = 2.
Siis iteraatio ptyy vuorottelemaan lukujen 1 ja 2 vlille. Nin ky kaikille positiivisille kokonaisluvuille (tt ei kuitenkaan ole matemaattisesti todistettu!).
Kirjoita ohjelma, joka laskee sykliin {1, 2} ptymiseen tarvittavien toistojen lukumrn luvuille n0 {1, 2, . . . , 100}.
9. Laajenna edellisen tehtvn ohjelmaa siten, ett iteraation alkuarvoksi
n0 ky mys negatiivinen kokonaisluku tai nolla. Laske, kuinka monta
iteraatiota tarvitaan, kunnes annetusta kokonaisluvusta (positiivinen tai
98
Fortran 95/2003
(1)k1
.
k
k=1
8. Funktiot ja aliohjelmat
99
Funktiot ja aliohjelmat
Kerromme tss luvussa Fortranin funktioiden ja aliohjelmien mrittelyst ja kytst. Funktioita ja aliohjelmia kutsutaan Fortran 95:ss yhteisell
nimell proseduurit. Itse mrittelemiesi proseduurien lisksi voit kytt
Fortranin standardiproseduureja.
100
8.2
Fortran 95/2003
Fortran 95:n yhteydess tarkoitetaan proseduurilla (procedure) joko funktiota (function) tai aliohjelmaa (subroutine). Funktio palauttaa arvon, joten
funktioita kytetn Fortranin lausekkeiden osana. Aliohjelma sen sijaan
siirt tietoa ainoastaan argumenttiensa vlityksell.
Fortranin ksitteist eroaa tlt osin esimerkiksi Pascal-kielen yhteydess
kytetyst terminologiasta: Pascalissa aliohjelma on yleisnimi funktioille ja
proseduureille. Kytmme Fortran-standardin mukaista terminologiaa, jotta Fortran-ohjelmakoodin kirjoittaminen ja lukeminen olisi helpompaa (esimerkiksi sanaa procedure kytetn Fortranin lauseiden osana). Lisksi
mys englanninkielisten ksikirjojen lukeminen on helpompaa, kun ksitteist on tuttu.
8.3
8.4
8. Funktiot ja aliohjelmat
101
RESULT-mrittelyss esitelty tunnusta kytetn funktion palauttaman arvon mrittelemiseen. Myhemmin esittelemme otsikkolauseen vaihtoehtoisia muotoja.
Funktion arvo palautetaan kokonaislukumuuttujassa desim, joka on mainittu RESULT-mrittelyss. Tt muuttujaa saa kytt normaalin muuttujan
tapaan funktion sisll. Muuttujan desim viimeksi saama arvo palautetaan
funktiokutsun arvona.
Kokonaislukumuuttuja i on desimaalit-funktion muodollinen argumentti.
Huomaa, ett funktio desimaalit ei muuta muodollisen argumenttinsa i
arvoa!
Funktion sisll mritelty muuttuja apu on paikallinen muuttuja, joka on
kytettviss vain funktion sisll. Funktiossa voi vapaasti mritell paikallisia muuttujia avuksi tarvittaviin laskentaoperaatioihin.
Voimme kytt funktiota desimaalit pohjelman sisisen funktiona seuraavasti:
PROGRAM desit
IMPLICIT NONE
INTEGER :: n
WRITE (*,*) Anna n:
READ (*,*) n
WRITE (*,*) Luku n: , n
WRITE (*,*) Desimaaleja: , desimaalit(n)
CONTAINS
Funktion desimaalit edell esitetty mrittely
END PROGRAM desimaalit
102
Fortran 95/2003
10101
5
-199
3
Koska Fortranin kokonaislukutyypill voi esitt vain rellisen kokoisia lukuja, ohjelmalle ei voi sytt mielivaltaisen pitki kokonaislukuja.
On mahdollista mritell mys funktio, jolla ei ole yhtn argumenttia. Sulkumerkkej on kuitenkin kytettv sek funktion mrittelyss ett kutsussa:
PROGRAM funtesti
IMPLICIT NONE
WRITE (*,*) Satunnaisluku: , rnd()
CONTAINS
FUNCTION rnd()
IMPLICIT NONE
REAL :: rnd
CALL RANDOM_NUMBER(rnd)
END FUNCTION rnd
END PROGRAM funtesti
8.5
Edell esittelimme RESULT-lausekkeessa funktion arvon palauttavan muuttujan. Paluuarvon sisltv muuttuja voi olla saman niminen kuin funktio.
Tm onnistuu jttmll RESULT-lauseke pois:
FUNCTION desimaalit(i)
IMPLICIT NONE
INTEGER :: i, desimaalit
Tss mriteltiin funktion desimaalit tyypiksi kokonaislukutyyppi. Tyyppimrittelyn voi antaa mys osana otsikkolausetta:
INTEGER FUNCTION desimaalit(i)
8. Funktiot ja aliohjelmat
103
RESULT-lausekkeen kytt on tarpeen erityisesti rekursiivisten (itsen kutsuvien) funktioiden tapauksessa. Tst kerrotaan lis kappaleessa 8.12 (sivu 111).
Tyyliseikoista voi olla monta mielt, mutta useimmiten RESULT-lausekkeen
kytt selkeytt ohjelmakoodia.
ja
i = i/10
104
Fortran 95/2003
8.7
Edellisess kappaleessa esitellyt funktiot palauttavat (yleens) vain funktiokutsun arvon eivtk muuta argumenttiensa arvoja. Usein tarvitaan tt monipuolisempaa tiedonsiirtoa proseduurin ja kutsuvan ohjelman vlill. Tt
varten Fortranissa voidaan mritell ja kytt aliohjelmia (subroutine).
Aliohjelman nimi mritelln SUBROUTINE-lauseessa, ja aliohjelmaa kutsutaan CALL-lauseella. Seuraavassa mrittelemme aliohjelman vaihda kahden reaaliluvun arvojen vaihtamiseksi keskenn:
SUBROUTINE vaihda(a,b)
IMPLICIT NONE
REAL :: a, b
REAL :: apu
apu = a
a = b
b = apu
END SUBROUTINE vaihda
1.000000
-1.000000
-1.000000
1.000000
8. Funktiot ja aliohjelmat
105
kokonaislukuargumentti
kompleksilukuargumentti
merkkitieto
106
Fortran 95/2003
END DO
END FUNCTION isot_merkit
END PROGRAM mjono_testi
Oletetun pituinen merkkijonoargumentti mjono on mritelty kytten merkint LEN=*. Funktio palauttaa merkkijonon uusi, joka on yht pitk kuin
argumentti mjono:
CHARACTER(LEN=LEN(mjono)) :: uusi
8.9
Proseduurin mrittelyss on mahdollista kertoa, mihin suuntaan kukin proseduurin argumenteista siirt tietoa. Tm onnistuu kyttmll INTENTmrett. Seuraavassa aliohjelman mrittelyss kerromme, ett argumentit a ja b siirtvt tietoa kutsuvasta ohjelmayksikst sek aliohjelmaan ett
takaisin pin:
SUBROUTINE vaihda(a,b)
IMPLICIT NONE
REAL, INTENT(INOUT) :: a, b
REAL :: apu
apu = a
a = b
b = apu
END SUBROUTINE vaihda
Mrittely INTENT(INOUT) kertoo, ett aliohjelma vaihda kytt muodollisten argumenttien aliohjelmakutsussa saamia arvoja. Lisksi aliohjelma
muuttaa vastaavien todellisten argumenttien arvoja palattaessa aliohjelmasta kutsuvaan ohjelmayksikkn.
Jos INTENT-mreit ei ole annettu, kntj ei tarkista proseduurin argumenttien kytttapaa. Lisksi INTENT-mre auttaa hahmottamaan ohjelman toimintaa: mre kertoo, mihin suuntaan tietoa siirretn proseduurin
kussakin argumentissa.
INTENT-mritteen kytt est esimerkiksi seuraavan virheellisen aliohjelmakutsun:
CALL vaihda(1.0,2.0)
Tss vlitetn vaihda-aliohjelmaan kaksi vakiota vaihdettaviksi keskenn. Muodollisten argumenttien INTENT(INOUT)-mre johtaa tss tapauksessa knnsaikaiseen virheeseen, koska vakioiden muuttaminen on
kielletty.
INTENT-mreen vaihtoehtoiset muodot ovat
INTENT(IN)
INTENT(OUT)
8. Funktiot ja aliohjelmat
INTENT(INOUT)
INTENT(IN OUT)
107
108
Fortran 95/2003
Funktio nesu laskee argumenttina x annettujen lukujen kumulatiivista nelisummaa kutsukerrasta toiseen.
Alustamme sisisen funktion paikallisen muuttujan nsum arvoltaan nollaksi
ja annamme muuttujalle mreen SAVE. Tmn johdosta muuttuja nsum saa
arvon 0.0 kutsuttaessa funktiota nesu ensimmisen kerran. Tmn jlkeen
muuttujan nsum arvo silyy funktiokutsujen vlill.
Edellisen ohjelman tulostus on
tulos:
tulos:
1.0000000
5.0000000
8.11
Tss luvussa on thn asti kytetty yksinomaan pohjelman sisisi proseduureja (internal procedure). Ne mritelln pohjelman lopussa lauseen
CONTAINS jlkeen.
Sisisten proseduurien lisksi Fortranissa voi mritell ja kytt ulkoisia
proseduureja (external procedure) ja moduulin proseduureja (module procedure). Seuraavassa kerromme tarkemmin sisisist ja ulkoisista proseduureista. Moduulien kytt esitelln luvussa 9 (sivu 126).
8. Funktiot ja aliohjelmat
109
Taulukkoa taulu kutsutaan pohjelman globaaliksi muuttujaksi, koska siihen voidaan viitata mys sisisist aliohjelmista. Globaaleja muuttujia tulisi
kytt harkiten, jottei synny tarpeettomia riippuvuuksia ohjelmayksikiden vlille.
Muuttuja apu on aliohjelman vaihda paikallinen muuttuja, eik se ny pohjelmaan tai pohjelman muihin sisisiin proseduureihin.
Aliohjelman vaihda mrittelyst voisi jtt pois lauseen
IMPLICIT NONE
110
Fortran 95/2003
Ulkoinen funktio desimaalit tytyy knt erikseen ja linkitt pohjelman kanssa ajokelpoiseksi ohjelmaksi.
Koska ulkoinen aliohjelma ei palauta arvoa, tytyy mrittelyyn kytt tyypinmrittelylauseen sijaan EXTERNAL-lausetta vaikkapa seuraavasti:
EXTERNAL vaihda
Ensimmisess funktiokutsussa vlitetn funktioon desimaalit reaalilukuvakio, vaikka funktiossa oletetaan ksiteltvn kokonaislukudataa. Toisessa tapauksessa vlitetn funktiokutsussa kaksi argumenttia, vaikka funktio tarvitsee vain yhden argumentin.
Kappaleessa 8.16 sivulla 116 kerrotaan lis kntjn tekemist proseduurien argumenttilistojen tarkistuksista.
Jos funktio on mritelty sisisen tai moduulin funktiona, huomaa kntj
8. Funktiot ja aliohjelmat
111
8.12
Rekursio
Funktion otsikkorivill on kytettv mrett RECURSIVE. Lisksi otsikkorivill on annettava RESULT-mrittely, jotta voimme kytt rekursiivisen
funktion tunnusta funktion sisll tekemn rekursiivisen funktiokutsun.
Kytmme funktion kert sisll rekursiivista kertomafunktion mritelm.
Jos muodollisen argumentin n arvo on nolla, saa funktio arvon 1. Muussa
tapauksessa kertomafunktion arvo on
kert_arvo = n * kert(n-1)
112
Fortran 95/2003
PROGRAM kertoma
IMPLICIT NONE
INTEGER :: n
DO
WRITE (*,(A),ADVANCE=no) Anna n:
READ (*,*) n
WRITE (*,*) n = , n
IF (n < 0) EXIT
WRITE (*,*) n! = , kert(n)
END DO
CONTAINS
Edell esitetty funktion kert mrittely
END PROGRAM kertoma
8. Funktiot ja aliohjelmat
113
Laajempia ja realistisempia esimerkkej rekursion kytst lytyy luvusta 14 sivulta 234 alkaen.
8.13
Proseduurit argumentteina
Fortranin proseduureihin voi vlitt datan lisksi argumentteina mys toisia proseduureja. Seuraavassa mritelty funktio asteina muuttaa mink
tahansa funktion palauttaman arvon radiaaneista asteiksi. Kytmme esimerkkin Fortranin standardifunktioita ASIN, ACOS ja ATAN:
PROGRAM astesti
IMPLICIT NONE
INTRINSIC ASIN, ACOS, ATAN
WRITE (*,*) arcsin(0.5): , asteina(ASIN,0.5)
WRITE (*,*) arccos(0.5): , asteina(ACOS,0.5)
WRITE (*,*) arctan(1.0): , asteina(ATAN,1.0)
CONTAINS
REAL FUNCTION asteina(f, x)
IMPLICIT NONE
REAL, EXTERNAL :: f
REAL, INTENT(IN) :: x
INTRINSIC ATAN
asteina = 45*f(x)/ATAN(1.0)
END FUNCTION asteina
END PROGRAM astesti
30.00000
60.00000
45.00000
114
Fortran 95/2003
2.0000000
3.0000000
2.0000000
-1.0000000
2.0000000
-1.0000000
2.0000000
-1.0000000
8. Funktiot ja aliohjelmat
8.14
115
PURE-mre
Jos funktio laske on mritelty sivuvaikutuksettomaksi funktioksi PUREmreell, voi kntj laskea silmukan funktiokutsut rinnakkain. PUREmre helpottaa kntjn toimintaa mys ohjelmakoodia optimoitaessa,
joten sen kytt on suositeltavaa.
Mys mrittelylausekkeissa (specication expression) saa kytt puhtaita
(PURE) funktioita:
SUBROUTINE s(a)
IMPLICIT NONE
REAL, DIMENSION(:,:) :: a
REAL, DIMENSION(rivit(a),sarakkeet(a)) :: apu
...
CONTAINS
PURE FUNCTION rivit(x)
REAL, INTENT(IN) :: x(:,:)
INTEGER :: rivit
rivit = SIZE(x,DIM=1)
END FUNCTION rivit
PURE FUNCTION sarakkeet(x)
...
END FUNCTION sarakkeet
END SUBROUTINE s
Edell mriteltiin puhtaat funktiot rivit ja sarakkeet, joiden avulla voimme mritell taulukon apu koon mrittelylauseessa.
8.15
ELEMENTAL-mre
Mre ELEMENTAL mahdollistaa alkioittaisten proseduurien mrittelyn. Tllin proseduurin argumenttina voi olla skalaari tai taulukko, ja kntj huolehtii tarvittavan koodin generoimisesta.
ELEMENTAL FUNCTION f(x, y)
IMPLICIT NONE
REAL, INTENT(IN) :: x, y
REAL :: f
f = SQRT(x**2 + y**2)
END FUNCTION f
116
Fortran 95/2003
8.16
Kutsumuodon mrittely
Proseduurin tai operaattorin kutsumuodolla (interface) tarkoitetaan argumenttien lukumr ja tyyppi sek mahdollisesti palautettavan arvon tyyppi.
Tunnettu kutsumuoto (explicit interface) on kyseess silloin, kun kntj
pystyy knnsaikana selvittmn kutsumuodon sek tekemn thn liittyvi tarkistuksia. Ohjelmayksikn sisisill proseduureilla sek moduulin
proseduureilla on tunnettu kutsumuoto. Moduulien kytst kerrotaan tarkemmin luvussa 9 (sivu 126).
Oletusarvoinen kutsumuoto (implicit interface) on kyseess silloin, kun kntj ei kykene selvittmn olion kutsumuotoa. Ulkoisilla proseduureilla on
oletusarvoinen kutsumuoto.
Jos kutsumuoto ei ole automaattisesti tunnettu, voidaan se mritell ohjelmayksikn INTERFACE-lohkossa. Tm mahdollistaa esimerkiksi argumenttilistojen tarkistuksen kytettess ulkoisia proseduureja.
Voisimme muuttaa edell mritelty aliohjelmaa suorita siten, ett mrittelemme operaatio-argumentin kutsumuodon INTERFACE-lohkossa:
SUBROUTINE suorita(operaatio, t1, t2)
IMPLICIT NONE
INTERFACE
SUBROUTINE operaatio(a,b)
IMPLICIT NONE
REAL, INTENT(INOUT) :: a, b
END SUBROUTINE operaatio
END INTERFACE
REAL, DIMENSION(:), INTENT(INOUT) :: t1, t2
INTEGER :: i
IF (SIZE(t1) /= SIZE(t2)) STOP t1 ja t2 erisuuret!
DO i = 1, SIZE(t1)
CALL operaatio(t1(i),t2(i))
END DO
END SUBROUTINE suorita
Tmn jlkeen kntj huomaisi esimerkiksi seuraavan virheellisen mrittelyn muodollisille argumenteille t1 ja t2:
8. Funktiot ja aliohjelmat
117
Lydtk virheen? Aliohjelman operaatio argumentit a ja b ovat kirjoittamamme INTERFACE-lohkon mukaan tyyppi
REAL, INTENT(INOUT) :: a, b
Tllin aliohjelmakutsu
CALL operaatio(t1(i),t2(i))
8.17
Seuraavassa on esimerkki NAG-aliohjelmakirjaston aliohjelman g05faf kutsumuodon esittmisest INTERFACE-lohkossa. Tm aliohjelma tuottaa tasajakautuneita satunnaislukuja vlilt [a, b].
PROGRAM nagrnd
IMPLICIT NONE
INTEGER, PARAMETER :: tarkkuus = SELECTED_REAL_KIND(12)
INTERFACE
SUBROUTINE g05faf(a, b, n, x)
IMPLICIT NONE
INTEGER, PARAMETER :: tarkkuus = SELECTED_REAL_KIND(12)
REAL(KIND=tarkkuus), INTENT(IN) :: a
REAL(KIND=tarkkuus), INTENT(IN) :: b
INTEGER, INTENT(IN) :: n
REAL(KIND=tarkkuus), INTENT(OUT), DIMENSION(n) :: x
END SUBROUTINE g05faf
END INTERFACE
REAL(KIND=tarkkuus), DIMENSION(5) :: taulukko
CALL g05faf(-1.0_tarkkuus, 1.0_tarkkuus, &
SIZE(taulukko), taulukko)
WRITE (*,*) taulukko
END PROGRAM nagrnd
Tss kytettiin NAG-aliohjelmakirjaston vanhempaa FORTRAN 77 -pohjaista versiota. Saatavilla on mys Fortran 95:een perustuva aliohjelmakirjasto, joka kytt hyvkseen moduuleita ja muita Fortranin kehittyneit
piirteit.
118
Fortran 95/2003
8.18
Valinnaiset ja avainsana-argumentit
Toisinaan on hyv, jos proseduurin kutsussa voi antaa vain osan argumenteista ja kytt oletusarvoja lopuille. Tllaisia argumentteja kutsutaan valinnaisiksi (optional). Useissa Fortranin standardiproseduureissa voi kytt
valinnaisia argumentteja. Seuraavassa on esimerkki tst:
INTEGER, PARAMETER :: tarkkuus = SELECTED_REAL_KIND(6)
Tss jtettiin antamatta eksponentin vaihteluvli lajiparametrin mrittelyss, jolloin funktio SELECTED_REAL_KIND kytt oletusarvoa tlle argumentille.
Avainsana-argumenteilla tarkoitetaan proseduurin argumentin ilmaisemista muodossa avainsana = arvo. Jos kytetn avainsana-argumentteja, on
argumenttien jrjestys vapaa, koska avainsana ilmaisee, mit muodollista
argumenttia kyseinen todellinen argumentti vastaa.
Seuraavassa on esimerkki avainsana-argumenttien kytst:
INTEGER, PARAMETER :: &
tarkkuus = SELECTED_REAL_KIND(r = 30, p = 6)
8.19
8. Funktiot ja aliohjelmat
119
keskiarvo = SUM(x)/SIZE(x)
END FUNCTION keskiarvo
END PROGRAM keskiarvo_testi
Haluaisimme muuttaa funktiota keskiarvo siten, ett keskiarvon laskemisesta voidaan jtt pois liian pienet tai liian suuret luvut. Valinnaiset argumentit mahdollistavat sen, ett samalla funktiolla voi laskea sek tavallisen
keskiarvon ett edell kuvatun muunnelman. Kytnnss tm tapahtuu
antamalla muodollisille argumenteille mre OPTIONAL. Funktiolla PRESENT
voi tarkistaa, onko valinnainen argumentti annettu funktiokutsussa.
Seuraavassa on muutetun funktion mrittely:
REAL FUNCTION keskiarvo(x, alaraja, ylaraja)
IMPLICIT NONE
REAL, DIMENSION(:), INTENT(IN) :: x
REAL, INTENT(IN), OPTIONAL :: alaraja, ylaraja
REAL :: a, b
INTEGER :: i, lkm
a = -HUGE(a)
b = HUGE(b)
IF (PRESENT(alaraja)) a = alaraja
IF (PRESENT(ylaraja)) b = ylaraja
keskiarvo = 0
lkm = 0
DO i = 1, SIZE(x)
IF (x(i) >= a .AND. x(i) <= b) THEN
keskiarvo = keskiarvo + x(i)
lkm = lkm + 1
END IF
END DO
IF (lkm /= 0) THEN
keskiarvo = keskiarvo/lkm
ELSE
keskiarvo = -HUGE(keskiarvo)
END IF
END FUNCTION keskiarvo
Funktiossa kytetn paikallisia muuttujia a ja b ala- ja ylrajojen tallentamiseen. Alussa rajoiksi asetetaan suurimmat negatiiviset ja positiiviset luvut
kyttmll funktiota HUGE. Jos valinnaiset argumentit on annettu, kytetn
rajoina annettuja arvoja:
IF (PRESENT(alaraja)) a = alaraja
IF (PRESENT(ylaraja)) b = ylaraja
Keskiarvo lasketaan muuttujaan keskiarvo DO-silmukassa. Silmukassa tarkistetaan, kuuluuko arvo x(i) halutulle vlille. Arvo x(i) listn muuttujaan keskiarvo vain tss tapauksessa:
IF (x(i) >= a .AND. x(i) <= b) THEN
keskiarvo = keskiarvo + x(i)
lkm = lkm + 1
END IF
Funktion lopussa palautetaan joko laskettu keskiarvo tai itseisarvoltaan suurin muuttujalla keskiarvo esitettviss oleva negatiivinen luku, jos yhtn
120
Fortran 95/2003
1.500
2.500
5.000
Viimeinen funktiokutsu palautti vastauksena itseisarvoltaan suuren negatiivisen luvun, joka ei mahtunut annettuun tulostuskenttn.
Avainsana-argumentteja voi kytt aina, kun proseduurin kutsumuoto on
tunnettu. Valinnaisten argumenttien tapauksessa argumenttilistan keskelt
voi jtt pois argumentteja, jolloin loppuosalle argumenteista on kytettv
avainsanoja.
8. Funktiot ja aliohjelmat
121
8.21
Nkyvyysalueet
Nkyvyysalue (scope) tarkoittaa sit ohjelman lauseiden kokonaisuutta, jossa kukin muuttujan, vakion tms. tunnus tai lausenumero on nkyviss. Kunkin ohjelmayksikn voi katsoa koostuvan joukosta nkyvyysalueita, jotka
eivt mene toistensa kanssa pllekkin.
Nkyvyysalue voi olla jokin seuraavista:
rakenteisen tyypin mrittely
proseduurin kutsumuodon mrittelylohko (interface body) lukuunottamatta kyseisen lohkon sisll olevia rakenteisten tyyppien mrittelyj, kutsumuodon mrittelylohkoja tai proseduureja
ohjelmayksikk (moduuli, pohjelma tai proseduuri) lukuunottamatta
kyseisen ohjelmayksikn sisll olevia rakenteisten tyyppien mrittelyj, kutsumuodon mrittelylohkoja tai proseduureja.
Taulukossa 8.1 on havainnollistettu nkyvyysalueita. Mrittelemme pohjelmassa rakenteisen tyypin kurssilainen, jota kytmme mys aliohjelmassa lue_tiedot. Mrittelemme lisksi funktion apurutiini kutsumuodon INTERFACE-lohkossa.
Pohjelmassa voitaisiin kytt tunnusta nimi vaikkapa muuttujan nimen, vaikka sama tunnus esiintyy tyypin kurssilainen mrittelyss. Tm
122
Fortran 95/2003
PROGRAM oppi
IMPLICIT NONE
TYPE kurssilainen
CHARACTER(LEN=30) :: nimi
REAL :: arvosana
END TYPE kurssilainen
INTEGER, PARAMETER :: lkm = 120
TYPE(kurssilainen), DIMENSION(lkm) :: &
oppilaat
INTEGER :: luokan_koko
CALL lue_tiedot(luokan_koko, oppilaat)
CONTAINS
SUBROUTINE lue_tiedot(koko, taulukko)
INTEGER, INTENT(OUT) :: koko
TYPE(kurssilainen), DIMENSION(:), &
INTENT(OUT) :: taulukko
INTERFACE
FUNCTION apurutiini(lkm)
IMPLICIT NONE
REAL, INTENT(IN) :: lkm
jne.
END FUNCTION apurutiini
END INTERFACE
jne.
END SUBROUTINE lue_tiedot
END PROGRAM oppi
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
alue
1
1
2
2
2
2
1
1
1
1
1
1
3
3
3
3
4
5
5
5
5
5
4
3
3
1
johtuu siit, ett tyypinmrittelyn sisll olevat tunnukset eivt kuulu pohjelman nkyvyysalueeseen eivtk siten mene pllekkin pohjelman
tunnusten kanssa.
Vastaavasti INTERFACE-lohkon sisll voi kytt vapaasti tunnuksia, kunhan ne ovat yksiksitteiset kunkin kutsumuodon mrittelylohkon sisll.
Esimerkiksi funktion apurutiini muodollinen argumentti lkm ei sekoitu
pohjelman saman nimiseen nimettyyn vakioon.
Kun tunnus on mritelty jossakin nkyvyysalueessa, se on kytettviss
kaikkialla nkyvyysalueessa. Jos nkyvyysalueessa otetaan kyttn moduuli USE-lauseella (tst kerrotaan seuraavassa luvussa), ovat kyseisess moduulissa mritellyt tunnukset kytettviss tmn nkyvyysalueen sisll.
Tllin nkyvyysalueessa ei en voi mritell saman nimisi paikallisia
tunnuksia.
Kussakin nkyvyysalueessa voi kytt sek nkyvyysalueen sisll mriteltyj tunnuksia ett sen isnnn nkyvyysalueessa mriteltyj tunnuksia.
Paikallinen tunnus korvaa aina isnnss mritellyn saman nimisen tunnuksen.
8. Funktiot ja aliohjelmat
123
Sisinen proseduuri voi viitata isnnn nkyvyysalueessa mriteltyihin tunnuksiin, jos proseduurissa ei ole mritelty saman nimist paikallista tunnusta. Taulukon 8.1 esimerkiss on pohjelman nimetty vakio lkm kytettviss aliohjelmassa lue_tiedot, jos aliohjelmassa ei mritell saman
nimist tunnusta.
Myskn INTERFACE-lohkon sisiset mrittelyt eivt vaikuta sisisen funktion lue_tiedot nkyvyysalueessa. Huomaa, ett INTERFACE-lohkon sislle
eivt ny lohkon isnnss tehdyt mrittelyt. Siten apurutiini-funktion
kutsumuodon mrittelyss (nkyvyysalue 5) ei ole kytettviss nkyvyysalueissa 1, 2 tai 3 tehtyj mrittelyj.
8.22
Yhteenveto
124
Fortran 95/2003
Harjoitustehtvi
1. Muuta kappaleen 8.8 esimerkkiohjelmaa siten, ett se muuttaa mys
skandinaaviset merkit , ja isoiksi kirjaimiksi.
2. Kirjoita funktio, joka laskee standardifunktioiden SIN, COS ja TAN arvon, kun reaalilukuargumentti annetaan asteina eik radiaaneina. Katso
mallia kappaleesta 8.13 sivulla 113.
3. Kirjoita kertoman laskeva rekursiivinen aliohjelma (ei funktio!), jonka
kutsusyntaksi voisi olla
CALL kertoma(n,tulos)
Kirjoita mys DO-silmukkaversio kertoman laskemiseksi. Vertaile rekursiivisen funktion ja silmukkaversion nopeutta. Voit kytt vertailuun
Unixin time-komentoa, Fortran 90:n standardialiohjelmaa SYSTEM_CLOCK
tai Fortran 95:n aliohjelmaa CPU_TIME.
4. Kirjoita funktio, joka laskee n termi sinifunktion sarjakehitelmst
pisteess x. Sinifunktion sarjakehitelm origon ympristss on
sin x = x
x 2i1
x3
x5
x7
(1)i+1
+
+ =
.
6
120
5040
(2i 1)!
i=1
Huomaa, ett tt sarjakehitelm voi kytt vain, kun |x| 0. Laske likiarvo lausekkeelle sin 0.5 kyttmll 2 tai 4 termi. Laske mys
lausekkeen SIN(0.5) arvo.
Huomaa, ett sarjakehitelmn n:s termi tn toteuttaa yhtln
t1 = x,
tn+1 = tn
x2
.
2n(2n + 1)
8. Funktiot ja aliohjelmat
125
x = 1, x = 1, x = 1,
1
2
3
xn = xn1 + xn2 + xn3 , n > 3.
Laske x12 . Tutki laskenta-ajan kyttytymist n:n funktiona kyttmll Unixin time-komentoa, Fortran 90:n aliohjelmaa SYSTEM_CLOCK tai
Fortran 95:n aliohjelmaa CPU_TIME. Onko rekursiivinen funktio tehokas? Toteuta laskeminen mys silmukkarakenteen avulla.
8. Kirjoita rekursiivinen funktio positiivisen kokonaisluvun m muuntamiseksi kymmenjrjestelmst k-kantaiseen jrjestelmn (1 < k < 100).
Esimerkiksi luku 1996 on 8-jrjestelmss (3714)8 = 3 83 + 7 82 +
81 + 4. Kyt ohjelmassasi hyvksi identiteetti
m = (dn kn1 + dn1 kn2 + + d1 )k + d0
= (m/k) k + MOD(m, k).
Edell merkint m/k tarkoittaa kokonaislukujen jakolaskua.
Kirjoita mys silmukkaversio algoritmista. Vertaile rekursiivisen funktion ja silmukkaversion nopeutta. Voit kytt vertailuun Unixin timekomentoa, Fortran 90:n aliohjelmaa SYSTEM_CLOCK tai Fortran 95:n aliohjelmaa CPU_TIME.
9. Kirjoita proseduuri skalaarifunktion f (x) integroimista varten. Kyt
esimerkiksi Gaussin integroimiskaavaa
I
ba
a+b
a+b
ba
ba
f(
) + f(
+ ) ,
2
2
2
2 3
2 3
126
Fortran 95/2003
Moduulit ja operaattorit
9.1
Modulaarinen ohjelmointi
9. Moduulit ja operaattorit
127
moduuli
CONTAINS
CONTAINS
CONTAINS
ulkoinen proseduuri
CONTAINS
CONTAINS
moduulin
proseduuri
sisinen
proseduuri
128
Fortran 95/2003
9.3
Huomaa, ett lause USE tulee antaa ennen IMPLICIT NONE -lausetta. Jotta
pohjelmassa voidaan kytt moduulia yksikot, on se knnettv ennen
pohjelmaa. Ohjelman kntminen ja ajaminen voisi tapahtua Unix-ympristss seuraavasti:
% f90 -c yksikt.f90
% f90 -o vakiotesti vakiotesti.f90 yksikot.o
% ./vakiotesti
tuumat senttein: 2.539999962
9.4
Edell mritelty moduuli yksikot on melko hankala kytt, koska kyttjn tulisi muistaa, mit vakioarvoja taulukon matkat alkiot vastaavat. Moduulia voi laajentaa siten, ett se sislt ohjelman, joka tekee muunnoksen
halutusta pituusyksikst toiseen. Jatkossa esitmme mys, miten taulukko
matkat voidaan mritell kytettvksi vain moduulin sislt ksin.
9. Moduulit ja operaattorit
129
MODULE yksikot
...
END MODULE yksikot
PROGRAM ohjelma
USE yksikot
...
CALL laske
...
END PROGRAM ohjelma
SUBROUTINE laske
USE yksikot
...
END SUBROUTINE laske
Kuva 9.2: Moduulin yksikot kytt useasta eri ohjelmayksikst. Sek pohjelma ett pohjelman kutsuma aliohjelma laske ottavat moduulin kyttn USElauseella.
metri, kohde)
metri, kohde)
metri, kohde)
metri, kohde)
metri, kohde)
130
Fortran 95/2003
Kytimme sytteess lainausmerkkej merkkijonojen ymprill, vaikka tss tapauksessa ne eivt ole tarpeen, sill merkkijonot tuuma ja cm eivt
sisll esimerkiksi vlilyntej.
9. Moduulit ja operaattorit
131
Jos haluamme myhemmin muuttaa kytetty laskentatarkkuutta suuremmaksi, voimme yksinkertaisesti muuttaa moduulia tarkkuus seuraavasti:
MODULE tarkkuus
IMPLICIT NONE
! INTEGER, PARAMETER :: reaaliluku = SELECTED_REAL_KIND(6)
INTEGER, PARAMETER :: reaaliluku = SELECTED_REAL_KIND(12)
END MODULE tarkkuus
Kun knnmme uudestaan tmn moduulin ja kaikki siit riippuvat moduulit, toimii koko ohjelmistomme suuremmalla tarkkuudella.
132
Fortran 95/2003
maksimiarvo mriteltiin julkisiksi kyttmll mrett PUBLIC, jolloin vakioita voidaan kytt moduulin ulkopuolella USE-lauseen avulla.
Standardifunktio EPSILON palauttaa pienimmn positiivisen liukuluvun ,
jolla ptee 1 + > 1. Standardifunktio HUGE palauttaa suurimman reaaliluvun, joka on esitettviss argumenttia vastaavalla tietotyypill.
Oletuksena on, ett moduulissa mritellyt oliot ovat julkisia. Tllin ne nkyvt niiss ohjelmayksikiss, joissa moduuli otetaan kyttn USE-lauseella.
Moduulia vakiot voisi kytt seuraavasti:
PROGRAM vakiotesti
USE vakiot
IMPLICIT NONE
WRITE (*,*) toleranssi: , toleranssi
WRITE (*,*) maksimi: , maksimiarvo
END PROGRAM vakiotesti
pohjelma vakiotesti
USE vakiot
USE tarkkuus
Kuva 9.3: Moduulien kyttkaavio.
PUBLIC- tai PRIVATE-mreen sijaan voi kytt erillisi lauseita, jotka asettavat moduulin tunnuksen julkiseksi tai yksityiseksi:
MODULE vakiot
USE tarkkuus
IMPLICIT NONE
PRIVATE
REAL(KIND=reaaliluku) :: x
REAL(KIND=reaaliluku), PARAMETER :: &
toleranssi = 100*EPSILON(x), &
maksimiarvo = HUGE(x)
PUBLIC :: toleranssi, maksimiarvo, reaaliluku
END MODULE vakiot
Jos PUBLIC- tai PRIVATE-lauseelle ei anneta argumentteja, asettaa lause oletusarvon moduulin tunnusten julkisuudelle. Edell mriteltiin tunnukset
oletusarvoisesti yksityisiksi lauseella
9. Moduulit ja operaattorit
133
PRIVATE
otetaan kyttn kaikki moduulissa mritellyt julkiset tunnukset. Jos osalle kyttn otetun moduulin tunnuksista halutaan antaa uusi nimi, tm
onnistuu seuraavasti:
USE moduuli[, paikallinen_tunnus => tunnus_moduulissa]...
Jos sama moduuli otetaan kyttn useaan kertaan, ksitelln kyseiset USElauseet yhten kokonaisuutena. Huomaa, ett moduulin olion voi ottaa kyttn vain yhdell nimell. Seuraava on siis kielletty:
USE vakiot, ONLY : maksimiarvo
USE vakiot, ONLY : maksimi => maksimiarvo
Mrittely ONLY kannattaa kytt, sill tllin USE-lauseesta nkee suoraan, mit moduulin tunnuksia ohjelmayksikss kytetn. Lisksi tllin
on helpompi vltt koniktit moduulissa mriteltyjen tunnusten ja ohjelmayksikn omien tunnusten kesken.
134
Fortran 95/2003
9.8
Esimerkki: muunnosohjelma
Kappaleissa 9.3 ja 9.4 esitellyn yksikot-moduulin vakiotaulukko matkat nkyy moduulin ulkopuolelle. Tm johtaa virhetilanteeseen esimerkiksi seuraavassa tapauksessa:
USE yksikot
IMPLICIT NONE
REAL :: matkat
9. Moduulit ja operaattorit
135
0.0254, &
0.3048, &
0.9144, &
1e3, &
1609.34 /)
PUBLIC :: muunna_r
CONTAINS
Funktion muunna_r mrittely
!
!
!
!
!
tuumat
jalat
jaardit
kilometrit
mailit
150
100
f (x)
50
465
1
2
x
Jatkuvan funktion nollakohta voidaan hakea puolitushaulla (bisection). Aiemmin kappaleessa 7.4 sivulla 90 kytimme nollakohdan hakuun Newtonin
menetelm. Puolitushaussa lhdetn vlist [a, b], jossa funktion arvojen
136
Fortran 95/2003
f (a) ja f (b) tiedetn olevan erimerkkisi. Kullakin iteraatiolla vli puolitetaan, ja jatkoon otetaan se vli, jolla funktion arvot ovat edelleen erimerkkisi ptepisteiss. Funktiolle f (x) = ex + x 5 voidaan valita haun
aloittamiseen esimerkiksi vli [0, 5], koska f (0) = 4 < 0 ja f (5) = e5 > 0.
Seuraava moduuli sislt funktion puolitushaku nollakohdan etsintn:
MODULE nollakohta
IMPLICIT NONE
PRIVATE
REAL, PARAMETER :: toleranssi = 1e3*EPSILON(1.0)
PUBLIC :: puolitushaku
CONTAINS
FUNCTION puolitushaku(f, a, b) RESULT(hakupiste)
IMPLICIT NONE
INTERFACE
FUNCTION f(x) RESULT(f_arvo)
REAL, INTENT(IN) :: x
REAL :: f_arvo
END FUNCTION f
END INTERFACE
REAL, INTENT(IN) :: a, b ! Hakuvlin ptepisteet
REAL :: x1, x2, hakupiste, arvo
LOGICAL :: merkki
x1 = a
x2 = b
merkki = f(x1) < 0.0
IF (merkki .EQV. (f(x2) < 0)) THEN
WRITE (*,*) Ptepistearvot samanmerkkiset!
hakupiste = -HUGE(hakupiste)
ELSE
DO WHILE (ABS(x1 - x2) > toleranssi*ABS(x1))
hakupiste = 0.5*(x1+x2)
arvo = f(hakupiste)
IF ((arvo < 0.0) .EQV. merkki) THEN
x1 = hakupiste
ELSE
x2 = hakupiste
END IF
END DO
END IF
END FUNCTION puolitushaku
END MODULE nollakohta
Funktiossa puolitushaku mriteltiin muodollisen argumentin f kutsumuoto INTERFACE-lohkossa. Tten funktion sisll tehdn kutsumuodon
mukaiset tarkistukset kytettess funktiota f.
Lausekkeen f (x) = ex + x 5 nollakohta voidaan nyt hakea puolitushaulla
seuraavasti:
PROGRAM ratkaisu
USE yhtalo, ONLY : fun
USE nollakohta, ONLY : puolitushaku
IMPLICIT NONE
9. Moduulit ja operaattorit
137
REAL :: x
x = puolitushaku(fun, 0.0, 5.0)
IF (ABS(x) < HUGE(x)) THEN
WRITE (*,*) Nollakohta:, x, fun(x)
END IF
END PROGRAM ratkaisu
1.3066101
2.4127960E-04
Huomaa, ett muuttujalle toleranssi annettiin mre SAVE. Koska muuttuja toleranssi alustetaan mrittelylauseessa, saa se automaattisesti SAVEmreen, joten mreen voisi jtt poiskin.
Jos SAVE-mrett ei ole annettu eik muuttujaa alusteta mrittelylauseessa, silyy muuttujan arvo moduulia kyttvien proseduurien kutsukertojen
vlill vain siin tapauksessa, ett moduuli otetaan kyttn mys pohjelmassa.
Moduulia nollakohta voisi nyt kytt seuraavasti:
PROGRAM ratkaisu
USE yhtalo, ONLY : fun
USE nollakohta, ONLY : puolitushaku, toleranssi
IMPLICIT NONE
REAL :: x
toleranssi = 1E-5
x = puolitushaku(fun, 0.0, 5.0)
WRITE (*,*) Nollakohta:, x, fun(x)
END PROGRAM ratkaisu
Tss muutettiin toleranssin oletusarvoa ennen nollakohdan hakua. Toleranssin voisi tietysti mritell mys rutiinin puolitushaku valinnaiseksi
argumentiksi, jolloin ei tarvita erillist julkista muuttujaa.
138
Fortran 95/2003
9.11
Esimerkki: normaalijakautuneet
satunnaisluvut
1
2 ln(x12 + x22 )
t=
x12 + x22
x2
y1 = tx1 ja y2 = tx2
1
1
x1
Seuraavan moduulin funktio normaali tuottaa normaalijakautuneen satunnaisluvun edell kuvatulla menetelmll. Koska algoritmi tuottaa kerralla
kaksi satunnaislukua, toinen niist otetaan talteen moduulin yksityiseen
muuttujaan talletettu_arvo.
MODULE satunnaisluvut
USE tarkkuus, ONLY : reaaliluku
IMPLICIT NONE
PRIVATE
REAL (KIND=reaaliluku), SAVE :: talletettu_arvo
LOGICAL, SAVE :: talletettu = .FALSE.
PUBLIC :: normaali
CONTAINS
FUNCTION normaali() RESULT(arvo)
IMPLICIT NONE
REAL (KIND=reaaliluku) :: arvo
REAL (KIND=reaaliluku), DIMENSION(2) :: x
REAL (KIND=reaaliluku) :: x_nelio, apu
9. Moduulit ja operaattorit
139
Aliohjelma RANDOM_NUMBER tuottaa satunnaislukuja vlilt [0, 1), joten ohjelmassa skaalataan luvut vlille [1, 1). Algoritmissa tarvitaan satunnaislukuja vlilt (1, 1), mutta algoritmi hylk ne pisteet, joissa toinen koordinaateista saa arvon 1. Tmn vuoksi tt erikoistapausta ei tarvitse ksitell erikseen.
Moduulin ainoa julkinen olio on funktio normaali. Yksityinen looginen
muuttuja talletettu kertoo, onko edellisell funktion kutsukerralla luotu satunnaisluku kytettviss.
Seuraavassa kyttesimerkiss pyydetn sytteen normaalijakautuneiden
satunnaislukujen lukumr. Ohjelma tuottaa ja tulostaa satunnaisluvut
kutsumalla funktiota normaali.
PROGRAM satunnaistesti
USE satunnaisluvut, ONLY : normaali
IMPLICIT NONE
INTEGER :: i, n
WRITE (*,(A),ADVANCE=NO) Anna n:
READ (*,*) n
DO i = 1, n
WRITE (*,(F10.6)) normaali()
END DO
END PROGRAM satunnaistesti
140
Fortran 95/2003
pohjelma satunnaistesti
USE satunnaisluvut
USE tarkkuus
Kuva 9.6: Ohjelmayksikiden kutsukaavio.
9.12
Geneeriset proseduurit
Geneerinen proseduuri voi toimia eri tavalla sen mukaan, mink tyyppisi
argumentteja sille annetaan. Monet Fortranin standardifunktioista ovat geneerisi: esimerkiksi trigonometriselle funktiolle SIN voi antaa argumentiksi vaikkapa reaaliluvun, kompleksiluvun tai taulukkotyyppisen argumentin.
Geneerisyytt kutsutaan joskus mys termill ylilataaminen (overloading)
eli operaation mrittelyalueen laajentaminen.
Kappaleissa 9.3, 9.4 ja 9.8 mrittelimme funktion muunna_r, jota voitiin
kytt seuraavasti:
muunna_r(3.0, tuuma, cm)
Voimme kuitenkin mritell uuden funktion muunna_i, joka kutsuu aiemmin mritelty muunna_r-funktiota:
REAL FUNCTION muunna_i(x, alkup, kohde) RESULT(tulos)
IMPLICIT NONE
INTEGER, INTENT(IN) :: x
CHARACTER(LEN=*), INTENT(IN) :: alkup, kohde
tulos = muunna_r(REAL(x), alkup, kohde)
END FUNCTION muunna_i
Geneerinen nimi muunna tytyy mritell INTERFACE-lohkossa ennen moduulin CONTAINS-lausetta. Geneerist nime vastaavat moduulin proseduu-
9. Moduulit ja operaattorit
141
rit voi luetella lauseessa MODULE PROCEDURE. Kaikkien tietty geneerist nime vastaavien proseduurien tytyy olla joko funktioita tai aliohjelmia.
MODULE yksikot
IMPLICIT NONE
PRIVATE
Edell esitetty vakiotaulukko matkat
INTERFACE muunna
MODULE PROCEDURE muunna_i, muunna_r
END INTERFACE
PUBLIC :: muunna
CONTAINS
REAL FUNCTION muunna_i(x, alkup, kohde) RESULT(tulos)
IMPLICIT NONE
INTEGER, INTENT(IN) :: x
CHARACTER(LEN=*), INTENT(IN) :: alkup, kohde
REAL :: tulos
tulos = muunna(REAL(x), alkup, kohde)
END FUNCTION muunna_i
RECURSIVE FUNCTION muunna_r(x, alkup, kohde) RESULT(tulos)
Edell esitetty mrittely
END FUNCTION muunna_r
END MODULE yksikot
142
Fortran 95/2003
INTEGER, INTENT(INOUT) :: i
END SUBROUTINE sub1
SUBROUTINE sub2(i,x)
IMPLICIT NONE
INTEGER, INTENT(INOUT) :: i
REAL, INTENT(INOUT) :: x
END SUBROUTINE sub2
END INTERFACE
Riippuen geneerisen funktion f reaalilukuargumentin x lajista valitaan suoritettavaksi joko funktio f_single tai funktio f_double. Kaksoistarkkuuden lajiparametri on mritelty vaatimalla tyypilt tarkuutta kaksi kertaa
normaalitarkkuuden verran. Tmn pitisi olla melko koneriippumaton tapa mritell FORTRAN 77:n tyyppi DOUBLE PRECISION vastaava reaalilukulaji.
9.13
Operaattoreiden mrittely
9. Moduulit ja operaattorit
143
Voimme mys mritell uusia kyttjn mrittelemi operaattoreita, joiden nimi alkaa pisteell ja pttyy pisteeseen. Esittelemme myhemmin tss kappaleessa operaattorin .fmt. mrittelyn ja kytn.
Kyttjn mrittelemt yksiargumenttiset operaattorit ovat suoritusjrjestykseltn vahvemmat kuin muut Fortranin lausekkeiden termit. Siten esimerkiksi lausekkeiden
(A, // (.fmt. 10) // )
(A, // .fmt. 10 // )
suoritusjrjestys on sama. Kyttjn mrittelemt kaksiargumenttiset operaattorit ovat puolestaan suoritusjrjestykseltn heikoimmat, joten tllaisia operaattoreita sisltvien lausekkeiden yhteydess voivat sulut olla tarpeen.
Luomme seuraavassa moduulin muotoilu, jossa mrittelemme uusia operaattoreita merkkijonoille. Ainoa merkkijonoille mritelty operaatio on (vertailuoperaatioiden lisksi) liitosoperaatio (//). Kytettvissmme on siten
operaattorit **, *, /, + ja -.
144
Fortran 95/2003
Standardifunktio REPEAT toistaa merkkijonoa niin monta kertaa kuin haluamme. Moduulissa on tarpeen mritell erillinen funktio kummallekin
toisto-operaattorin kytttavalle (toistokerrat annetaan joko ennen merkkijonoa tai sen jlkeen).
Seuraavassa on esimerkki moduulin kytst:
PROGRAM muotoilutesti
USE muotoilu
WRITE (*,(A)) 4*Hurraa!
WRITE (*,(A)) 3*Hei! *2
END PROGRAM muotoilutesti
9. Moduulit ja operaattorit
145
Seuraavat mrittelyt voi list edell kytettyyn muotoilu-moduuliin. Emme kyt Fortran 95:n standardioperaattoreita vaan luomme uuden nimetyn
operaattorin .fmt. (nimen tytyy alkaa pisteell ja ptty pisteeseen).
INTERFACE OPERATOR(.fmt.)
MODULE PROCEDURE minimileveyskoodi
END INTERFACE
Funktio palauttaa muotoilukoodin kolmen merkin pituisessa merkkijonossa. Kokonaisluvun vaatiman kentn leveys (ilman etumerkki) saadaan selville sisisell funktiolla desimaalit. Tmn jlkeen tulostetaan tarvittavan
kentn pituus merkkijonoon mjono ja listn muotoilukoodin alkuun viel
merkki I.
Edell mritelty operaattoria .fmt. voi nyt kytt seuraavasti:
PROGRAM muotoilutesti
USE muotoilu
IMPLICIT NONE
INTEGER :: m = 1996
CHARACTER(LEN=10) :: formaatti
formaatti = (A, // .fmt. m // ,A)
WRITE (*,(A)) Muotoilukoodi: // formaatti
WRITE (*, formaatti) Luku on , m, .
m = -100000*m
formaatti = (A, // .fmt. m // ,A)
146
Fortran 95/2003
Aliohjelmassa kokonaisluku tulostetaan kokonaisluku n tarvittavan pituiseen merkkijonomuuttujaan apu kytten sisist tiedostoa (sivu 209). Tulostamiseen kytetn operaattorin .fmt. tuottamaa muotoilukoodia. Merkkijonoargumentti mjono on mritelty seuraavasti:
CHARACTER(LEN=*), INTENT(OUT) :: mjono
9. Moduulit ja operaattorit
147
Tllin sijoituslauseen vasemmalla puolella voi olla mink pituinen merkkijono tahansa.
9.14
Kun mrittelemme yksiargumenttisen operaattorin, tulee INTERFACElohkossa esiintyvien proseduurien olla yksiargumenttisia funktioita, joiden muodollisella argumentilla on mre INTENT(IN). Jos luettelemme
INTERFACE-lohkossa useamman funktion nimet, tytyy niden argumenttien tyypin poiketa toisistaan. Tm sen vuoksi, ett kntj pystyy knnsaikana valitsemaan, mik funktiokutsu tulee sijoittaa operaattorin paikalle.
Kaksiargumenttista operaattoria mriteltess tulee INTERFACE-lohkossa
esiintyvien proseduurien olla kaksiargumenttisia funktioita, joiden argumenteilla on mre INTENT(IN). Ensimminen muodollinen argumentti vastaa operaattorin vasenta argumenttia ja toinen oikeaa argumenttia.
Sijoitusoperaattorille mritelln uusi merkitys seuraavasti:
INTERFACE ASSIGNMENT(=)
[MODULE PROCEDURE proseduurin_tunnus &
[, proseduurin_tunnus]...]...
END INTERFACE
Lohkossa esiintyvien proseduurien tulee olla aliohjelmia, joiden ensimminen argumentti on tyyppi INTENT(OUT) ja toinen argumentti puolestaan tyyppi INTENT(IN). Nm muodolliset argumentit vastaavat sijoituslauseen vasenta ja oikeaa puolta. Muodollisten argumenttien tyyppien tulee
poiketa valmiiksi mritellyist sijoituslauseen merkityksist sek muista
kyseisess INTERFACE-lohkossa esiintyvien aliohjelmien tyypeist.
9.15
148
Fortran 95/2003
Harjoitustehtvn on edell mriteltyj merkkijono-operaatioita vastaavien funktioiden mrittely. Nit merkkijonofunktioita voisi kytt vaikkapa seuraavasti:
PROGRAM muotoilutesti
USE muotoilu
IMPLICIT NONE
INTEGER :: m = 1996
CHARACTER(LEN=10) :: tulostus, formaatti
tulostus = mjono(m)
WRITE (*,(A)) Vuosi on // TRIM(tulostus) // .
formaatti = (A, // fmt(m) // ,A)
WRITE (*,(A)) Muotoilukoodi: // formaatti
WRITE (*, formaatti) Luku on , m, .
END PROGRAM muotoilutesti
9.16
9.17
Yhteenveto
9. Moduulit ja operaattorit
149
Tss luvussa kytiin nopeassa tahdissa lpi moduulien kyttmahdollisuuksia. Lis esimerkkej lytyy luvusta 14 (sivu 234). Koska moduuliajattelun oppii ainoastaan ohjelmoimalla, kannattaa seuraaviin harjoitustehtviin perehty kunnolla! Voit mys toteuttaa jonkin oman ohjelmointitehtvsi kytten moduuleita.
Harjoitustehtvi
1. Lis merimailin ja valovuoden pituusyksikt kappaleessa 9.12 sivulla
140 esitettyyn muunnosohjelmaan.
2. Mrittele geneerinen aliohjelma vaihda, jonka avulla voi vaihtaa argumenttien arvot keskenn:
INTEGER :: i, j
REAL :: x, y
CHARACTER(LEN=10) :: rivi1, rivi2
...
CALL vaihda(i,j)
CALL vaihda(x,y)
CALL vaihda(rivi1,rivi2)
150
Fortran 95/2003
5. Muuta kappaleen 9.9 (sivu 135) nollakohdan hakurutiinia siten, ett menetelmn kytetn Newtonin menetelm (katso mallia kappaleesta
7.4 sivulta 90).
6. Mrittele merkkijonojen muunnosmoduuli, jonka sisltmt funktiot
isot_merkit ja pienet_merkit muuttavat argumenttinaan saamansa
merkkijonot isoiksi tai pieniksi kirjaimiksi. Ota huomioon mys skandinaaviset merkit!
7. Mrittele funktio fmt, joka palauttaa merkkijonona tss luvussa mritelty operaattoria .fmt. vastaavan kokonaisluvun muotoilukoodin
seuraavasti:
formaatti = (A, // fmt(m) // ,A)
9. Mrittele moduulissa satunnaislukuja tuottava funktio rnd, joka palauttaa annetun mrn tasajakautuneita satunnaislukuja. Funktiolla on
kaksi valinnaista argumenttia, joilla voi mrt, mille vlille [a, b) satunnaisluvut skaalataan. Seuraavassa on funktion kyttesimerkkej:
INTEGER, PARAMETER :: n = 10
REAL, DIMENSION(n) :: x, y
x = rnd(n)
y = rnd(n,-1.0,1.0)
R = R + R ,
resistanssit sarjassa,
1
2
1/R = 1/R1 + 1/R2 , resistanssit rinnakkain.
Mrittele reaalilukumuuttujia ksittelevt operaattorit, joita voidaan
kytt seuraavasti:
REAL :: r, r1, r2
r = r1 .sarjassa. r2
r = r1 .rinnakkain. r2
11. Laajenna edell mriteltyjen operaattorien kyttaluetta siten, ett niit voi kytt mys yksiargumenttisina operaattoreina seuraavasti:
REAL, DIMENSION(5) :: r0
REAL :: r
r = .sarjassa. r0
r = .rinnakkain. r0
9. Moduulit ja operaattorit
151
13. Laajenna edell mriteltyj operaattoreita siten, ett voit antaa operaattorin vasemmanpuoleisena argumenttina loogisen taulukon, joka
kertoo mitk alkiot tulee ottaa mukaan keskiarvon tai keskihajonnan
laskemiseen:
keskiarvo = (x >= -1 .AND. x <= 1) .karvo. x
14. Mrittele yksiargumenttiset operaattorit + ja -, jotka muuttavat merkkijonon isoiksi tai pieniksi kirjaimiksi:
WRITE (*,*) +Isoiksi kirjaimiksi!
WRITE (*,*) -PIENET KIRJAIMET!
15. Mrittele kaksiargumenttinen operaattori -, joka poistaa merkkijonosta annetut merkit ja lis merkkijonon loppuun vastaavan mrn vlilyntej:
WRITE (*,*) Teksti - k
WRITE (*,*) Teksti - ts
16. Mrittele operaattori /, joka liitt yhteen etu- ja sukunimen sisltvt merkkijonot ja muuttaa kummankin ensimmisen kirjaimen isoksi
ja loput pieniksi. Nimien vliin tulee yksi vlilynti. Seuraavassa on esimerkki operaattorin kytst:
mjono = etu
SUKUA
x = 1, x = 1,
1
2
xn = xn1 + xn2 , n > 2.
Funktion tulisi muistaa aiemmin lasketut luvut annettuun maksimiarvoon asti. Seuraavassa on moduulin kyttesimerkki:
PROGRAM fibotest
USE fibomod, ONLY : fibo, fibo_max
fibo_max = 100
WRITE (*,*) fibo(10): , fibo(10)
WRITE (*,*) fibo(12): , fibo(12)
END PROGRAM fibotest
152
Fortran 95/2003
10
Rakenteiset tietotyypit
Esittelemme tss luvussa rakenteisten tietotyyppien mrittelyn ja annamme kyttesimerkkej rakenteisista tyypeist. Kerromme mys operaattoreiden mrittelyst ja kytst sek abstraktien tietotyyppien luomisesta.
10.1
Aiemmista FORTRAN-versioista poiketen Fortran 95 sislt mahdollisuuden kytt rakenteisia tietotyyppej (derived type) taulukoiden ja skalaarien lisksi. Rakenteisten tietotyyppien kytll voi selkeytt ohjelmaa kokoamalla yhteen muuttujaan toisiinsa liittyvi tietoja.
Yhdistmll moduulit ja rakenteiset tietotyypit voimme mritell tietorakenteillemme halutunlaisia operaatioita. Toisin sanoen voimme rakentaa
abstrakteja tietotyyppej, jotka koostuvat datasta sek datalle mritellyist operaatioista. Tllaisesta lhestymistavasta on esimerkkej myhemmin
tss luvussa.
Oman tietotyypin mrittely nytt esimerkiksi tlt:
TYPE vektorityyppi
REAL :: x
REAL :: y
REAL :: z
END TYPE vektorityyppi
Tm tietotyyppi koostuu kolmesta reaalilukutyyppisest alkiosta. Kun tietotyyppi on mritelty, voidaan uutta tyyppi oleva muuttuja mritell ohjelmassa esimerkiksi seuraavilla lausekkeilla:
TYPE(vektorityyppi) :: v
TYPE(vektorityyppi), DIMENSION (100) :: solmut
Rakenteista tietotyyppi olevan muuttujan alkioihin voidaan viitata prosenttimerkin (%) avulla seuraavasti:
v % y = 1.1
solmut(1:100) % x = 0.0
solmut(1:100) % y = 1.0
153
Tyyppimrittely luo mys tyyppirakenteen alustimen, joka palauttaa arvonaan tmn tyyppisen tieto-olion. Tyyppialustimen nimi on sama kuin tyypinkin.
Seuraavassa sijoitamme rakenteiseen muuttujaan v luvut (1.0, 2.0, 3.0), jotka WRITE-lause tulostaa.
v = vektorityyppi( 1.0,2.0,3.0 )
WRITE(*,*) v % x, v % y, v % z
154
Fortran 95/2003
TYPE kolmiotyyppi
REAL :: pinta_ala
TYPE(vektorityyppi) :: normaali
TYPE(vektorityyppi), DIMENSION(3) :: karkipisteet
END TYPE kolmiotyyppi
Ohjelmassa kytettiin taulukkoalustinta (/ ... /) muodostamaan kolmialkioinen taulukko tyypin vektorityyppi alkioista.
Fortran-standardi ei mrittele oletusarvoista rakenteen alkioiden talletusjrjestyst muistissa (kuten ei taulukon alkioidenkaan), vaan tm on toteutuskohtaista. Rakenteen alkiojrjestyksen voi kuitenkin pakottaa vastaa-
155
Mrett SEQUENCE tarvitaan kytnnss vain silloin, kun rakenteisen tyypin muuttujia halutaan vlitt eri ohjelmointikielten vlill.
Rakenteisen tyypin alkioille voi antaa mys oletusarvot suoraan tyypin mrittelyss:
PROGRAM kolmio_testi
IMPLICIT NONE
INTEGER, PARAMETER :: rkd = SELECTED_REAL_KIND(6,30)
REAL, PARAMETER :: alkuarvo = HUGE(1.0_rkd)
TYPE vektorityyppi
REAL(KIND=rkd) :: x = alkuarvo
REAL(KIND=rkd) :: y = alkuarvo
REAL(KIND=rkd) :: z = alkuarvo
END TYPE vektorityyppi
TYPE kolmiotyyppi
REAL(KIND=rkd) :: pinta_ala = alkuarvo
TYPE(vektorityyppi) :: normaali
TYPE(vektorityyppi), DIMENSION(3) :: karkipisteet
END TYPE kolmiotyyppi
TYPE(kolmiotyyppi) :: kolmio
WRITE (*,*) kolmio % normaali
END PROGRAM kolmio_testi
3.4028235E+38
3.4028235E+38
156
Fortran 95/2003
Voimme mritell moduuliin vektorilaskenta funktioita, jotka ksittelevt tyypin vektorityyppi tieto-olioita. Aluksi mrittelemme funktiot,
157
Lopuksi teemme funktiot, jotka mrittelevt loput vektorityyppiin kohdistuvista operaatioista: pistetulo, vektorin pituus ja vektoriristitulo.
FUNCTION pistetulo(v1, v2) RESULT(tulos)
! Funktio palauttaa arvonaan vektoreiden
! v1 ja v2 pistetulon
IMPLICIT NONE
REAL :: tulos
TYPE(vektorityyppi), INTENT(IN) :: v1, v2
tulos = v1 % x * v2 % x
tulos = tulos + v1 % y * v2 % y
tulos = tulos + v1 % z * v2 % z
END FUNCTION pistetulo
FUNCTION vektorinormi( v ) RESULT(pituus)
! Funktio palauttaa arvonaan vektorin v pituuden
IMPLICIT NONE
REAL :: pituus
TYPE(vektorityyppi), INTENT(IN) :: v
pituus = SQRT(pistetulo(v,v))
END FUNCTION vektorinormi
158
Fortran 95/2003
Vektori u: , u
Vektori v: , v
Vektorin u pituus: , pituus
Vektoreiden u ja v ristitulo: , w
Vektoreiden u ja v pistetulo: , k
10.3
1.000
NULL-funktio
Fortran 95:ess (mutta ei Fortran 90:ss) osoitintaulukot voi alustaa kohteesta irrotetuiksi (disassociated) NULL-funktion avulla:
REAL, DIMENSION(:), POINTER
:: t => NULL()
159
TYPE :: pinotyyppi
REAL, DIMENSION(:), POINTER :: arvot => NULL()
INTEGER :: huippu = -1
END TYPE pinotyyppi
TYPE(pinotyyppi) :: &
pino, & ! Oletusalustus
pino2 = pinotyyppi(NULL(),0)
Tllin moduulia kyttv ohjelma ei voi viitata alkioihin suoraan. Tst seuraa mys se, ett tarvittaessa voimme vaihtaa tyypin mrittelyn ja moduulin toteutuksen toiseksi ilman, ett moduulia kyttvi ohjelmia tarvitsisi
muuttaa. Tyypin alkioista osa ei voi olla julkisia ja osa yksityisi, vaan joko
kaikki ovat julkisia tai kaikki yksityisi.
160
Fortran 95/2003
uusi % x =
uusi % y =
uusi % z =
END FUNCTION
x
y
z
vektori
Vektorin arvo mrtn kyttmll funktiota vektori ja vektorin komponentit saadaan selville funktiolla komponentit.
Voisimme laajentaa vektorityypin mrittely viel esimerkiksi siten, ett
se sislt tiedon koordinaattisysteemist, jossa vektorin komponentit on
esitetty:
TYPE vektorityyppi
PRIVATE
REAL :: x, y, z
TYPE(koordinaatisto) :: nykykoordinaatisto
END TYPE vektorityyppi
161
Voisimme mys laajentaa vektorityypin ksittelemn n-ulotteisen avaruuden vektoreita, jolloin vektorin komponentit kannattaisi alunperinkin esitt
taulukkona:
TYPE vektorityyppi
PRIVATE
INTEGER :: n
REAL DIMENSION(:), POINTER :: komponentit
TYPE(koordinaatisto) :: nykykoordinaatisto
END TYPE vektorityyppi
Vektorin alustavan proseduurin tehtviin kuuluu nyt mys varata komponenteille tarpeellinen mr tilaa. Dynaamisesta tilanvarauksesta kerrotaan
kappaleessa 11.11 (sivu 178) ja POINTER-mreell luoduista osoitinmuuttujista kappaleessa 11.13 (sivu 183).
10.6 Yhteenveto
Voit huomattavasti selkeytt ohjelmaa tehtvn sopivalla tietotyypin valinnalla. Tm samalla helpottaa ratkaisualgoritmin toteutusta. Yhdistmll rakenteiset tietotyypit ja moduulit voit luoda abstrakteja tietotyyppej
sek piilottaa toteutuksen yksityiskohdat kyttjlt, jonka ei nit yleens
tarvitse tiet.
Tyyppimrittely tehdn seuraavasti:
TYPE [, julkisuus ::] nimi
muuttujamrittelyt
END TYPE nimi
Tyyppimrittely luo rakenteen alustimen, jonka nimi on sama kuin tyypinkin. Alustinta kytetn antamaan rakenteisen tietotyypin muuttujalle
arvo:
muuttuja = tyyppi(arvo1,...,arvon)
Harjoitustehtvi
1. Laske vektorimoduulilla pistetulo vektoreista, joista toinen on kahden
vektorin ristitulo ja toinen jompi kumpi alkuperisist vektoreista. Mit
saat tulokseksi? Miksi?
Kirjoita vektorikolmitulon laskeva funktio, jonka otsikkorivi on
162
Fortran 95/2003
Mrittele funktio normaali(k), joka laskee kolmion k yksikknormaalin. Vihje: muodosta vektorit v1 = t2-t1 ja v2 = t3-t1, miss suureet
t1,t2 ja t3 ovat kolmion krkipisteiden paikkavektorit ja kyt hyvksesi edellisen harjoitustehtvn tulosta. Onko normaali mielestsi yksiksitteinen?
Mrittele mys kolmion pinta-alan laskeva funktio pinta_ala(k).
3. Lis vektorimoduuliin operaatio, joka tarkistaa, ovatko kaksi vektoria
likimain samat. Kyt tss operaattorin == ylilatausta. (Likimrinen
yhtsuuruus mritelln tehtvss 9 sivulla 65.)
4. Laajenna kolmiotyypin mrittely ksittmn yleinen tasomonikulmio.
5. Lis vektorimoduuliin operaatiot, joka muuntavat vektorin komponentit karteesisesta koordinaatistosta pallokoordinaatistoon ja pinvastoin.
Niden funktioiden otsikkolauseet ovat
FUNCTION vektori_pallo(r, theta, phi) RESULT(vektori)
ja
FUNCTION komponentit_pallo(vektori) RESULT(tulostaulukko)
Koska moduulin sisinen esitysmuoto on karteesinen, funktioiden tytyy tehd tarpeelliset muunnokset. Muunnos karteesiseen koordinaatistoon tapahtuu kaavoilla
x = r sin cos ,
y = r sin sin ,
z = r cos .
6. Mrittele aliohjelma vaihda, joka vaihtaa kahden vektorin arvot keskenn:
CALL vaihda(v1,v2)
Siis rakenteinen tyyppi sislt kolme kokonaislukua, joilla on eri KINDarvot: SELECTED_INT_KIND(2) ja SELECTED_INT_KIND(4).
8. Lis edellisen harjoituksen rakenteiseen tyyppiin kentt nime varten.
9. Kirjoita funktio, joka palauttaa merkkijonossa nimen ja pivmrn
seuraavassa muodossa:
Jaska Jokunen (01.01.1999)
163
Kyt mrittelyss kaavaa ABS(u-v). Huomaa, ett ABS-operaation toteuttava funktio vektorinormi (sivu 157) tuottaa ylivuodon, jos vektorin komponentit ovat lhell ylivuototasoa, vaikka tulos olisikin esitettviss liukulukuna. Esimerkin ongelmasta tarjoaa lauseke
ABS(vektori(a,a,a))
164
Fortran 95/2003
11
Taulukot ja
osoitinmuuttujat
11.1
mrittelevt molemmat kolmiulotteisen taulukon. Alkioita on kummassakin taulukossa 101 101 101. Tllainen taulukkomrittely on Fortran 95
-standardin kielell tunnetun muotoinen taulukko (explicit-shape array). Mrittelyst voi halutessaan jtt indeksien alarajat pois, jolloin nm oletetaan ykksiksi. Esimerkiksi reaalilukutaulukon mrittely on siis yleisemmin
muotoa
REAL, DIMENSION(ala1:yla1,ala2:yla2,...,alaN :ylaN ) :: x
tai muotoa
REAL :: x(ala1:yla1,ala2:yla2,...,alaN :ylaN )
165
PROGRAM taulukointi
IMPLICIT NONE
INTEGER, PARAMETER :: n = 100
INTEGER :: i
REAL, DIMENSION(n) :: x
REAL :: pi
pi = 2*ACOS(0.0)
DO i = 1, n
x(i) = SIN(pi*(i-1.0)/(n-1.0))
END DO
WRITE(*,(A)) sin(x) =
WRITE(*,(5(F11.7))) x
END PROGRAM taulukointi
0.0317279
0.1892512
0.0634239
0.2203106
0.0950560
0.2511480
0.1265925
0.2817326
0.0950560
0.0634239
0.0317279 -0.0000001
Dynaamisesti varattavan taulukon (dynamic array) kokoa ei kerrota mrittelyvaiheessa, vaan sek ala- ett ylrajat jtetn auki. Mrittelyss kytetn joko mrett ALLOCATABLE tai myhemmin esiteltv POINTERmrett. Esimerkiksi lause
REAL, DIMENSION(:,:,:), ALLOCATABLE :: x
mrittelee kolmiulotteisen taulukon, jonka kokoa ei ole mritelty. Mrittelyss kerrotaan, ett taulukko on kolmiulotteinen sek dynaamisesti
varattavissa. Tllaista taulukkoa kutsutaan mukautuvan muotoiseksi taulukoksi (deferred-shape array). Dynaamisesta muistin varauksesta kerrotaan
enemmn kappaleessa 11.11 (sivu 178).
Proseduureissa voi taulukoille varata tilaa mys suoraan muuttujamrittelyss automaattisten taulukoiden (automatic array) avulla:
SUBROUTINE ali(n)
IMPLICIT NONE
INTEGER :: n
REAL, DIMENSION(n) :: x
jne.
END SUBROUTINE ali
166
Fortran 95/2003
11.2
Jlkimmisen operaation voisi tehd helpommin taulukko-operaatioiden avulla eli yksinkertaisesti asettamalla:
y = 1.0
Selit miksi!
Seuraava esimerkki lis kahden vlein taulukon x alkiot yhdest kymmeneen taulukon y alkioihin:
REAL, DIMENSION(5) :: y
167
y = y + x(::2)
Samaan tapaan voidaan valita osa useampiulotteisesta taulukosta. Mrittelemme aluksi taulukon
REAL, DIMENSION(5,8) :: a
Tllin lausekkeen
a(2:5:2, 4:6)
1
2
3
4
5
1 1 2 5 9
x(i)
Huomaa, ett taulukon x ensimminen alkio sijoitetaan sek taulukon y ensimmiseen ett toiseen alkioon. Fortran 95 -standardi kielt sijoituksen
toisin pin: samassa lausekkeessa ei voi sijoittaa kahteen kertaan arvoa samalle indeksille. Toisin sanoen lauseke
y(i) = x(1:5)
168
Fortran 95/2003
11.3
Taulukkoalustin
Taulukon alustin siis mritelln sulkeissa (/ . . . /). Jlkimmisen sijoituslauseen oikealla puolella on niin sanottu toistolista (implied do list),
joka toimii kuten tavallinenkin DO-silmukka. Toistolista on sulkujen sisll, ja indeksimuuttujan mrittely tulee silmukan sislln jlkeen pilkulla
erotettuna:
(SIN(pi*i/(n-1.0)), i = 0, n-1)
Toistolista on taulukon alustuksessa samassa asemassa kuin muutkin alustuslausekkeen osat. Esimerkiksi lauseke
(/ 0, (i, i = 1,5), 1 /)
Rakenteen
(/ 0, (1, i = 1,4), (2, i = 1,3) /)
169
x(1,1) = 1
x(1,2) = 3
x(1,3) = 5
x(2,1) = 2
x(2,2) = 4
x(2,3) = 6
11.4
Fortran-standardi ei mr taulukon alkioiden talletusjrjestyst muistissa, vaan tm on jtetty kntjn toteuttajan tehtvksi. Taulukko-operaatioille on kyllkin mritelty taulukoiden alkiojrjestys (array element order),
joka on sama kuin FORTRAN 77 -standardissakin. Alkiojrjestys on mrtty siten, ett taulukon ensimmist indeksi vastaavat alkiot ovat jrjestyksess ensin, toista indeksi vastaavat alkiot tmn jlkeen, sitten kolmatta
jne. Matriisille alkioiden ksittelyjrjestys on siten sarakkeittain kuten
matematiikassa yleisesti ja pinvastoin kuin C-kieless.
Edellisen esimerkin alkiot tulivat siis talletetuksi taulukkoon x seuraavassa
alkiojrjestyksess:
x(1,1)
x(2,1)
x(1,2)
x(2,2)
x(1,3)
x(2,3)
11.5
=
=
=
=
=
=
1
2
3
4
5
6
Taulukoidaan jlleen funktio sin x. Tll kertaa kysytn kyttjlt taulukoitavien pisteiden mr vlilt [0, ]. Taulukolle varataan dynaamisesti
muistia, ja funktion arvot tulostetaan ptteelle.
PROGRAM trigo
IMPLICIT NONE
INTEGER, PARAMETER :: reaali = SELECTED_REAL_KIND(10)
REAL(KIND=reaali), DIMENSION(:), ALLOCATABLE :: x
REAL(KIND=reaali), PARAMETER :: &
pi = 3.141592653589793_reaali
INTEGER :: i, n, allocstat
WRITE(*,(A),ADVANCE=no) Anna n:
170
Fortran 95/2003
READ(*,*) n
IF (n > 0) THEN
ALLOCATE(x(n), STAT = allocstat)
IF ( allocstat /= 0 ) STOP
ELSE
STOP n <= 0!
END IF
x = (/ (i, i = 0, n-1) /)
x = SIN(pi*x/(n-1))
WRITE(*,(A)) sin(x) =
WRITE(*,(5(F10.7))) x
END PROGRAM trigo
11.6
Seuraava ohjelma laskee funktion f (x, y) = sin x 2 + y 2 kuvaajan taulukkoon z. Funktion arvot lasketaan aliohjelmassa f. Argumenttina vlitetn
pisteet, joissa funktio evaluoidaan, sek tulostaulukko. Aliohjelma tarkistaa lisksi, ett taulukot ovat todella samanmuotoisia, jotta operaatio olisi
mritelty.
PROGRAM taulukko
IMPLICIT NONE
INTEGER,PARAMETER :: n = 5
REAL, DIMENSION(n) :: t
REAL, DIMENSION(n,n) :: x, y, z
INTEGER :: i
t = (/ (10.0*i/(n-1)-5.0, i = 0, n-1) /)
DO i = 1,n
x(i,1:n) = t
y(1:n,i) = t
END DO
CALL f(x,y,z)
WRITE(*,*) z
CONTAINS
SUBROUTINE f(x,y,z)
IMPLICIT NONE
REAL, DIMENSION(:,:) :: x, y, z
IF ( ANY(SHAPE(x) /= SHAPE(y)) .OR. &
ANY(SHAPE(x) /= SHAPE(z)) ) THEN
171
Funktion f kyttm standardifunktio SHAPE palauttaa arvonaan muuttujan muodon. Kaksiulotteisen taulukon muoto on rivien ja sarakkeiden lukumr. Standardifunktio ANY palauttaa tiedon siit, onko sille argumenttina
annetun loogisen taulukon arvoista mikn tosi.
Aliohjelman mrittelyss voi muodollisena argumenttina olla kolme erityyppist taulukkomrittely. Ensimminen nist on oletetun muotoinen
taulukko (assumed-shape array):
REAL, DIMENSION(ala1:,ala2:,ala3:) :: x
Taulukon varsinainen muoto mrytyy aliohjelmaa kutsuttaessa todellisen argumentin mukaan. Alarajat voi halutessaan jtt pois mrittelyst, jolloin ne oletetaan ykksiksi. Tss taulukkomrittelyss ei voi kytt
ALLOCATABLE-mrett. Oletetun muotoista taulukkomrittely kytettess proseduurin kutsumuodon on oltava tunnettu sek muodollisen ja todellisen parametrin tyyppien, lajiparametrien ja taulukkojen indeksien mrien
tytyy kaikkien olla samat.
Toinen taulukkoargumenttien kytttapa on tunnetun muotoinen taulukko
(explicit-shape array) eli taulukkomrittely, jossa taulukon muoto on kokonaan mrtty. Toisin kuin oletetun muotoiselle taulukolle, muodollisen ja
todellisen argumentin dimensioiden mrn ei tarvitse olla samat. Seuraavassa esimerkiss pohjelmassa mritelty kaksiulotteista taulukko ksitelln sek yksiulotteisena aliohjelmassa ali_1 ett kolmiulotteisena aliohjelmassa ali_3.
PROGRAM tunnettu_muoto
IMPLICIT NONE
INTEGER, PARAMETER :: n = 5
REAL, DIMENSION(n,n) :: taul = 0.0
CALL ali_1(taul,n)
WRITE (*,(5(F8.3))) taul(3,:)
CALL ali_3(taul,n)
WRITE (*,(5(F8.3))) taul(3,:)
CONTAINS
SUBROUTINE ali_1(taul,n)
IMPLICIT NONE
INTEGER :: n
REAL, DIMENSION(n*n) :: taul
taul(8:20) = -1.0
END SUBROUTINE ali_1
SUBROUTINE ali_3(taul,n)
IMPLICIT NONE
INTEGER :: n
REAL, DIMENSION(n,n/2,2) :: taul
172
Fortran 95/2003
taul(3,:,:) = 1.0
END SUBROUTINE ali_3
END PROGRAM tunnettu_muoto
-1.000
1.000
-1.000
1.000
-1.000
1.000
0.000
0.000
173
PROGRAM taulukko_pala_2
IMPLICIT NONE
INTEGER, PARAMETER :: n = 6
REAL, DIMENSION(n) :: a = 1.0, b = -1.0
EXTERNAL ali
CALL ali(a(1:n:2), n/2, b(1:n/2), n/2)
WRITE (*,(6(F8.3))) a, b
END PROGRAM taulukko_pala_2
SUBROUTINE ali(t1, m, t2, n)
IMPLICIT NONE
INTEGER :: m, n
REAL :: t1(m), t2(n)
t1 = 2.0
t2 = 4.0
END SUBROUTINE ali
11.7
1.000
4.000
2.000
4.000
1.000
-1.000
2.000
-1.000
1.000
-1.000
Taulukkoarvoiset funktiot
Funktiot voivat olla mys taulukkoarvoisia. Tm saadaan aikaiseksi mrittelemll RESULT-lausekkeessa annettu muuttuja taulukoksi (jonka tytyy
olla tunnetun muotoinen). Seuraavassa on tst esimerkki:
PROGRAM taulukkofunktio
IMPLICIT NONE
INTEGER, PARAMETER :: n = 5
REAL, DIMENSION(n,n) :: x, y
REAL, DIMENSION(n) :: t
INTEGER :: i
t = (/ (10.0*i/(n-1)-5.0, i = 0, n-1) /)
DO i = 1,n
x(i,1:n) = t
y(1:n,i) = t
END DO
WRITE(*,*) f(x,y)
CONTAINS
FUNCTION f(x,y) RESULT(z)
IMPLICIT NONE
REAL, DIMENSION(:,:) :: x,y
REAL, DIMENSION(SIZE(x,1),SIZE(x,2)) :: z
IF ( ANY(SHAPE(x) /= SHAPE(y)) ) THEN
WRITE(*,*) Argumentit eivt ole samanmuotoisia
STOP
174
Fortran 95/2003
ELSE
z = SIN(SQRT(x**2 + y**2))
END IF
END FUNCTION f
END PROGRAM taulukkofunktio
Funktio f palauttaa arvonaan kaksiulotteisen taulukon z, jonka koko saadaan selville standardifunktiolla SIZE. Funktio tarkastaa, ett taulukot x ja
y ovat saman kokoisia.
Palautettavan taulukon koko pit pysty laskemaan funktion argumenteista. Jos tm ei ole mahdollista, tulostaulukko pit palauttaa osoitinmuuttujia kytten, kuten kappaleen 11.11 funktiossa varaa (sivu 180).
11.8
Fortran 95 -standardissa on paljon taulukko-operaatioita, joiden avulla taulukoita voidaan ksitell kokonaisuuksina. Tavalliset operaattorit (esimerkiksi +, , , sek loogiset operaattorit) suoritetaan taulukoille alkioittain. Mys useat Fortranin standardifunktiot (intrinsic function) ovat alkioittaisia, kuten esimerkiksi SIN, COS, SQRT jne. Lisksi kieless on taulukoiden
ksittelyyn tarkoitettuja sisisi apufunktioita, kuten matriisitulo (MATMUL)
sek matriisin alkioiden summan (SUM) tai tulon lasku (PROD).
Alla oleva aliohjelma laskee taulukon arvot sisltmien lukujen keskiarvon
ja keskihajonnan kytten taulukkofunktioita SIZE, SUM ja SQRT.
SUBROUTINE tilasto(arvot, keskiarvo, keskihajonta)
IMPLICIT NONE
REAL, DIMENSION(:), INTENT(IN) :: arvot
REAL, INTENT(OUT) :: keskiarvo, keskihajonta
REAL :: varianssi
INTEGER :: n
n = SIZE(arvot)
keskiarvo = SUM(arvot)/n
varianssi = SUM((arvot-keskiarvo)**2)/(n-1)
keskihajonta = SQRT(varianssi)
END SUBROUTINE tilasto
11.9
Taulukoiden ksittelyyn on Fortran 95 -standardissa useita standardifunktioita (katso mys lukua 13):
TRANSPOSE(a): Matriisin a transpoosi.
MATMUL(a,b): Matriisien a ja b matriisitulo.
175
176
Fortran 95/2003
REAL, DIMENSION(10,10) :: x
INTEGER :: n
LOGICAL :: l
n = COUNT( x > 0.0 )
l = ANY( x < 0.0 )
l = ALL( x >= 0.0 )
Saman asian voi tehd hiukan vhemmll kirjoittamisella kyttmll lausetta WHERE:
WHERE( x < 0 ) x = 0
Fortran sislt mys muutaman standardifunktion, joilla taulukoista voidaan eri tavoin valita haluttu joukko arvoja:
MERGE(truearray,falsearray,mask): Funktio palauttaa taulukon,
jonka alkiot valitaan argumentin mask mukaan siten, ett jos taulukon
mask vastinalkion arvo on tosi, alkio valitaan taulukosta truearray, ja
vastaavasti jos taulukon mask vastinalkion arvo on eptosi, alkio valitaan taulukosta falsearray.
SPREAD(array,dim,ncopies): Kopioidaan argumenttina annettua taulukkoa ncopies kertaa uuteen taulukkoon.
PACK(array,mask,vector): Tulostaulukkoon haetaan ne array-taulukon alkiot, joita vastaavat taulukon mask alkiot ovat tosia. Tulostaulukko on vektori (yksiulotteinen taulukko). Jos valinnainen argumentti
177
vector on annettu, tulostaulukon loppuun listn arvoja tst taulukosta, kunnes tulostaulukon koko on sama kuin taulukon vector.
UNPACK(vector,mask,array): Taulukon vector arvot sijoitetaan taulukon array paikalle siell, miss taulukon mask arvot ovat tosia.
CSHIFT(array,shift,dim): Siirretn taulukon alkioita argumentin
shift kertoma mr argumentin dim antamaan suuntaan. Taulukon
reunalta ulos menevt alkiot tulevat taulukon toiselta laidalta sisn.
EOSHIFT(array,shift,boundary,dim): Funktio toimii muuten samalla tavalla kuin funktio CSHIFT, paitsi ett taulukon rajalta ulos joutuvat
alkiot eivt kierr toiselle laidalle, vaan nm arvot otetaan valinnaisesta argumentista boundary (jos tt ei ole annettu, arvot asetetaan
nolliksi).
11.10
FORALL-rakenne
178
Fortran 95/2003
b(1)
c(2) b(2)
c(3) b(3)
.
a(1:n,1:n) =
c(4) b(4)
c(5) b(5)
Normaali taulukkosyntaksi poimii taulukoista suorakulmaisen lohkon. Esimerkkin mrittelemme taulukon
REAL, DIMENSION(5,8) :: y
1
2
3
4
5
11.11
Dynaaminen muistinvaraus
Taulukoille voidaan varata tilaa staattisen varauksen lisksi ohjelman suorituksen aikana, jolloin taulukon koko voidaan mrt esimerkiksi ohjelman
sytteiden mukaan. Dynaamisesti varattava taulukko tytyy ilmoittaa kntjlle mreell ALLOCATABLE tai vaihtoehtoisesti mreell POINTER. Mre POINTER mrittelee osoitinmuuttujan, joista kerrotaan enemmn kappaleessa 11.13 (sivu 183). Mys proseduurien automaattiset taulukot, joista on
kerrottu kappaleessa 11.1, ovat dynaamisesti varattavia taulukoita.
Joissain tilanteissa, kuten esimerkiksi omien tietotyyppien mrittelyss,
ALLOCATABLE-mrett ei voi kytt, vaan on kytettv POINTER-mrett.
Seuraavassa on esimerkki mreiden kytst:
179
Taulukon koot siis jtetn kokonaan mrittelemtt, vain taulukon dimensioiden mr annetaan mrittelyss kyttmll symbolia :. Ajonaikainen
tilanvaraus tehdn ALLOCATE-lauseella seuraavasti:
INTEGER :: allocstat
ALLOCATE(x(-n:n,0:m), y(n), STAT=allocstat)
IF (allocstat /= 0) STOP
Proseduurin sisll paikalliseen muuttujaan varattu tila on yleens vapautettava ennen proseduurista poistumista: paikalliset muuttujat voivat, toteutuksesta riippuen, menett tilansa proseduurista poistuttaessa. Nm
muuttujat varataan yleens joka kerta uudestaan ohjelman yllpitmst
pinomuistista.
Tarvittaessa muuttujan saa kyllkin silyttmn arvonsa proseduurikutsujen vlill kyttmll SAVE-mrett. Fortran 95 -kieless, Fortran 90:st
poiketen, paikallisiin muuttujiin ALLOCATE-lauseella varattu tila vapautetaan
automaattisesti, jos nille ei ole annettu SAVE-mrett. Hyv tapa kuitenkin
on kytt eksplisiittisesti DEALLOCATE-lausetta.
Jos proseduuriin vlitetn POINTER-tyyppinen taulukko, joka varataan dynaamisesti, alkaa taulukon indeksointi samasta arvosta kuin vlitettvss
POINTER-taulukossa. Vertaamme POINTER- ja ALLOCATABLE-taulukkojen vlittmist eri tavalla mriteltyihin funktioihin:
PROGRAM ptr_testi
IMPLICIT NONE
REAL, DIMENSION(:), POINTER :: a
REAL, DIMENSION(:), ALLOCATABLE :: b
ALLOCATE (a(-1:1), b(-1:1))
WRITE (*,(A,5(I4))) Alarajat: , lb_1(a), lb_1(b), &
lb_2(a), lb_3(a), lb_3(b)
180
Fortran 95/2003
CONTAINS
INTEGER FUNCTION lb_1(x) RESULT(lb)
IMPLICIT NONE
REAL, DIMENSION(:) :: x
lb = LBOUND(x,1)
END FUNCTION lb_1
INTEGER FUNCTION lb_2(x) RESULT(lb)
IMPLICIT NONE
REAL, DIMENSION(:), POINTER :: x
lb = LBOUND(x,1)
END FUNCTION lb_2
INTEGER FUNCTION lb_3(x) RESULT(lb)
IMPLICIT NONE
REAL, DIMENSION(2:) :: x
lb = LBOUND(x,1)
END FUNCTION lb_3
END PROGRAM ptr_testi
-1
Funktiossa lb_1 alaraja on oletusarvo eli 1. Funktioon lb_2 vlitetn osoitintaulukko, ja indeksointi alkaa esimerkiss 1:st. Funktiossa lb_3 on
puolestaan mritelty, ett indeksointi aloitetaan aina arvosta 2.
Jos proseduuri varaa muistia osoitinmuuttujaan (POINTER), varattu muistitila voidaan palauttaa kutsuvalle proseduurille, jolloin sen tehtvksi j
hoitaa mys muistitilan vapauttaminen.
Seuraavassa ohjelmassa funktio varaa palauttaa osoitinmuuttujan, jonka
voi sijoittaa toiseen osoitinmuuttujaan komennolla => (kappale 11.13 sivulla 183):
PROGRAM varaus
IMPLICIT NONE
REAL, DIMENSION(:), POINTER :: a
a => varaa(1000)
WRITE(*,*) Varatun taulukon koko=, SIZE(a)
DEALLOCATE(a)
CONTAINS
FUNCTION varaa(n) RESULT(p)
IMPLICIT NONE
INTEGER :: n
REAL, DIMENSION(:), POINTER :: p
INTEGER :: allocstat
ALLOCATE(p(n), STAT=allocstat)
IF (allocstat > 0) CALL varausvirhe(allocstat)
CONTAINS
SUBROUTINE varausvirhe
WRITE (*,*) Muistin varaus eponnistui,&
& paluukoodi:, allocstat
STOP
END SUBROUTINE varausvirhe
181
Jos tehtvn dimensio tai pisteparien lukumr valitaan suureksi, tarvitaan edellisess ohjelmassa hyvin paljon keskusmuistia. Jos dimensio on
esimerkiksi 5 ja pistepareja on 100 000, varataan ohjelmassa muistitilaa
2 5 100 000 = 106 reaaliluvun verran. Jos reaaliluku vie tilaa esimerkiksi kahdeksan tavua, varataan ohjelmassa tss tapauksessa keskusmuistia
8 megatavua.
Fortran 95 vapauttaa automaattisesti proseduureissa varatut paikalliset dynaamiset taulukot:
SUBROUTINE testi(n)
IMPLICIT NONE
INTEGER :: n
182
Fortran 95/2003
11.12
Erastotheneen seula on klassinen algoritmi alkulukujen lytmiseksi. Vaikka nykyisin tunnetaan paljon tehokkaampiakin menetelmi, pystytn tll
menetelmll etsimn esimerkiksi miljoonaa pienemmt alkuluvut kohtalaisen nopeasti. Seula perustuu yksinkertaiseen ideaan: poistetaan lukutaulukosta ensin kahdella jaolliset luvut, sitten kolmella jaolliset luvut, sitten
viidell jaolliset luvut jne.
Kytmme Erastotheneen seulan toteuttamiseen taulukkosyntaksia ja dynaamista muistinvarausta. Ohjelma kysyy alkulukujen ylrajaa ja seuloo tmn jlkeen alkuluvut taulukkoon numerot.
PROGRAM Erastotheneen_seula
IMPLICIT NONE
INTEGER, PARAMETER :: iso = SELECTED_INT_KIND(9)
INTEGER(iso) :: max_nro
INTEGER(iso), DIMENSION(:), ALLOCATABLE :: numerot
INTEGER(iso) :: i, alku_lkm
INTEGER :: ok
WRITE (*,*) Syt alkulukujen ylraja:
READ (*,*) max_nro
IF (max_nro > 2) THEN
ALLOCATE (numerot(max_nro), STAT=ok)
IF (ok /= 0) THEN
WRITE (*,*) Muistinvaraus eponnistui!
STOP
END IF
! Taulukon alustus luvuilla 0, 2, 3, 4, ...
numerot = (/ 0, (i, i = 2, max_nro) /)
DO i = 2, FLOOR(SQRT(REAL(max_nro)))
IF (numerot(i) /= 0) THEN
numerot(2*i:max_nro:i) = 0
ENDIF
END DO
! Lasketaan alkulukujen lkm
alku_lkm = COUNT(numerot /= 0)
! Kertn alkuluvut taulukon alkuun
numerot(1:alku_lkm) = PACK(numerot, numerot /= 0)
! Tulostus
183
Silmukassa
DO i = 2, FLOOR(SQRT(REAL(max_nro)))
ei tarvitse kyd lpi kaikkia lukuja maksimiarvoon max_nro asti, sill mak
simiarvon nelijuurta max_nro suuremmat luvut tulisivat muuten kyty
lpi kahteen kertaan.
Taulukko-operaatio COUNT laskee .TRUE.-arvojen lukumrn ja operaatio
PACK pakkaa taulukosta halutut alkiot.
Ohjelma tulostaa kaikki lydetyt alkuluvut, joten maksimiarvoksi ei kannata
sytt kovin suurta lukua:
% f90 seula.f90
% ./a.out
Syt alkulukujen ylraja:
100
Lysin
25 kpl alkulukuja, jotka olivat <=
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
100
Ohjelma tulostaa vain alkulukujen lukumrn, jos poistat lauseen (tai muutat sen huutomerkill kommentiksi)
WRITE (*,(5I10)) numerot(1:alku_lkm)
Seuraavassa kyttesimerkki:
Syt alkulukujen ylraja:
1000000
Lysin
78498 kpl alkulukuja, jotka olivat <=
1000000
11.13
Osoitinmuuttujat
184
Fortran 95/2003
Osoitinmuuttujien trkeimpi kytttarkoituksia ovat dynaamiset tietorakenteet kuten lista- ja puurakenteet sek muuttuvan mittaiset taulukot omissa tietotyypeiss.
Jotta osoitinmuuttujaa voitaisiin kytt, tytyy se ensin saada osoittamaan
johonkin muistitilaan. Uuden muistialueen varaaminen ja thn osoittaminen tehdn siis ALLOCATE-lauseella, mink jlkeen osoittimen kytt on
oleellisesti samanlaista kuin tavallisten muuttujienkin.
REAL, DIMENSION(:,:), POINTER ::
ALLOCATE (x(100,100))
x(3:6, 3:6) = 0.0
Osoitinmuuttujan osoittamalle kohteelle tytyy muuttujamrittelyss antaa mre TARGET (tai kohteen tytyy olla toinen osoitin). Tmn lisksi
osoittimen ja kohteen alkioiden tyyppien tulee olla lajiparametri mukaan
lukien samat. Taulukoiden yhteydess taulukoiden ulottuvuuksien mrien
on oltava samat.
Kun osoitinmuuttuja on tavalla tai toisella saatu osoittamaan johonkin varattuun muistitilaan, se kyttytyy kuten tavallinenkin muuttuja. Arvon sijoittamiseksi osoitinmuuttujan kohteeseen kytetn tavallista sijoituslausetta.
Jos osoitinmuuttuja osoitin on alustettu kuten edell, niin lauseke
osoitin = 5
185
ALLOCATABLE-mrett ei voi kytt proseduurin muodolliselle parametrille, mutta POINTER-mrett voi kytt.
Seuraavassa esimerkiss osoitinmuuttujia kytetn eri tavoin. Aluksi mrittelemme muuttujat ja alustamme taulukon a:
REAL, DIMENSION(5), TARGET :: a
REAL, POINTER :: b, d
REAL, POINTER, DIMENSION(:) :: c
a = (/ (i, i = 1, 5) /)
WRITE-lauseen tulostus on
2.000000
WRITE-lauseen tulostus on
3.000000
5.000000
1 2 3 4 5
a
b
c
1 2
Kuva 11.3: Osoitinmuuttujien kyttesimerkki.
WRITE-lauseen tulostus on
1.000000
186
Fortran 95/2003
d => c(2)
d = 5
WRITE(*,*) c(2)
Lause d
Lause d
si luvun
tulostus
Sijoitusoperaatioiden => ja = eron ymmrtminen on trke osoitinmuuttujia kytettess. Vr sijoituslause johtaa vaikeasti lydettviin virhetilanteisiin. Muistitilan varausta ja osoittimen d kytt on havainnollistettu
kuvassa 11.4.
1 2 3 4 5
c
d
Kuva 11.4: Osoitinmuuttujaan c on varattu tilaa dynaamisesti. Osoitinmuuttuja d
osoittaa taulukon c toiseen alkioon.
Taulukko-osoittimen alkioille ei voi yksitellen kytt osoitinsijoitusta, toisin sanoen taulukko-osoitinta ei voi osoituksessa indeksoida. Tmn rajoituksen voi kiert mrittelemll taulukon, jonka alkiot ovat itse mritelty toissijaista tietotyyppi. Tm toissijainen tietotyyppi koostuu puolestaan yhdest komponentista, joka on osoitinmuuttuja ensisijaiseen rakenteen sisltvn tietotyyppiin. Osoitinmuuttujien tllaista kytt selvent
luvun 14.7 sukupuuesimerkki sivulla 261.
Funktio ASSOCIATED(osoitin) palauttaa arvonaan tiedon siit, onko osoittimelle annettu jokin kohde. Tlle funktiolle ei kuitenkaan voi antaa argumenttina osoitinta, jota ei ole alustettu tavalla tai toisella. Ennen osoittimen kohdistamista se on epmrisess tilassa. Sit ei siis voi vlitt ASSOCIATEDlausekkeelle, jotta voisimme tarkistaa onko se kohdistettu. Tst ongelmasta
psemme lauseella NULLIFY(osoitin), joka alustaa osoittimen nollattuun
tilaan, muttei kohdista osoitinta mihinkn kohteeseen.
Fortran 95 sislt NULLIFY-lauseen lisksi funktion NULL(), jolla osoitinmuuttuja voidaan mys alustaa:
osoitin => NULL()
Funktiota NULL voi kytt muuttujamrittelyiss alustimena sek rakenteiden oletusarvojen mrityksiss, toisin kuin NULLIFY-lausetta.
Funktiokutsu ASSOCIATED(a,b) kertoo, osoittaako osoitinmuuttuja a kohteeseen b. Jos sek a ett b ovat osoitintyyppi, kertoo funktiokutsu, osoittavatko ne samaan kohteeseen.
11.14
187
Esimerkki: listarakenne
Tss luvussa teemme ohjelman, joka ksittelee linkitetty listaa. Listan alkiot ovat tss esimerkiss kaksi kokonaislukua: avain ja lkm. Mrittelemme listan siten, ett listtess listaan alkioita ne tallentuvat avaimen
mukaan suuruusjrjestyksess. Lisksi listassa on tieto siit, kuinka monta
kertaa kukin luku on talletettu listaan.
MODULE listamoduuli
IMPLICIT NONE
TYPE alkiotyyppi
INTEGER :: avain, lkm
END TYPE alkiotyyppi
TYPE listatyyppi
TYPE(alkiotyyppi) :: alkio
TYPE(listatyyppi), POINTER :: seuraava
END TYPE listatyyppi
CONTAINS
Aliohjelman lisaa mrittely.
END MODULE listamoduuli
Vaikka tyyppimrittelyss listatyyppi kytetn tyyppi itsen, on tm rakenne luvallinen: rakenteinen tyyppi voi sislt osoittimen omaan
tyyppiins.
Aliohjelma, joka lis alkion listaan, voitaisiin mritell seuraavasti:
SUBROUTINE lisaa(lista, luku)
! Listn kokonaisluku listaan, siten ett alkiot pysyvt
! avaimen mukaan kasvavassa jrjestyksess.
IMPLICIT NONE
TYPE(listatyyppi), POINTER :: lista
INTEGER :: luku
TYPE(listatyyppi), POINTER :: edellinen, uusi, nykyinen
nykyinen => lista
NULLIFY(edellinen)
DO WHILE( ASSOCIATED(nykyinen) )
IF ( luku > nykyinen % alkio % avain ) THEN
! Jos listtv luku on suurempi kuin listan
! nykyalkion avain mennn listassa eteenpin
edellinen => nykyinen
nykyinen => nykyinen % seuraava
ELSE IF ( nykyinen % alkio % avain == luku ) THEN
! Listassa on jo tm arvo
nykyinen % alkio % lkm = nykyinen % alkio % lkm + 1
EXIT
ELSE
! Oikea paikka lytyi. Listn listaan uusi alkio
ALLOCATE( uusi )
IF ( ASSOCIATED(edellinen) ) THEN
edellinen % seuraava => uusi
188
Fortran 95/2003
ELSE
lista => uusi
END IF
uusi % alkio % avain = luku
uusi % alkio % lkm = 1
uusi % seuraava => nykyinen
EXIT
END IF
END DO
! Jos lista tuli kyty kokonaisuudessaan lpi, uusi
! arvo kuuluu listan loppuun. Jos listaa ei alunperin
! ollut olemassa, luodaan se.
IF ( .NOT. ASSOCIATED(nykyinen) ) THEN
IF ( ASSOCIATED(edellinen) ) THEN
ALLOCATE(uusi)
edellinen % seuraava => uusi
ELSE
ALLOCATE( lista )
uusi => lista
END IF
uusi % alkio % avain = luku
uusi % alkio % lkm = 1
NULLIFY( uusi % seuraava )
END IF
END SUBROUTINE lisaa
Lista pttyy siis osoittimeen, jolle ASSOCIATED-funktio palauttaa arvon eptosi. Kun listaan luodaan uusi alkio, sen seuraaja tytyy alustaa NULLIFYfunktiolla
NULLIFY( uusi % seuraava )
189
1
9
8
4
4
Listan sislt:
Alkio:
Alkio:
Alkio:
Alkio:
1
4
8
9
Lukumr:
Lukumr:
Lukumr:
Lukumr:
1
2
1
1
11.15
Yhteenveto
190
Fortran 95/2003
ei tee mitn. Toisaalta taulukot x(1:0,1:2) ja x(1:0,1:3) eivt ole samanmuotoiset (conformable), koska ensimmisen taulukon koko on 0 2 ja
toisen 0 3.
Taulukkoa voi indeksoida kokonaislukuvakiolla, skalaarimuuttujalla tai kokonaislukuvektorilla sek rakenteella [alku][:loppu][:lisys].
Osoitinmuuttuja luodaan POINTER-mreell:
tyyppi, POINTER :: muuttujan nimi
Tmn lisksi osoittimen ja sen kohteen on oltava samaa tyyppi, sek taulukoiden osalta saman muotoisia.
Trke osoitinmuuttujien kyttkohde ovat dynaamiset tietorakenteet kuten listat (kappale 11.14 sivulla 187) ja puurakenteet. Binripuun toteutusta ksittelee kappale 14.6 sivulla 256 ja sukupuun toteutusta kappale 14.7
sivulla 261.
Harjoitustehtvi
1. Onko seuraava mrittely oikein?
REAL DIMENSION(1:3,2:3) :: aa
191
8. Alkulukuteoreeman mukaan
lim
(n)
= 1,
n/ ln n
aji bik , j = 1, . . . , l, k = 1, . . . n,
i=1
192
Fortran 95/2003
12
Fortran 95:ss on monipuoliset mahdollisuudet tiedon syttn ja tulostamiseen. Aluksi esittelemme yksinkertaiset sytt- ja tulostuslauseet, jotka
muotoilevat tulostuksen automaattisesti. Sen jlkeen ksittelemme syttja tulostuslauseiden yleist rakennetta ja muotoilukoodeja. Kerromme mys
tiedostojen ksittelyst, binrisest sytst ja tulostuksesta sek suorasaantitiedostoista. Lopuksi kerromme muun muassa merkkijonoihin kirjoittamisesta sek virhetilanteiden ksittelyst.
12.1
Sytt ja tulostus
Nppimist
Tiedosto levyll
jne.
Nyttpte
Paperitulostin
Tiedosto levyll
jne.
193
Sytt
INTEGER
REAL
COMPLEX
LOGICAL
CHARACTER
Skalaarit
Taulukot
Rakenteiset tyypit
Tulostus
INTEGER
REAL
COMPLEX
LOGICAL
CHARACTER
Skalaarit
Taulukot
Rakenteiset tyypit
12.2
Fortranin sytt- ja tulostuslauseet READ ja PRINT tulostavat ja lukevat oletusarvoisesti ptteelt. Lauseiden kytt on esitelty seuraavassa esimerkiss:
PROGRAM kulmikas
IMPLICIT NONE
REAL :: alpha
PRINT *, Anna kulma alpha
READ *, alpha
PRINT *, Kulman sini ja kosini ovat , &
SIN(alpha), COS(alpha)
END PROGRAM kulmikas
Ohjelmassa symboli * ilmaisee, ett kntj tulkitsee syttvirtaa automaattisesti syttmuuttujien tyyppien mukaan ja muotoilee tulostuksen automaattisesti. Esimerkiss annettiin PRINT-lauseelle argumentiksi lista erityyppisi muuttujia. Mys sytss ohjelma voi lukea useille muuttujille
arvot samalla READ-lauseella. Perkkiset sytettvt arvot erotetaan vlilynnill tai pilkulla, tai ne voi mys kirjoittaa eri riveille.
Edell esitettyjen yksinkertaisten READ- ja PRINT-lauseiden sijaan kannattaa
useimmiten kytt lauseita READ ja WRITE seuraavaan tapaan:
PROGRAM kulmikas
IMPLICIT NONE
REAL :: alpha
WRITE (*,*) Anna kulma alpha
194
Fortran 95/2003
Tm ohjelma toimii tsmlleen samoin kuin edellinen. WRITE- ja READlauseissa ensimminen symboli * ilmaisee, ett kytetn oletusarvoisia
sytt- ja tulostuskanavia ja toinen symboli * viittaa oletusmuotoiluun.
12.3
Edell esitellyt sytt- ja tulostuslauseet olivat esimerkkej oletusmuotoilusta eli listan ohjaamasta muotoilusta (list-directed formatting), josta kerromme tss hieman tarkemmin. Myhemmin kerromme sarakesidonnaisesta
sytst ja tulostuksesta, jota kytetn muotoilukoodien avulla.
195
INTEGER :: i
REAL :: x
CHARACTER(LEN=10) :: nimi
COMPLEX :: z
LOGICAL :: totuus
READ (*,*) i, x, nimi, z, totuus
Alla olevassa taulukossa on esitetty ohjelmalle annettuja syterivej ja muuttujien arvoja syterivin lukemisen jlkeen.
Sytetty rivi
2 -1 -3
1, 3, 2
2, , 0
3*0 Nollaus
1 / loppuu
1
3
4
0
4
3
2
0
0
5
196
Fortran 95/2003
Oletusarvoisesti merkkijonot tulostetaan sellaisenaan ja perkkisten merkkijonolausekkeiden vliin ei tule erotinta. Kaikkien muiden muuttujatyyppien osalta listan ohjaamaa tulostusta voidaan suoraan kytt listan ohjaamassa sytss. OPEN-lauseen DELIM-tarkentimella voidaan listan ohjaamaa
tulostusta muuttaa siten, ett merkkijonojen ymprille tulostetaan lainausmerkki tai heittomerkki. Oletus on DELIM=NONE. Muita vaihtoehtoja ovat
APOSTROPHE eli heittomerkki () ja QUOTE eli lainausmerkki (").
Seuraava ohjelmanptk tulostaa eri tyyppisi muuttujia listan ohjaamalla
tulostuksella:
INTEGER :: i = 3
REAL :: x = 3.14
CHARACTER(LEN=*), PARAMETER :: kehote = "Avot"
WRITE (*,*) i, kehote, x
3.140000
Huomaa, ett esimerkkitulostuksessa kokonaisluku 3 ja sit seuraava merkkijonolauseke kirjoitettiin suoraan perkkin.
12.4
Sytt- ja tulostuslauseet
Tydellisess muodossaan sytt- ja tulostuslauseet ottavat argumenteikseen kanavanumeron (unit) sek muotoilukoodin (fmt). Lisksi tarvitaan tu-
197
lostuslista (iolist) eli lista luettavista tai tulostettavista muuttujista tai lausekkeista.
Kanavanumero mahdollistaa lukemisen ja kirjoittamisen ulkoisesta tiedostosta. Oletusarvoista sytt- ja tulostuskanavaa merkitn symbolilla *. Tiedostojen avaamista ja kanavanumeroita ksitelln sivulla 204.
12.5
Muotoilukoodit
Muotoilukoodi mr, miten tieto pit sytn tai tulostuksen yhteydess muotoilla. Muotoilukoodi siis ilmaisee, kuinka leven kenttn ja miten
muotoiltuna kukin muuttuja tulisi kirjoittaa. Muotoilukoodi voidaan antaa
eri tavoin: merkkijonovakiona, merkkijonolausekkeena, merkkijonomuuttujana tai FORMAT-lauseen lausenumerona. Aikaisemmissa esimerkeiss muotoilukoodi korvattiin symbolilla *, jolloin valittiin listan ohjaama muotoilu.
Seuraavassa esimerkiss on muotoilukoodi I5 ilmaistu kolmella eri tavalla.
Tm koodi tulostaa kokonaisluvun n viisi merkki leven kenttn.
PROGRAM tulosta
IMPLICIT NONE
INTEGER :: n = 34
CHARACTER(LEN=*), PARAMETER :: form = (I5)
WRITE (*, (I5)) n
WRITE (*, form) n
WRITE (*, 30) n
30 FORMAT (I5)
END PROGRAM tulosta
! Merkkivakio muotoilukoodina
! Merkkijonomuuttuja (tss vakio)
! FORMAT-lauseen kytt
198
Fortran 95/2003
Tietotyyppi
Muotoilukoodi Esimerkki
Kokonaisluvut
Kokonaisluvut binriesityksen
Kokonaisluvut oktaaliesityksen
Kokonaisluvut heksadesimaaliesityksen
Iw
Bw
Ow
Zw
I5
B8
O5
Z4
Reaaliluvut desimaaliesityksen
Fw .d
F7.4
Reaaliluvut eksponenttiesityksen
Tekniikan esitysmuoto
Tieteellinen esitysmuoto
Ew .d
Ew .dEe
ENw .d
ESw .d
E12.3
E12.3E4
EN12.3
ES12.3
Loogiset muuttujat
Lw
L7
Merkkijonot
A
Aw
A
A20
Yleinen esitystapa
Gw .d
G9.3
12.5.1 Kokonaisluvut
Kokonaislukujen muotoilukoodi on I. Koodin jlkeen ilmoitetaan kentn
leveys, esimerkiksi I5. Valinnaisesti voi kentn leveyden jlkeen ilmoittaa
tulostettavien numeroiden vhimmismrn (esim. I5.3), jolloin pienten
lukujen edelle tulostetaan nollia.
Seuraavassa on kokonaislukuja tulostava esimerkkiohjelma:
WRITE (*,(I5)) 10
WRITE (*,(I5.3)) 10
WRITE (*,(I5)) 100000
Viimeisell rivill luvun esitys oli liian leve viiden merkin kenttn, jolloin
tulostettiin *-merkkej.
Kokonaisluvut voi mys tulostaa binri-, oktaali- tai heksadesimaaliesityksen muotoilukoodeilla B, O tai Z. Nit kytetn samoin kuin I-muotoilukoodia.
Kokonaislukujen sytss luetaan aina kentn leveyden mittainen mr
199
merkkej tai rivin loppuun asti. Lukujen vliss olevat vlilynnit eivt ole
merkitsevi. Muotoilukoodien kytt voi helposti johtaa virhetilanteisiin, jos
luvut eivt ole tsmlleen oikeissa sarakkeissa.
Alla olevassa taulukossa on esitetty sytettyj merkkej ja niist luettuja
kokonaislukuja, kun luvut luetaan seuraavilla lauseilla:
INTEGER :: i, j
READ (*, (2I5)) i, j
Syte
1234567890
123
45
123 45
1 3 4 5 6 4
Luetut luvut
12345
123
12
134
67890
45
345
56
12.5.2 Reaaliluvut
Reaaliluvut voidaan tulostaa desimaaliesityksen (koodi F) tai eksponenttiesityksen (koodi E). Kumpaankin koodiin liittyy kentn leveys ja desimaalien lukumr, esimerkiksi F9.3 tai E12.3. Desimaalipiste sek eksponentin esitys sisltyvt sallittuun kokonaispituuteen. E-koodille voi antaa mys
eksponenttiosan pituuden, esimerkiksi E15.3E4.
Seuraavat esimerkit valaisevat F- ja E-koodien kytt:
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
(*,
(*,
(*,
(*,
(*,
(*,
(F7.2)) 12.3443
(F9.4)) 12.3443
(F9.4)) 37283845.3872
(E12.3)) 12.3443
(E12.5)) 1.243E-5
(E15.3E4)) 1.243E-5
(*,(F9.3)) 0.0345
(*,(E12.3)) 0.0345
(*,(EN12.3)) 0.0345
(*,(ES12.3)) 0.0345
200
Fortran 95/2003
Tulostukseksi saadaan:
0.034
0.345E-01
34.500E-03
3.450E-02
Tiedon sytss reaalilukujen muotoilukoodit Fw .d ja Ew .d toimivat seuraavasti: ohjelma lukee joka tapauksessa kentn leveyden w ilmoittaman
mrn merkkej tai kunnes rivi loppuu. Numeroiden vliss olevat vlilynnit eivt oletusarvoisesti ole merkitsevi.
Jos sytetyss luvussa on desimaalipiste, mr se desimaaliosan alun.
Tllin muotoilukoodin (esimerkiksi Fw .d) desimaalien mrll d ei ole
merkityst. Jos luvussa ei ole desimaalipistett, tulkitaan oikeanpuoleiset d
merkki desimaalipisteen oikealla puolella olevaksi desimaaliosaksi.
Luvut voi sytt mys eksponenttimuodossa, vaikkapa esitysmuodossa
2.1E5, 2.1E+5 tai 2.1+5. Esimerkiksi jos luetaan reaalilukuja lauseella
READ (*,(F7.2)) x
muuntuvat luvut taulukon 12.2 mukaisesti. Taulukon toiselta rivilt huomataan, ett vlilyntej ei otettu huomioon. Kolmas rivi osoittaa, ett luvusta kytettiin kaikki nelj desimaalia, vaikka muotoilukoodissa oli ilmoitettu
kentn leveydeksi kaksi. Kentn leveytt kytetn vasta silloin, kun sytetyss luvussa ei ole desimaalipistett. Esimerkeiss ilman desimaalipistett
sytetyt luvut tulkitaan sadasosina eli kaksi oikeanpuolimmaista lukua tulkitaan desimaaliosaksi. Lisksi taulukossa on esimerkkej eksponenttimuotoisesta sytst, jossa eksponenttia osoittavan e-kirjaimen voi halutessaan
jtt pois.
Taulukko 12.2: Tiedon syttminen muotoilukoodin (F7.2) avulla.
Syte
Luettu reaaliluku
2.1
2 . 1
-2.3142
21
2
1324
1.2e1
1.2e-1
-1.2-2
2.1
2.1
-2.3142
0.21
0.02
13.24
12
0.12
-0.012
12.5.3 Kompleksiluvut
Kompleksilukuja varten tulee antaa kaksi muotoilukoodia, reaali- ja imaginriosalle erikseen. Seuraavassa on esimerkki tst:
COMPLEX :: z = (0.3234, 3.423)
201
Tulostuksena on 0.323 0.34E+01. Samoin sytss luetaan reaali- ja imaginriosa erikseen omilla muotoilukoodeilla. Kytettess listan ohjaamaa
muotoilua (symboli *) luetaan ja tulostetaan kompleksiluvut sulkujen sisll
olevina lukupareina. Jos kompleksiluku tulostettaisiin kyttmll esimerkiksi muotoilukoodia (F6.3), tulostuisi ensin reaaliosa, tmn jlkeen
rivinvaihto ja lopuksi luvun imaginriosa omalle rivilleen.
12.5.4 Merkkijonot
Merkkijonoja muotoillaan koodilla A, jolle annetaan parametriksi kentn leveys. Jos merkkijono on lyhyempi kuin kentn leveys, sijoitetaan merkkijono
kentn oikeaan laitaan. Jos merkkijono on pidempi kuin kentt, katkaistaan
merkkej merkkijonon lopusta. Merkkijonojen muotoilukoodia voi kytt
mys ilman kentn leveytt, jolloin koko merkkijonolauseke tulostetaan tai
luetaan.
Seuraavassa on esimerkkej merkkijonojen tulostamisesta:
WRITE (*,(A4)) Kuk
WRITE (*,(A4)) Kukkuluuruu
WRITE (*,(A)) Kukkuluuruu
Reaaliluku
Tulostus
0.0000234
0.1832
12.328
1343.43
3628372.843
.23400E-04
.18320
12.328
1343.4
.36284E+07
202
Fortran 95/2003
12.5.6 Ohjauskoodit
Trkeimmt sytn ja tulostuksen ohjauskoodit on esitetty taulukossa 12.4.
Koodi TR toimii tsmlleen samoin kuin koodi X.
Taulukko 12.4: Sytn ja tulostuksen ohjauskoodeja.
Tehtv
Koodi Esimerkki
Rivinvaihto
Absoluuttinen sarkaus
Suhteellinen sarkaus oikealle
Tulosta vlilyntej
Suhteellinen sarkaus vasemmalle
Vlilynnit eivt vaikuta sytss (oletus)
Vlilynnit tulkitaan nolliksi sytss
Tulosta plusmerkki luvun eteen
l tulosta plusmerkki luvun eteen
/
Tn
TRn
nX
TLn
BN
BZ
SP
SS
12.6
(I5,/,I8)
(I5,T20,I5)
(I5,TR5,I5)
(I5,5X,I5)
(I5,TL3,I5)
(BN,I5)
(BZ,I5)
(SP,I5)
(SS,I5)
Muotoilukoodien yhdistminen ja
tulostuslistat
Usein tulostuslistassa on monta lauseketta, ja muotoilukoodi sislt muotoiluohjeet nille eri tietotyypeille. Muotoilukoodi voi sislt yll esiteltyj
eri tietotyyppien koodeja, ohjauskoodeja, merkkijonovakioita sek toistorakenteita.
Esimerkiksi viisi perkkist kokonaislukua voidaan tulostaa muotoilukoodilla (5I8) ja kolme kokonaisluku-reaalilukuparia muotoilukoodilla
(3(I5,F8.3))
Jos muotoilukoodi loppuu ennen kuin kaikki tulostuslistan alkiot on ksitelty, tulostetaan rivinvaihto ja aloitetaan koodin kyttminen alusta.
Seuraava ohjelma havainnollistaa tulostuslistoja:
PROGRAM tulosta
IMPLICIT NONE
REAL, DIMENSION(5) :: a = 1
WRITE (*,("Taulukko a", 5G9.3)) a
WRITE (*,("Rivi ", 3G9.3)) a
END PROGRAM tulosta
1.00
1.00
203
Muotoilukoodin toistoon voi vaikuttaa kyttmll sulkuja. Esimerkiksi muotoilukoodi (A,/,(5F7.3)) tulostaa aluksi merkkijonon ja rivinvaihdon
sek lopuksi reaalilukuja, viisi lukua riville. Siis muotoilukoodin toistaminen
aloitetaan lopussa olevien sulkujen sislt. Seuraavassa on tst esimerkki:
PROGRAM toisto
IMPLICIT NONE
INTEGER :: i
WRITE (*,(A,/,(5F7.3))) Lukujono:, &
(SIN(i/10.0), i = 1, 12)
END PROGRAM toisto
0.296
0.717
0.389
0.783
0.479
0.841
Luvut tulostuivat puolipisteell ja vlilynnill erotettuina. Kytimme merkki : lopettamaan muotoilukoodin kytn, kun viimeinen tulostuslistan luku
on tulostettu.
204
Fortran 95/2003
12.7
12.8
Tiedostojen ksittely
Seuraavissa kappaleissa kerrotaan tiedostojen ksittelyst ja niiden liittmisest sytt- ja tulostuskanaviin. OPEN-lauseella avataan tiedosto ja liitetn se annettuun kanavanumeroon, INQUIRE-lauseella kyselln tiedoston
tai kanavan ominaisuuksia ja CLOSE-lauseella suljetaan tiedosto. Auki oleva
tiedosto voidaan kelata alkuun lauseella REWIND ja rivin verran taaksepin
lauseella BACKSPACE. Mys edell esitetyt READ- ja WRITE-lauseet ottavat parametrikseen kanavanumeron.
205
Yleens kanava 5 on syttkanava (standard input), ja kanava 6 on tulostuskanava (standard output). Lisksi useissa Unix-jrjestelmiss kanava 0
on varattu virheilmoituksille (standard error). Nm kanavat on valmiiksi
avattu, joten nit kanavanumeroita voi suoraan kytt sytt- ja tulostuslauseissa. Kuten tmn luvun alussa esitettiin, sytt- ja tulostuslauseissa
kanavanumero voidaan korvata merkill *, jolloin luetaan ja kirjoitetaan
ptteelt.
Monissa tietokoneissa kyttjrjestelm avaa uuden tiedoston, jos kirjoitetaan kanavanumerolle, jota ei ole liitetty mihinkn tiedostoon. Esimerkiksi
kanavalle 7 kirjoittaminen saattaa tuottaa tiedoston fort.7. Toisissa tietokoneissa avaamattomalle kanavalle kirjoittaminen tuottaa virheilmoituksen.
Seuraavassa esimerkiss luetaan tiedostosta data.a taulukon koko, varataan taulukko ja luetaan taulukon alkiot.
PROGRAM lue_taulukko
IMPLICIT NONE
REAL, ALLOCATABLE, DIMENSION(:) :: a
INTEGER :: n
OPEN (10, FILE=data.a)
READ (10, *) n
ALLOCATE (a(n))
READ (10, *) a
CLOSE (10)
END PROGRAM lue_taulukko
OPEN-lauseelle voi antaa useita tarkentimia. Tiedoston olemassaoloa ohjataan tarkentimella STATUS=st, miss st on merkkijonolauseke, jonka arvo
on OLD, NEW, REPLACE, SCRATCH tai UNKNOWN.
Arvo OLD edellytt, ett tiedosto on olemassa, ja arvo NEW puolestaan,
ett tiedosto ei saa olla olemassa. Tarkentimen arvolla REPLACE avattu
vanha tiedosto tuhotaan, muuten avataan uusi tiedosto. Arvo SCRATCH
luo tilapistiedoston, joka hvitetn CLOSE-lauseen suorituksen yhteydess. Tss tapauksessa tiedostolle ei saa antaa nime.
Seuraavassa esimerkiss avataan tilapistiedosto kanavalle 10:
OPEN (10, STATUS=SCRATCH)
Tarkentimella POSITION mrtn, mihin kohtaan tiedostoa aloitetaan kirjoittaa. Yleisimmin kytetty arvo tlle tarkenteelle on APPEND, jolloin kirjoitetaan tiedoston pern:
OPEN(20, FILE=data.a, POSITION=APPEND)
206
Fortran 95/2003
12.8.2 Binritiedostot
Fortranin oletusarvoinen tiedostotyyppi on tekstitiedosto, joka sislt luettavassa muodossa tallennettuja merkkijonoja ja lukuja. Niden lukeminen
ja kirjoittaminen on esimerkki formatoidusta tiedonsiirrosta.
Kuitenkin suurten tiedostojen ksittelyss on edullisempaa kytt binritiedostoja, joissa luvut ja merkkijonot on ilmaistu tietokoneen sisisess esitysmuodossa. Binritiedostojen kytt on formatoimatonta tiedonsiirtoa.
Fortranin binritiedostoilla on oma, kyseisest Fortran-toteutuksesta riippuva sisinen esitysmuoto. Siten esimerkiksi C-kielell kirjoitettu binritiedosto ei sellaisenaan ole yleens luettavissa Fortran-ohjelmalla.
Binritiedostot voivat sst huomattavasti tilaa, ne ovat nopeampia kytt, ja lisksi lukujen tarkkuus ei heikkene luku- ja kirjoitusoperaatioiden
takia. Binritiedostojen huono puoli on, ett ihminen ei saa niiden sisllst
selv, eik tiedostoja voi yleens siirt eri tietokoneiden vlill.
Binritiedosto avataan kytten OPEN-lauseessa tarkenninta
FORM=UNFORMATTED
12.8.3 Suorasaantitiedostot
Fortranin tiedostot ovat oletusarvoisesti perkkissaantitiedostoja, joita luetaan alusta alkaen tietue eli rivi kerrallaan. Fortranissa voi mys avata suo-
207
rasaantitiedostoja, jolloin tiedostosta voidaan lukea rivej halutussa jrjestyksess. Suorasaantitiedostot ovat oletusarvoisesti binrisi.
Suorasaantitiedostot ovat hydyllisi esimerkiksi monissa tietokantasovelluksissa. Tietueita ei tarvitse kirjoittaa jrjestyksess, vaan tiedostossa voi
olla reiki eli tyhji kirjoittamattomia tietueita.
Suorasaantitiedostot avataan kytten OPEN-lauseen tarkenninta
ACCESS=DIRECT
Oletusarvoisesti tiedostot ovat binrisi, joten tekstimuotoisen suorasaantitiedoston avaukseen tulee liitt tarkennin FORM=FORMATTED. Tietueen
pituus on ilmoitettava avauksessa tarkentimella RECL=pituus. Tietueen pituus ilmaistaan tekstitiedostoille merkkein ja binritiedostoille yleens tavuina. Luku- ja kirjoituslauseissa tulee valita tietue tarkentimella REC=tietue,
miss tietue tarkoittaa tietueen jrjestysnumeroa.
Alla olevassa esimerkiss avataan kaksi suorasaantitiedostoa, toinen binrisen ja toinen tekstimuotoisena.
INTEGER, DIMENSION(10) :: r
OPEN (10, FILE=dir.bin, ACCESS=DIRECT, RECL=40)
OPEN (20, FILE=dir.txt, ACCESS=DIRECT, &
FORM=FORMATTED, RECL=10)
WRITE (10, REC=13) r
WRITE (20, (F10.3), REC=3) r
Binritiedostoon kirjoitetaan tietue numero 13, joka sislt kymmenalkioisen kokonaislukutaulukon. Tss oletetaan, ett kokonaislukumuuttuja vie nelj tavua keskusmuistia ja vaatii vastaavan mrn tilaa binritiedostossa. Tekstitiedostoon kirjoitetaan kokonaislukutaulukon alkiot kukin
omaksi tietueekseen tietueesta 3 alkaen.
tai muotoa
INQUIRE (FILE=tiedosto, lista)
208
Fortran 95/2003
Mre
Selitys
Muuttujatyyppi
EXIST
OPENED
NAME
ACCESS
FORM
ACTION
NEXTREC
IOLENGTH
Looginen
Looginen
Merkkijono
Merkkijono
Merkkijono
Merkkijono
Kokonaisluku
Kokonaisluku
INTEGER :: n
REAL :: x
CHARACTER(LEN=12) :: saanti, muoto
INQUIRE (FILE=data.bin, EXIST=olemassa)
IF (.NOT. olemassa) &
STOP Tiedostoa data.bin ei ole olemassa!
OPEN(UNIT=10, FILE=data.bin, ACCESS=DIRECT, RECL=4)
READ(10, REC=3) x
INQUIRE (UNIT=10, ACCESS=saanti, FORM=muoto, NEXTREC=n)
WRITE (*,*) saanti, muoto, n, x
END PROGRAM kysely
UNFORMATTED
4 23.00000000
INQUIRE-lauseella saa mys selville tulostettavan muuttujalistan esityspituuden tulostuslaitteella. Tll tavalla voi esimerkiksi saada selville muuttujien binrisen talletustavan viemn tilan (yleens sama kuin lukujen viem
keskusmuistitila):
INTEGER :: len
INTEGER :: i
INQUIRE (IOLENGTH=len) i
WRITE (*,*) Kokonaisluvut, len, tavua
12.9
209
READ- ja WRITE-lauseissa voi kanavanumeron korvata merkkijonomuuttujan nimell, jolloin sytt- ja tulostusoperaatiot kohdistuvat thn merkkijonoon (ns. sisinen tiedosto). Tt voidaan kytt hyvksi esimerkiksi
luotaessa tilapistiedostojen nimi tai analysoitaessa ja muunnettaessa syterivej.
Seuraavassa esimerkiss muodostetaan tilapistiedoston nimi kirjoittamalla
se merkkijonomuuttujaan (esimerkitiedoston nimi on temp.007).
CHARACTER(LEN=20) :: tnimi
INTEGER :: n = 7
WRITE (tnimi, ("temp.", I3.3)) n
PRINT *, tnimi
OPEN(10, FILE=tnimi)
Standardifunktio INDEX hakee rivin ensimmisen pilkun sarakeindeksin. Ohjelma olettaa, ett rivill on tsmlleen yksi pilkku.
210
Fortran 95/2003
12.10
NAMELIST-rakenne
NAMELIST-rakenne mahdollistaa muuttujaryhmn ksittelemisen yhten kokonaisuutena sytss ja tulostuksessa. Muuttujille voidaan antaa arvot niiden nimien mukaan vapaassa jrjestyksess. Erityisen hydyllinen NAMELISTrakenne on silloin, kun muuttujille on annettu alkuarvot ja osalle muuttujista luetaan uudet arvot tiedostosta.
NAMELIST-rakenteen kytt havainnollistaa seuraava esimerkki:
PROGRAM leivo
IMPLICIT NONE
INTEGER :: jauhot = 1, sokeri = 1, munat = 1
NAMELIST /kakku/ jauhot, sokeri, munat
READ (*, NML=kakku)
WRITE (*, NML=kakku)
END PROGRAM leivo
NAMELIST-rakenne on ktev esimerkiksi pienten sytttiedostojen muotoilussa, jolloin sytttiedostosta tulee itsedokumentoiva.
12.11
Virhetilanteiden ksittely
Luettaessa tiedostoa READ-lauseella saa tilamuuttuja iovar negatiivisen arvon, jos tiedosto loppuu, positiivisen arvon virhetilanteessa ja arvon nolla,
211
12.12
Yhteenveto
Tss luvussa on esitetty trkeimmt Fortranin sytt- ja tulostusoperaatiot. Monista piirteist, erityisesti OPEN-lauseen lismreist, on ksitelty
vain oleellisimmat toiminnot. Seuraavissa luetteloissa on esitelty trkeimpien sytt- ja tulostuslauseiden syntaksi. Valinnaiset osat on kirjoitettu
hakasulkuihin.
212
Fortran 95/2003
Harjoitustehtvi
1. Mit eroa on WRITE- ja PRINT-lauseilla?
2. Seuraavassa esimerkiss on mritelty eri tavoilla Fortranin muotoilulausekkeita. Mit ohjelma tekee? Mitk mrittelyt ovat mielestsi toimivimpia?
PROGRAM muoto
IMPLICIT NONE
REAL :: x
CHARACTER(LEN=11) :: form1
CHARACTER(LEN=*), PARAMETER :: form2 = (F12.3,A)
x = 12.0
form1 = (F12.3,A)
WRITE (*, form1) x, hello
WRITE (*, form2) 2*x, hi
WRITE (*, (F12.3,A)) 3*x, hi hi
END PROGRAM muoto
213
4. Kirjoita listan ohjaamat syttrutiinit, jotka lukevat arvot edellisen tehtvn taulukoille. Anna esimerkki ohjelmasi sytttiedostosta.
5. Tiedostossa on formatoitua dataa seuraavan taulukon mukaisessa sarakesidonnaisessa esitysmuodossa:
Tieto
Sarakkeet Koodaus
etunimi
sukunimi
sukupuoli
siviilisty
115
2145
50
52
ik
5457
merkkijono
merkkijono
N=nainen, M=mies
0=naimaton, 1=naimisissa,
2=avoliitossa, 3=muu tai tuntematon
vuosina
214
Fortran 95/2003
9. Kirjoita ohjelma, joka tulostaa funktion f (x) = (sin x)/(x + cos x)2
kuvaajan tekstiptteelle esimerkiksi seuraavasti:
Syt ala- ja ylraja: 2 5
Syt laskentapisteiden lukumr
ja kuvaajan leveys vaakatasossa: 15 32
x:
y:
:.........:.........:.........:.
2.000
0.362
+
2.214
0.307
+
2.429
0.234
+
2.643
0.154
+
2.857
0.078
+
3.071
0.016
+
3.286 -0.027
+
3.500 -0.053 +
3.714 -0.066 +
3.929 -0.068 +
4.143 -0.065 +
4.357 -0.058 +
4.571 -0.050 +
4.786 -0.042
+
5.000 -0.034
+
Tss muuttuja k on kuukauden piv (1, 2, . . . , 31). Muuttuja m on kuukausi: 1 = maaliskuu, 2 = huhtikuu, . . . , 10 = joulukuu, 11 = tammikuu,
12 = helmikuu (ksittele tammikuu ja helmikuu edellisen vuoden kuukausina). Muuttuja c on vuosisata, esimerkiksi vuonna 1987 on c = 19.
Muuttuja y on vuosi eli vuonna 1987 on y = 87, paitsi tammi- ja helmikuussa y = 86. Muuttuja w on viikonpiv: 0 = sunnuntai, . . . , 6 =
lauantai.
13. Kirjoita ohjelma, joka laskee vektorin euklidisen normin. Vertaa ohjelmasi tehokkuutta BLAS-rutiiniin SNRM2, kun vektorin alkioiden lukumr on suuri.
13. Standardiproseduurit
13
215
Standardiproseduurit
13.1
Standardiproseduurien perusksitteit
Fortran 95 -standardi sislt 115 standardialiohjelmaa ja -funktiota. Useimmat standardiproseduurit ovat geneerisi, joten samaa funktio- tai aliohjelmakutsua voi kytt eri tyyppisille argumenteille. Tten funktiokutsua
SIN(x) voi kytt eri lajien reaali- ja kompleksilukuargumenteille.
Osa standardiproseduureista on alkioittaisia (elemental), mik tarkoittaa, ett proseduurikutsu kohdistuu kuhunkin argumentin alkioon erikseen. Esimerkiksi ohjelmakoodi
REAL, DIMENSION(100) :: x, y
INTRINSIC SIN
x = SIN(y)
216
Fortran 95/2003
13.2
Standardiproseduurien kuvauksia
Taulukko Sivu
Sekalaisia varusfunktioita
Kellonaika ja pivmr
Satunnaislukujen tuottaminen
Trigonometriset sek logaritmi- ja eksponenttifunktiot
Numeerinen tarkkuus ja konversiot
Numeerisia ja matemaattisia funktiota
Merkkijonojen ksittely
Taulukko-operaatioita
Lis taulukko-operaatioita
Proseduureja bittien ksittelyyn
13.1
13.2
13.3
13.4
13.5
13.6
13.7
13.8
13.9
13.10
217
217
218
220
221
222
223
224
225
226
Taulukoissa on kerrottu kunkin proseduurin kutsusyntaksi sek argumenttien mahdolliset tyypit. Lisksi on kerrottu argumenttien INTENT-arvot (IN,
OUT tai INOUT) sek ilmoitettu, onko argumentti valinnainen (OPTIONAL). Proseduuri voi palauttaa tulokset OUT- tai INOUT-tyyppisiss argumenteissa ja
lukee sytteen IN- tai INOUT-tyyppisist argumenteista.
Funktion palauttaman arvon tyyppi on esitetty seuraavaan tapaan:
L = ALLOCATED(array) tutki, onko taulukolle varattu tilaa
Kirjain L tarkoittaa, ett funktion arvo on tyyppi LOGICAL. Muita mahdollisuuksia ovat: I eli INTEGER, R eli REAL, D eli DOUBLE PRECISION, C eli
CHARACTER ja Z eli COMPLEX.
Kaksoistarkkuuden tyyppi DOUBLE PRECISION esiintyy taulukoissa historiallisista syist. Tmn tyypin kytn voi korvata parametrisoidulla reaalilukutyypill.
Jos funktion arvo riippuu argumenttien tyypist, on tm merkitty seuraavasti:
* = MAXVAL(array,dim,mask) maksimiarvo
Jos useammalla proseduurilla on sama argumenttilista, on nm proseduurit lueteltu taulukossa perkkin ja niiden alapuolella on yhteinen argumenttien kuvaus.
13. Standardiproseduurit
217
Fortranin standardiproseduurien kytt esitelln mys oppaan muissa luvuissa. Kerromme Fortranin lausekkeista luvussa 6 (sivu 67). Havainnollistamme taulukkojen ksittely luvussa 11 (sivu 164).
Argumentin tyyppi
Suunta Valinnaisuus
ALLOCATABLE
IN
IN
IN
OPTIONAL
Argumentin tyyppi
Suunta Valinnaisuus
REAL
OUT
218
Fortran 95/2003
Argumentin tyyppi
Suunta Valinnaisuus
13.3
INTEGER
INTEGER, DIMENSION(m)
INTEGER, DIMENSION(m)
OUT
IN
OUT
OPTIONAL
OPTIONAL
OPTIONAL
Kyseess on siis vuoden 1998 heinkuun 28. piv, ja kello on hiukan yli
11:00:39. Ohjelman tulostamat sekunnit puolestaan vastaavat kuluvan vuorokauden kellonaikaa sekunteina.
13. Standardiproseduurit
13.4
219
Taulukossa 13.3 on esitelty satunnaislukujen tuottamiseen tarvittavat rutiinit. Satunnaisluvut riippuvat satunnaislukugeneraattorin alustamiseen kytetyist siemenluvuista. Samoilla siemenluvuilla saadaan aina sama satunnaislukusarja. Jos siemenlukua ei aseteta, ohjelma voi tuottaa eri ajokerroilla
samat satunnaisluvut.
Seuraavassa ohjelmassa alustamme satunnaislukugeneraattorin kellonajan
perusteella laskettavalla siemenluvulla ja tuotamme halutun mrn tasajakautuneita satunnaislukuja vlilt [a, b).
PROGRAM satunnainen
IMPLICIT NONE
CALL alusta
CALL tulosta
CONTAINS
SUBROUTINE alusta
IMPLICIT NONE
INTEGER :: koko, tila
INTEGER, DIMENSION(8) :: t
INTEGER, DIMENSION(:), ALLOCATABLE :: siemen
CALL RANDOM_SEED(size=koko)
ALLOCATE(siemen(koko), stat=tila)
IF (tila > 0) STOP Tilanvaraus eponnistui!
CALL DATE_AND_TIME(values = t)
siemen = 100*t(7) + t(8)/10
CALL RANDOM_SEED(put=siemen)
END SUBROUTINE alusta
SUBROUTINE tulosta
IMPLICIT NONE
INTEGER :: n, tila
REAL :: a, b
REAL, DIMENSION(:), ALLOCATABLE :: luvut
write (*,(A),ADVANCE=NO) Anna ala- ja ylraja:
READ (*,*) a, b
WRITE (*,(A),ADVANCE=NO) &
Anna satunnaislukujen lukumr:
READ (*,*) n
ALLOCATE(luvut(n), stat=tila)
IF (tila > 0) STOP Tilanvaraus eponnistui!
CALL RANDOM_NUMBER(luvut)
WRITE (*,(A)) Satunnaisluvut:
WRITE (*,(6(F10.6))) a + (b-a)*luvut
END SUBROUTINE tulosta
END PROGRAM satunnainen
Satunnaislukugeneraattori alustettiin aliohjelmassa alusta ja satunnaislukujen tuottaminen tehtiin aliohjelmassa tulosta. Satunnaislukugeneraattorin vaatiman siemenlukutaulukon koko selvitettiin aliohjelmakutsulla
CALL RANDOM_SEED(size=koko)
220
Fortran 95/2003
Siemenlukutaulukon sisllksi asetettiin rutiinin DATE_AND_TIME palauttamista sekunneista ja millisekunneista laskettu kokonaisluku, joka on vlilt
[0, 29999]:
CALL DATE_AND_TIME(values = t)
siemen = 100*t(7) + t(8)/10
CALL RANDOM_SEED(put=siemen)
Tuloksena on tasajakautuneita satunnaislukuja vlilt [0, 1). Tulostuslausekkeessa a + (b-a)*luvut luvut skaalataan vlille [a, b).
Seuraavassa on ohjelman kyttesimerkki:
Anna ala- ja ylraja: -1 1
Anna satunnaislukujen lukumr: 10
Satunnaisluvut:
-0.253170 0.654368 -0.700821 -0.983755 -0.877386
0.135530 -0.885027 -0.704163 -0.781958
0.948415
Argumentin tyyppi
R = ACOS(x) arkuskosini
R = ASIN(x) arkussini
x
REAL, |x| 1
Suunta Valinnaisuus
IN
R = ATAN(x) arkustangentti
R = TAN(x) tangentti
x
REAL
* = COS(x) kosini
* = SIN(x) sini
x
REAL tai COMPLEX
IN
IN
IN
IN
REAL
IN
* = EXP(x) eksponenttifunktio
* = LOG(x) luonnollinen logaritmi
x
IN
REAL, x > 0
IN
13. Standardiproseduurit
221
Argumentin tyyppi
Suunta Valinnaisuus
IN
x
numeerinen
IN
* = HUGE(x) suurin luku annetun muuttujan tyyppi
x
IN
REAL
IN
IN
IN
OPTIONAL
IN
IN
OPTIONAL
x
mik tahansa perustyyppi
IN
I = SELECTED_INT_KIND(r) halutun tarkkuuden kokonaislukutyyppi
r
INTEGER
IN
I = SELECTED_REAL_KIND(p,r) halutun tarkkuuden reaalilukutyyppi
p
INTEGER
r
INTEGER
R = SCALE(x,i) skaalaa reaaliluku: x = x*(b**i)
x
REAL
i
INTEGER
R = SET_EXPONENT(x,i) aseta luvun x eksponentti
x
i
REAL
INTEGER
IN
IN
IN
IN
IN
IN
OPTIONAL
OPTIONAL
222
Fortran 95/2003
Argumentin tyyppi
Suunta Valinnaisuus
IN
z
COMPLEX
IN
R = AINT(a,kind) katkaisu kokonaislukuun nollan suuntaan
R = ANINT(a,kind) lhin kokonaisluku
a
REAL
IN
kind
INTEGER
IN
I = CEILING(a,kind) pyristys ylspin
a
REAL
kind
INTEGER
Z = CONJG(z) kompleksikonjugaatti
IN
IN
z
COMPLEX
* = DIM(x,y) erotus x y tai nolla jos x y < 0
IN
x
INTEGER tai REAL
y
sama kuin x
D = DPROD(x,y) kaksoistarkkuuden tulo: x y
IN
IN
x
oletustarkkuuden REAL
y
oletustarkkuuden REAL
I = FLOOR(a,kind) katkaisu alaspin
IN
IN
a
REAL
kind
INTEGER
R = FRACTION(x) luvun murto-osa
x
REAL
* = MAX(a1,a2,a3, . . . ) lukujen maksimiarvo
IN
IN
OPTIONAL
OPTIONAL
OPTIONAL
IN
IN
IN
IN
OPTIONAL
* = SQRT(x) nelijuuri: x
x
IN
IN
IN
IN
IN
OPTIONAL
13. Standardiproseduurit
223
Argumentin tyyppi
Suunta Valinnaisuus
IN
i
INTEGER
kind
INTEGER
I = IACHAR(c) ASCII-merkin jrjestysnumero
IN
IN
OPTIONAL
IN
IN
IN
OPTIONAL
IN
IN
string
CHARACTER
IN
ncopies
INTEGER
IN
C = SCAN(string,set,back) hae merkkej merkkijonosta
string
CHARACTER
set
CHARACTER
back
LOGICAL
C = TRIM(string) poista lopussa olevat vlilynnit
IN
IN
IN
OPTIONAL
string
CHARACTER
IN
I = VERIFY(string,set,back) tarkista, koostuuko merkkijono
annetuista merkeist
string
CHARACTER
IN
set
CHARACTER
IN
back
LOGICAL
IN
OPTIONAL
224
Fortran 95/2003
Argumentin tyyppi
Suunta Valinnaisuus
OPTIONAL
OPTIONAL
OPTIONAL
IN
IN
IN
IN
IN
IN
OPTIONAL
13. Standardiproseduurit
225
Argumentin tyyppi
Suunta Valinnaisuus
IN
IN
IN
OPTIONAL
* = MINVAL(array,dim,mask) minimiarvo
array
OPTIONAL
OPTIONAL
OPTIONAL
IN
array
mik tahansa taulukko
IN
dim
INTEGER
IN
* = PRODUCT(array,dim,mask) taulukon alkioiden tulo
OPTIONAL
IN
IN
matrix_a
numeerinen tai looginen matriisi
matrix_b
numeerinen tai looginen matriisi
* = TRANSPOSE(matrix) matriisin transpoosi
IN
IN
matrix
taulukko, DIMENSION(m,n)
IN
226
Fortran 95/2003
Argumentin tyyppi
Suunta Valinnaisuus
IN
IN
IN
IN
i
INTEGER
IN
pos
INTEGER
IN
I = IAND(i,j) kokonaislukujen looginen and-operaatio
I = IEOR(i,j) biteittinen xor-operaatio (exclusive or)
I = IOR(i,j) biteittinen or-operaatio
i
INTEGER
j
sama kuin i
I = NOT(i) biteittinen looginen komplementti
i
INTEGER
IN
IN
IN
IN
IN
i
INTEGER
IN
shift
INTEGER
IN
size
INTEGER
IN
OPTIONAL
CALL MVBITS(from,frompos,len,to,topos) kopioi bittej muuttujasta
toiseen
from
INTEGER
IN
frompos
INTEGER
IN
len
INTEGER
IN
to
INTEGER
INOUT
topos
INTEGER
IN
13.5
Esimerkki: bittienksittelyoperaatiot
Fortran 95:n bittienksittelyproseduurit perustuvat USA:n armeijan standardiin (MIL-STD 1753). Useimmat bittioperaatiot ovat alkioittaisia, joten niille
voi antaa mys taulukkoargumentteja.
Bittioperaatiot ksittelevt kokonaislukuja, joissa on jonossa s bitti wk ,
k = 0, 1, . . . , s 1. Bittien jrjestys on oikealta vasemmalle, ja kokonaisluvun
13. Standardiproseduurit
227
ei-negatiivinen arvo on
s1
wk 2k .
k=0
Tietyn bitin arvon saa selville funktiokutsulla BTEST(i,pos), miss kokonaislukumuuttujan pos arvo on vlilt 0 pos < BIT_SIZE(i). Funktio
palauttaa loogisen arvon .TRUE. tai .FALSE..
Funktiokutsu IAND(i,j) palauttaa kokonaislukujen i ja j vastaaville biteille tehdyn and-operaation tuloksen. Seuraavassa on esimerkki funktion
toiminnasta:
i
j
IAND(i,j)
0
0
0
0
1
0
1
0
0
1
1
1
Kokonaislukujen i ja j tytyy olla samaa lajia. Funktio IAND palauttaa arvonaan tt lajia olevan kokonaisluvun.
Funktio ISHFTC(i,shift,size) palauttaa kokonaisluvun, jossa size oikeanpuoleista bitti on siirretty kehss |shift| paikkaa vasemmalle (tai
oikealle, jos shift on negatiivinen).
Aliohjelmakutsu
CALL MVBITS(from,frompos,len,to,topos)
kopioi kokonaisluvun from bittej kokonaislukuun to. Kopiointi alkaa paikassa frompos olevasta bitist. Kopioitavan bittijonon pituus on len. Bitit
kopioidaan paikasta topos alkaen. Argumenttien tytyy tytt seuraavat
ehdot: len 0, frompos 0, frompos+len BIT_SIZE(from), topos 0
ja topos+len BIT_SIZE(to).
13.6
228
Fortran 95/2003
PROGRAM bittioperaatiot
IMPLICIT NONE
INTEGER, PARAMETER :: &
kok_luku = SELECTED_INT_KIND(9), bit_len = 8
INTEGER(KIND=kok_luku), DIMENSION(4) :: luvut
INTEGER :: i
WRITE (*,(A,I3)) Syt nelj kokonaislukua vlilt &
&0 ... , 2**bit_len-1
READ (*,*) luvut
DO i = 1, SIZE(luvut)
WRITE (*,(A,I1,":",7X,A)) Data , i, bitit(luvut(i))
END DO
WRITE (*,(A,A)) Pakattu data: , bitit(pakkaa(luvut))
CONTAINS
FUNCTION bitit(n)
IMPLICIT NONE
INTEGER(KIND=kok_luku), INTENT(IN) :: n
CHARACTER(LEN=4*bit_len) :: bitit
INTEGER :: i, lkm
bitit =
lkm = MIN(LEN(bitit), BIT_SIZE(n))
DO i = 0, lkm-1
IF(BTEST(n,i)) THEN
bitit(lkm-i:lkm-i) = 1
ELSE
bitit(lkm-i:lkm-i) = 0
END IF
END DO
END FUNCTION bitit
FUNCTION pakkaa(taulu)
IMPLICIT NONE
INTEGER, DIMENSION(:), INTENT(IN) :: taulu
INTEGER(KIND=kok_luku) :: pakkaa
INTEGER :: i, paikka
pakkaa = 0
DO i = 1, SIZE(taulu)
paikka = bit_len*(i-1)
IF ((paikka + bit_len) > BIT_SIZE(pakkaa)) RETURN
CALL MVBITS(taulu(i), 0, bit_len, pakkaa, paikka)
END DO
END FUNCTION pakkaa
END PROGRAM bittioperaatiot
Sisinen funktio bitit muuntaa kokonaisluvun merkkijonoksi, jossa esiintyy kokonaisluvun bittej vastaavat merkit 0 ja 1. Sisinen funktio
pakkaa siirt kokonaislukutaulukon taulu merkitsevt bitit funktion arvona palautettavan kokonaisluvun sislle.
Ohjelman kytt voisi nytt tlt:
Syt nelj kokonaislukua vlilt 0 ... 255
100 127 254 209
Luvut ovat: 100, 127, 254, 209
Data 1:
00000000000000000000000001100100
Data 2:
00000000000000000000000001111111
13. Standardiproseduurit
229
Data 3:
00000000000000000000000011111110
Data 4:
00000000000000000000000011010001
Pakattu data: 11010001111111100111111101100100
13.7
Standardifunktioiden erityisnimet
230
Fortran 95/2003
0.8414710
(0.8414710,0.0000000E+00)
0.0000000E+00
Geneerinen nimi
Erityisnimet
AINT(a)
ANINT(a)
NINT(a)
ABS(a)
MOD(a,p)
SQRT(x)
EXP(x)
LOG(x)
LOG10(x)
SIN(x)
COS(x)
TAN(x)
ASIN(x)
ACOS(x)
ATAN(x)
ATAN2(y,x)
SINH(x)
COSH(x)
TANH(x)
AIMAG(z)
CONJG(z)
LEN(s)
INDEX(s,t)
SIGN(a,b)
DIM(x,y)
AINT, DINT
ANINT, DNINT
NINT, IDNINT
IABS, ABS, DABS, CABS
MOD, AMOD, DMOD
SQRT, DSQRT, CSQRT
EXP, DEXP, CEXP
ALOG, DLOG, CLOG
ALOG10, DLOG10
SIN, DSIN, CSIN
COS, DCOS, CCOS
TAN, DTAN
ASIN, DASIN
ACOS, DACOS
ATAN, DATAN
ATAN2, DATAN2
SINH, DSINH
COSH, DCOSH
TANH, DTANH
AIMAG
CONJG
LEN
INDEX
ISIGN, SIGN, DSIGN
IDIM, DIM, DDIM
DPROD(x,y)
R, D
R, D
R, D
I, R,
I, R,
R, D,
R, D,
R, D,
R, D
R, D,
R, D,
R, D
R, D
R, D
R, D
R, D
R, D
R, D
R, D
Z
Z
C
C
I, R,
I, R,
R
13.8
D, Z
D
Z
Z
Z
Z
Z
D
D
R,
R,
I
I,
I,
R,
R,
R,
R,
R,
R,
R,
R,
R,
R,
R,
R,
R,
R,
R
Z
I
I
I,
I,
D
D
D
R, D, Z
R, D
D, Z
D, Z
D, Z
D
D, Z
D, Z
D
D
D
D
D
D
D
D
R, D
R, D
Listietoja
Tss esitetty laajempi Fortranin standardiproseduurien kuvaus lytyy ksikirjoista Fortran 90 Handbook [ABM+ 92] ja Fortran 95 Handbook [ABM+ 97]
sek Fortran-kntjien ksikirjoista. Mys teos Fortran 95 Language Guide [Geh96] soveltuu ksikirjaksi.
13. Standardiproseduurit
231
13.9
Geneerinen nimi
INT(a)
INT
IFIX
IDINT
R
R
D
I
I
I
REAL(a)
REAL
FLOAT
SNGL
I
I
D
R
R
R
MAX(a1,a2,...)
MAX0
AMAX1
DMAX1
AMAX0
MAX1
I
R
D
I
R
I
R
D
R
I
MIN(a1,a2,...)
MIN0
AMIN1
DMIN1
AMIN0
MIN1
I
R
D
I
R
I
R
D
R
I
Yhteenveto
Fortran 95:een sisltyy yli sata standardiproseduuria, joita kannattaa kytt hyvksi omassa ohjelmointityss. Nm proseduurit ovat tehokas ja
luotettava tapa toteuttaa ohjelmoinnin perusoperaatioita.
Harjoitustehtvi
1. Ratkaise yhtln x n = 1 kaikki kompleksiset juuret (vihje: e2 k i = 1,
k = 0, 1, . . . ).
2. Muuta kappaleen 13.4 satunnaislukuja tuottavaa ohjelmaa siten, ett
kyttj pyydetn syttmn siemenluku.
3. Kirjoita aliohjelma, joka muuntaa napakoordinaattiesityksen (r , ) karteesisiksi koordinaateiksi (x, y). Kirjoita mys pinvastaisen muunnoksen tekev aliohjelma. Kyt hyvksi mritelmi
sin = y/r ,
cos = x/r ,
r = x2 + y 2 .
232
Fortran 95/2003
5. Laske 5 4 ja 4 3 -kokoisten matriisien A ja B tulo C = AB standardifunktiolla MATMUL. Laske mys tulo C T = B T AT , miss B T on matriisin
B transpoosi jne.
6. Etsi kyttjn syttmst korkeintaan 80 merkin pituisesta merkkijonosta ensimmisen numeromerkin sijainti kytten SCAN-funktiota.
7. Kirjoita looginen funktio numerot, joka ilmoittaa, koostuuko argumenttina annettu merkkijono pelkstn numeromerkeist. Kyt apuna standardifunktiota VERIFY.
8. Mrittele aliohjelma suorakulmio, joka tulostaa halutun kokoisia suorakulmioita. Aliohjelmakutsun CALL suorakulmio(3,5) tulostus voisi nytt tlt:
+---+
!
!
+---+
10. Lis kappaleen 13.6 ohjelmaan funktio, joka purkaa kokonaislukumuuttujaan pakatut pienet positiiviset kokonaisluvut. Funktion tulee
palauttaa arvonaan neljn alkion mittainen kokonaislukutaulukko.
11. Tee salasanageneraattori, joka muodostaa ja tulostaa 8 merkist koostuvan satunnaisen salasanan, joka koostuu isoista ja pienist kirjaimista,
numeroista sek erikoismerkeist
!"#%&/()=?+*;:,._-<>
13. Kirjoita funktiot, jotka palauttavat arvoinaan yksiulotteisen reaalilukutaulukon, jonka alkiot muodostavat
(a) aritmeettisen jonon, jonka alkuarvo ja askel on annettu
(b) geometrisen jonon, jonka alkuarvo ja kerroin on annettu.
Funktioiden kutsut voisivat nytt seuraavilta:
a(1:n) = seq_real(start, inc, n)
b(1:n) = geomseq_real(start, coeff, n)
13. Standardiproseduurit
233
i = maxloci_real(vector,mask)
i = miniloci_real(vector,mask)
15. Kirjoita edellist tehtv vastaavat funktiot kokonaislukuargumenteille. Sijoita funktiot moduuliin ja mrittele niille geneeriset nimet, esimerkiksi maxloci ja miniloci.
234
Fortran 95/2003
14
Esimerkkiohjelmia
14.1
Aihe
Kappale Sivu
Nelilaskin
Datan lajittelu
Sokkelon tekeminen
Yksiulotteinen soluautomaatti
Life-soluautomaatti
Binripuu
Sukupuu
Optimointi: evoluutiostrategiat
Lineaaristen yhtlryhmien ratkaisu
14.1
14.2
14.3
14.4
14.5
14.6
14.7
14.8
14.9
234
237
243
247
253
256
261
263
269
Nelilaskin
14. Esimerkkiohjelmia
235
REAL :: a, b
silmukka: DO
WRITE(UNIT=*,FMT=(A),ADVANCE=no) kehote
READ (*,(A)) rivi
rivi = ADJUSTL(rivi)
IF (LEN_TRIM(rivi) /= 1) THEN
CALL lue_syote(rivi)
ELSE
SELECT CASE (rivi(1:1))
CASE (+)
a = pop(); b = pop(); CALL push(b+a)
CASE (-)
a = pop(); b = pop(); CALL push(b-a)
CASE (*)
a = pop(); b = pop(); CALL push(b*a)
CASE (/)
a = pop(); b = pop(); CALL push(b/a)
CASE (P, p)
a = pop(); WRITE (*,*) a
CASE (Q, q)
STOP
CASE DEFAULT
CALL lue_syote(rivi)
END SELECT
END IF
END DO silmukka
CONTAINS
SUBROUTINE lue_syote(rivi)
IMPLICIT NONE
CHARACTER (LEN=*), INTENT(IN) :: rivi
INTEGER :: tila
REAL :: luku
tila = 0
READ (rivi,*,IOSTAT=tila) luku
IF (tila == 0) THEN
CALL push(luku)
ELSE
WRITE (*,*) Syntaksivirhe - viimeisin &
&sytttietorivi hyltty!
END IF
END SUBROUTINE lue_syote
END PROGRAM nelilaskin
Mrittelemme moduulin pinomoduuli myhemmin tss kappaleessa. Tst moduulista ovat perisin pinon ksittelyoperaatiot pop ja push.
Ohjelma lukee kyttjn antaman syterivin 80 merkin pituiseen merkkijonomuuttujaan rivi. Alussa siirretn vlilynnit sytteen alusta loppuun.
Jos sytteess on enemmn kuin yksi vlilynnist poikkeava merkki, kyseess on luvun sisltv syte tai virhetilanne. Jos sytteen pituus on yksi
vlilynnist poikkeava merkki, on kyseess komento, yksittinen numeromerkki tai virhetilanne.
Seuraavassa on ohjelman kyttesimerkki:
rpn> 5
236
Fortran 95/2003
rpn> 2.2
rpn> *
rpn> p
11.00000000
rpn> 10
rpn> 3
rpn> /
rpn> p
3.333333254
rpn> q
Moduulissa kytetty tyyppi pinotyyppi on yksityinen, sill moduulin sisltmt tieto-oliot on piilotettu kyttmll PRIVATE-lausetta. Tten voimme muuttaa pinon toteutuksen yksityiskohtia moduulin toiminnallisuuden
muuttumatta.
14. Esimerkkiohjelmia
14.2
237
Datan lajittelu
Tss esimerkiss lajittelemme yksiulotteisia taulukkoja suuruusjrjestykseen. Ensimmisen lajittelualgoritmina kytmme sijoituslajittelua (insertion sort), joka on yksinkertainen ja riittv pienelle datamrlle (parikymment alkiota). Tmn jlkeen toteutamme Shellsort-lajittelualgoritmin
nousuindeksin laskemista varten.
14.2.1 Sijoituslajittelu
Voimme mritell reaalilukutaulukon lajittelevan aliohjelman lajittele_r
seuraavasti:
MODULE jarjestys
IMPLICIT NONE
CONTAINS
SUBROUTINE lajittele_r(taulu)
IMPLICIT NONE
REAL, INTENT(INOUT), DIMENSION(:) :: taulu
REAL :: apu
INTEGER :: i, j, n
n = SIZE(taulu)
DO i = 2, n
apu = taulu(i)
DO j = i, 2, -1
IF (taulu(j-1) <= apu) EXIT
taulu(j) = taulu(j-1)
END DO
taulu(j) = apu
END DO
END SUBROUTINE lajittele_r
END MODULE jarjestys
238
Fortran 95/2003
Aliohjelma lajittele_i on lhestulkoon edell esitellyn lajittele_r-aliohjelman kopio, ainoa muutos tulee riveille:
SUBROUTINE lajittele_i(taulu)
IMPLICIT NONE
INTEGER, DIMENSION(:), INTENT(INOUT) :: taulu
INTEGER :: apu
jne.
END SUBROUTINE lajittele_i
14. Esimerkkiohjelmia
239
Tmkin aliohjelma on muilta osin reaalilukuja lajittelevan aliohjelman suora kopio, sill mys merkkijonojen jrjestyksen vertailuun voi kytt operaattoria <=.
Voimme kytt geneerisen lajitteluproseduurin lajittele sisltv moduulia seuraavasti:
PROGRAM lajittelu_testi
USE jarjestys, ONLY : lajittele
IMPLICIT NONE
REAL, DIMENSION(:), ALLOCATABLE :: dr
INTEGER, DIMENSION(:), ALLOCATABLE :: di
CHARACTER(LEN=8), DIMENSION(:), ALLOCATABLE :: dc
INTEGER :: n, i, tila
WRITE (*,(A),ADVANCE=NO) Anna n>1:
READ (*,*) n
IF (n <= 1) THEN
STOP n <= 1
ELSE
ALLOCATE(dr(n), di(n), dc(n), STAT=tila)
IF (tila /= 0) THEN
STOP Muistinvaraus eponnistui!
ELSE
CALL RANDOM_NUMBER(dr)
di = 1e6*dr
dc = teksti-
dc(:)(8:8) = CHAR(IACHAR( ) + &
MOD(di,1+IACHAR(z)-IACHAR( )))
WRITE (*,(A,/,6(F9.5))) Data:, dr
CALL lajittele(dr)
WRITE (*,(A,/,6(F9.5))) Lajiteltu data:, dr
WRITE (*,(A,/,6(I9))) Data:, di
CALL lajittele(di)
WRITE (*,(A,/,6(I9))) Lajiteltu data:, di
WRITE (*,(A,/,6(A9))) Data:, dc
CALL lajittele(dc)
WRITE (*,(A,/,6(A9))) Lajiteltu data:, dc
END IF
END IF
END PROGRAM lajittelu_testi
Pohjelmassa tytetn reaalilukutaulukko dr satunnaisluvuilla reaalilukuvlilt [0, 1). Kokonaislukutaulukon di arvot saadaan kertomalla nm
reaaliluvut miljoonalla. Merkkitaulukon dc arvoiksi asetetaan merkkijonot
teksti-c, miss c on satunnainen ASCII-merkki vlilynnin ja z-kirjaimen vlilt (katso liitett D sivulla 324).
Ohjelman tulostus nytt tlt:
Anna n>1: 11
Data:
0.11639 0.96485
0.88297
0.42049
0.49586
0.57739
240
Fortran 95/2003
0.94234
Lajiteltu
0.11639
0.57739
Data:
116391
942340
Lajiteltu
116391
577386
Data:
teksti-"
teksti-C
Lajiteltu
teksti-"
teksti-b
0.24316
data:
0.24316
0.68923
0.55013
0.68923
0.47643
0.42049
0.88297
0.47643
0.94234
0.49586
0.96485
0.55013
964846
243162
data:
243162
689230
882970
550126
420486
689230
495856
476426
577386
420486
882970
476426
942340
495856
964846
550126
teksti-
teksti-*
data:
teksti-*
teksti-r
14. Esimerkkiohjelmia
241
IF (askel == 1) EXIT
END DO
END FUNCTION nousuindeksi
END MODULE nousu
Funktio nousuindeksi palauttaa tuloksen taulukossa idx. Shellsort-algoritmi on kohtalaisen nopea, vaikkakin isoille taulukoille (tuhansia alkioita) olisi
Quicksort-algoritmi luultavasti nopeampi.
Ohjelmakoodissa on kytetty Fortran 95:n ohjausrakenteita DO ... END DO
ja DO WHILE ... END DO sek EXIT-lausetta. Indeksitaulu idx alustetaan
kytten Fortranin taulukkoalustinta (/ ... /).
Olkoon lajiteltavana reaalilukutaulukko tiedot, jolloin nousuindeksin laskeminen ja lajittelu voitaisiin tehd seuraavasti:
PROGRAM lajittelu_testi
! Otetaan kyttn lajittelufunktio:
USE nousu, ONLY : nousuindeksi
IMPLICIT NONE
REAL, DIMENSION(:), ALLOCATABLE :: tiedot
INTEGER, DIMENSION(:), ALLOCATABLE :: indeksit
INTEGER :: n, tila
WRITE (*,(A),ADVANCE=NO) Anna n>1:
READ (*,*) n
IF (n <= 1) THEN
STOP n <= 1
ELSE
ALLOCATE(tiedot(n), indeksit(n), STAT=tila)
IF (tila /= 0) THEN
STOP Virhe muistinvarauksessa!
END IF
CALL RANDOM_NUMBER(tiedot)
WRITE (*,(A,/,8(F9.5))) Data:, tiedot
indeksit = nousuindeksi(tiedot)
WRITE (*,(A,/,8(F9.5))) Lajiteltu data:, &
tiedot(indeksit)
END IF
END PROGRAM lajittelu_testi
242
Fortran 95/2003
Aliohjelmassa lajittele lasketaan nousuindeksi taulukolle taulu, ja tmn jlkeen argumentti taulu lajitellaan nousuindeksin avulla. Jos aliohjelmalle lajittele on annettu valinnaiset (OPTIONAL) argumentit lisataulu1
tai lisataulu2, lajitellaan nm saman nousuindeksin avulla. Valinnaisten argumenttien antaminen aliohjelmakutsussa voidaan selvitt standardifunktion PRESENT avulla. Funktio SIZE palauttaa taulukon koon.
Voimme kytt tt lajittelualiohjelmaa esimerkiksi seuraavasti:
PROGRAM nousukas
USE nousu, ONLY : lajittele
IMPLICIT NONE
REAL, DIMENSION(100) :: d1, d2, d3
CALL RANDOM_NUMBER(d1)
d2 = 10.0 - d1
d3 = 2.0*(d1 - 0.5)
CALL lajittele(d1, d2, d3)
END PROGRAM nousukas
14. Esimerkkiohjelmia
243
14.3
Sokkelon tekeminen
Tehtvn on luoda sokkeloruudukko, jossa on tsmlleen yksi reitti sokkelon lpi vasemmasta ylkulmasta oikeaan alakulmaan. Tehtv voidaan
jakaa seuraaviin osavaiheisiin:
1. kysytn halutun sokkelon kokoa ja alustetaan laskentatehtv
2. luodaan sokkelo
3. tulostetaan muodostettu sokkelo.
Sokkelo voidaan luoda ehk helpoiten kaksiulotteiseen kokonaislukutaulukkoon. Sokkelon tekemisess tarvittava tieto vapaista ja kussakin vaiheessa
kytetyist ruuduista sijoitetaan thn taulukkoon.
Seuraavassa esitetn runko sokkelon tekevlle ohjelmalle:
PROGRAM sokkelo
IMPLICIT NONE
INTEGER, DIMENSION(:,:), ALLOCATABLE :: taulu
INTEGER :: leveys, korkeus
Alustetaan tehtv
Luodaan sokkelo
Tulostetaan sokkelo
END PROGRAM sokkelo
Aliohjelmassa alusta kytetn pohjelman alussa mriteltvi globaaleja vakioita reuna ja tyhj, joiden arvot mrmme myhemmin.
244
Fortran 95/2003
Ohjelma siis simuloi diskreetti satunnaiskulkua (random walk) suorakulmaisessa hilassa. Umpikujaan joutumisen voi tarkistaa seuraavalla funktiolla:
LOGICAL FUNCTION umpikuja(k, l)
IMPLICIT NONE
INTEGER, INTENT(IN) :: k, l
umpikuja = taulu(k,l+1) /= tyhja .AND. &
taulu(k,l-1) /= tyhja .AND. &
taulu(k+1,l) /= tyhja .AND. &
taulu(k-1,l) /= tyhja
END FUNCTION umpikuja
14. Esimerkkiohjelmia
245
CASE(3)
CALL RANDOM_NUMBER(t)
arvaa = vapaat(FLOOR(3*t+1))
END SELECT
END FUNCTION arvaa
Nyt meill onkin mriteltyn valmis sokkelonteko-ohjelma lukuunottamatta tulostusproseduuria. Voimme simuloida tulostusta aluksi seuraavalla yksinkertaisella aliohjelmalla:
SUBROUTINE tulosta
IMPLICIT NONE
INTEGER :: k
DO k = 1, korkeus
WRITE (*,(24(I3))) taulu(k,1:leveys)
END DO
END SUBROUTINE tulosta
246
Fortran 95/2003
CALL alusta
CALL sijoita(1,1,alku)
CALL tulosta
CONTAINS
Proseduurit alusta, sijoita, umpikuja, arvaa,
suuntia ja tulosta
END PROGRAM sokkelo
Aliohjelmakutsu
CALL sijoita(1,1,alku)
aloittaa sokkelon luomisen kokonaislukutaulukon taulu vasemmasta ylkulmasta. Ohjelman tulostus voisi olla seuraavaa:
Anna sokkelon leveys
10 5
1 4 5 34 33 32 31
2 3 6 19 20 33 34
9 8 7 18 21 26 27
10 13 14 17 22 25 42
11 12 15 16 23 24 43
ja korkeus:
30
29
28
41
40
31
34
35
38
39
32
33
36
37
40
14. Esimerkkiohjelmia
247
Tulostusproseduurissa luodaan sokkelon mrittelev merkkityypin taulukko merkkitaulu kyttmll taulukkonotaatiota. Tulostus tehdn riveittin.
Seuraavassa ohjelman kyttesimerkki:
Anna sokkelon leveys ja korkeus:
10 5
+ +-+-+-+-+-+-+-+-+-+
! !
!
!
+ + + +-+-+ +-+ +-+ +
!
! !
!
! !
!
+-+-+ + + +-+-+ + +-+
!
! ! !
!
!
+ +-+-+ + + +-+-+-+ +
! !
! ! ! !
!
!
+ + + + + + + + + +-+
!
!
!
! !
!
+-+-+-+-+-+-+-+-+-+ +
Tss tulostettiin sama sokkelo, joka esitettiin aiemmin kokonaislukutaulukkona. Ohjelmaa on kytetty mys tulostamaan tmn kirjan kansikuva.
14.4
Yksiulotteinen soluautomaatti
248
Fortran 95/2003
Mrittelimme moduulin sisiseen kyttn tietotyypin ca_rule_type, jonka taulukkoon table voimme sijoittaa soluautomaatin snttaulukon. Soluautomaatin alustamisen voisi tehd seuraavasti:
FUNCTION ca_init(n, k) RESULT(res)
IMPLICIT NONE
14. Esimerkkiohjelmia
249
INTEGER, INTENT(IN) :: n, k
INTEGER, DIMENSION(n) :: res
REAL, DIMENSION(n) :: t
CALL RANDOM_NUMBER(t)
res = k*t
END FUNCTION ca_init
Funktiossa ca_table kytettiin funktiota ca_rule laskemaan soluautomaatin snt taulukkoon rule, joka on tyyppi ca_rule_type. Sisisell funktiolla ca_value puolestaan lasketaan soluautomaattihilan arvo seuraavalla
ajanhetkell. Tmn voisi toteuttaa seuraavasti:
FUNCTION ca_value(config) RESULT(res)
IMPLICIT NONE
INTEGER, DIMENSION(:), INTENT(IN) :: config
INTEGER, DIMENSION(SIZE(config)) :: res
INTEGER :: r, k, n, i
r = rule % r
k = rule % k
n = SIZE(config)
res = 0
DO i = -r, r
res = res + CSHIFT(config,i)
END DO
res = rule % table(res+1)
END FUNCTION ca_value
Funktiossa kytetn isntproseduurista ca_table perisin olevan rulemuuttujan arvoa. Rakenteisen muuttujan komponentteihin viitataan prosenttimerkin avulla: rule%r, rule%k ja rule%table.
Funktiossa ca_value lasketaan rinnakkain soluautomaattihilan uudet arvot. Muuttuja res on taulukko, ja lauseessa res = 0 asetetaan taulukon
kaikki alkiot nolliksi. Kaikkien naapuristojen alkioiden summat lasketaan
250
Fortran 95/2003
listn siten res-taulukon alkioihin config-taulukon alkiot siirrettyin periodisesti i askelta. Lopulliset soluautomaattihilan arvot saadaan indeksoimalla taulukkoa rule%table seuraavaan tapaan:
res(i) = rule % table(res(i)+1)
14. Esimerkkiohjelmia
251
14.4.3 Kyttesimerkki
Kytmme moduulia ca1d soluautomaattien havainnollistukseen:
PROGRAM ca1dtest
USE ca1d, ONLY : ca_init, ca_table
IMPLICIT NONE
INTEGER, DIMENSION(:,:), ALLOCATABLE :: table
INTEGER, DIMENSION(:), ALLOCATABLE :: init
INTEGER :: nr, k, r, t, n, iter, i
WRITE (*,*) Anna nr, k, r:
READ (*,*) nr, k, r
WRITE (*,*) Pituus ja iter. lkm:
READ (*,*) n, iter
ALLOCATE(table(n,0:iter), init(n))
init = ca_init(n, k)
table = ca_table(init, k, r, nr, iter)
DO i = 0, iter
WRITE (*,(35I2))) table(:,i)
END DO
END PROGRAM ca1dtest
lkm:
1 1 0 1 0 1 1 1 0 0 1 0 0 0 1 1
0 0 0 1 0 0 0 0 1 1 1 1 0 1 0 0
1 0 0 1 0 0 1 1 0 0 1 0 0 1 1 1
252
Fortran 95/2003
PGM-tiedoston kaksi ensimmist merkki ovat P2. Tmn jlkeen tulee kuvan dimensiot sek datassa esiintyv maksimiarvo. Tulostusksky voisi nytt seuraavalta:
CALL write_pgm(ca1d.pgm, table)
1
0
1
0
1
0
0
1
1
1
1
1
1
0
0 ...
1 ...
Tss hilan pituus oli 240 ja soluautomaattia iteroitiin 100 kertaa. Tilat on
esitetty riveittin, ylimpn on alkutila.
PGM-formaatin sijaan voi kytt PPM-formaattia (portable pixmap), jossa
voi esitt vrillist dataa.
14. Esimerkkiohjelmia
253
r = rule % r
k = rule % k
n = SIZE(config)
res = SUM( CSHIFT( SPREAD(config, DIM=2, ncopies=2*r+1), &
shift=(/(i, i = -r, r)/), DIM=1), DIM=2)
res = rule % table(res+1)
END FUNCTION ca_value
Tss selvimme taulukkosyntaksilla, yhtn silmukkaa ei tarvita. Ongelmaksi voisi muodostua muistinkytt, sill funktio SPREAD tuottaa taulukon,
jonka koko on n(2r + 1). Toisaalta useimmiten sde r on paljon pienempi
kuin hilan pituus n, joten tm ei ole ongelma. Tmn koodin luettavuus ei
kuitenkaan ole yht hyv kuin aiemman silmukkaversion.
14.4.6 Listietoa
Soluautomaateista kerrotaan mm. teoksissa Theory and Applications of Cellular Automata (Stephen Wolfram, World Scientic, 1986) ja A New Kind of
Science (Stephen Wolfram, Wolfram Media, 2002). CSC on julkaissut teoksen
Workshop on Cellular Automata, Proceedings (toim. Juha Haataja, 1991).
14.5
Life-soluautomaatti
254
Fortran 95/2003
DO iter = 1, toistot/2
CALL piirra(lauta_1,lauta_2)
CALL laske(lauta_1,lauta_2)
CALL piirra(lauta_2,lauta_1)
CALL laske(lauta_2,lauta_1)
END DO
IF (MOD(toistot,2) == 1) THEN
CALL piirra(lauta_1,lauta_2)
CALL laske(lauta_1,lauta_2)
END IF
CALL piirra(lauta_2,lauta_1)
CALL pyyhi
CONTAINS
Aliohjelmat lue_lauta, pyyhi, piirra ja laske
END PROGRAM Life
14. Esimerkkiohjelmia
255
SUBROUTINE pyyhi
WRITE (*,(A)) CHAR(27) // [2J
END SUBROUTINE pyyhi
&
&
&
&
Peliss tapahtuneet muutokset voidaan piirt kytten VT100-ptteen ohjauskoodeja. Aliohjelmassa piirra kytetn kappaleessa 9.13.2 sivulla 144
esitelty muotoiluoperaattoria .fmt., jolloin tulostettavan merkin rivi ja
saraketta kuvaavat luvut saadaan tulostettua tsmlleen oikean kokoisiin
kenttiin. Aliohjelman muodollinen argumentti lauta_1 on Life-pelin uusi
tilanne ja lauta_2 vanha tilanne.
SUBROUTINE piirra(lauta_1,lauta_2)
USE muotoilu ! Kytetn operaattoria ".fmt."
IMPLICIT NONE
CHARACTER(LEN=*), PARAMETER :: escape = CHAR(27) // [
INTEGER, DIMENSION(:,:), POINTER :: lauta_1, lauta_2
INTEGER :: i, j
DO i = 1, SIZE(lauta_1,1)
DO j = 1, SIZE(lauta_1,2)
IF (lauta_1(i,j) /= lauta_2(i,j)) THEN
WRITE (*,(A),ADVANCE=NO) escape
WRITE (*,( // .fmt. i // ,A), &
256
Fortran 95/2003
ADVANCE=NO) i, ;
WRITE (*,( // .fmt. (j-1) // ,A), &
ADVANCE=NO) j-1, H
IF (lauta_1(i,j) /= 0) THEN
WRITE (*,(A),ADVANCE=NO) *
ELSE
WRITE (*,(A),ADVANCE=NO)
END IF
END IF
END DO
END DO
IF (lauta_1(1,1) /= 0) THEN
WRITE (*,(A)) escape // 1;0H*
ELSE
WRITE (*,(A)) escape // 1;0H
END IF
END SUBROUTINE piirra
Tuloksena lasketaan 300 toistokertaa 40 20 -kokoisella laudalla. Seuraavassa on kuuden ensimmisen iteraatioaskeleen tilanteet (vain laudan vasemman ylkulman tilanne on esitetty).
*
**
**
*
***
**
*
**
***
* *
* **
**
14.6
*
* *
*
**
* *
* *
**
**
* *
***
*
**
*** * *
*
* * *
* **
*
***
**
**
* **
* *
**
***
***
*
*
**
****
*
*
* *
*
**
*
*
*
* *
*
Binripuu
14. Esimerkkiohjelmia
257
258
Fortran 95/2003
14. Esimerkkiohjelmia
259
ELSE
mina => mina%oikea
END IF
END DO
ALLOCATE(mina)
mina%avain = avain
mina%tieto = tieto
mina%vasen => loppu
mina%oikea => loppu
IF (avain < isa%avain) THEN
isa%vasen => mina
ELSE
isa%oikea => mina
END IF
END SUBROUTINE syota
SUBROUTINE tulosta_puu()
! Tm on pllystakki tulostusaliohjelmalle
WRITE (*,*) Listaus tiedoista puurakenteen &
&mukaan sisennettyin:
CALL tulosta_sisainen(juuri%oikea, 1)
END SUBROUTINE tulosta_puu
RECURSIVE SUBROUTINE tulosta_sisainen(mina, taso)
! Tm aliohjelma tulostaa rekursiivisesti puun
IMPLICIT NONE
TYPE(puu), POINTER :: mina
INTEGER, INTENT(IN) :: taso
IF (.NOT. ASSOCIATED(mina, loppu)) THEN
CALL tulosta_sisainen(mina%vasen, taso+1)
WRITE (*,*) REPEAT( ,2*taso), mina%avain, mina%tieto
CALL tulosta_sisainen(mina%oikea, taso+1)
END IF
END SUBROUTINE tulosta_sisainen
END MODULE bpuu
Seuraava pohjelma alustaa binripuun, lukee ptteelt avaimia ja tietoalkioita ja lis ne puuhun. Sen jlkeen tulostetaan puu. Viimeinen silmukka kysyy kyttjlt avainkentti ja hakee puusta vastaavan tietokentn. Jos avainta ei lydy puusta, algoritmi palauttaa loppu-solmussa olevan
virheilmoituksen.
PROGRAM puut
USE bpuu
IMPLICIT NONE
CHARACTER(LEN=avain_pituus) :: avain
CHARACTER(LEN=tiedon_pituus) :: tieto
CALL alusta_puu()
tiedon_luku: DO
WRITE (*, (A), ADVANCE = NO) Syt avain &
&(tyhj lopettaa):
READ(*, (A)) avain
260
Fortran 95/2003
018
014
016
013
019
03
017
015
02
06
05
08
09
14. Esimerkkiohjelmia
261
02
03
Turku ja Pori
Hme
05 Kymi
06 Vaasa
08 Oulu
09 Uusimaa I
14.7
Sukupuu
Sukupuun esittmiseen ei edell kytetty binripuu sovi, koska vanhemmilla voi olla nolla, yksi tai useampi jlkelist. Tarvitaan siis uudenlainen listarakenne. Seuraava moduuli toteuttaa sukupuutyypin sek proseduurit sukutiedon lukemiseen ja tulostamiseen. Moduulissa on mritelty tietotyyppi
perhe, joka sislt vanhempien nimet ja syntymajat, lasten lukumrn
sek osoittimet lapsiin.
Lapsien esittmist varten tarvitaan taulukko lapset, jonka alkiot sisltvt osoitinmuuttujan perhe-tietotyyppiin. Ohjelmassa viitataan muuttujan
mina lapseen numero i rakenteella
mina%lapset(i)%p
262
Fortran 95/2003
14. Esimerkkiohjelmia
263
(, TRIM(mina%puol_synt_aika) ,)
END IF
DO i = 1, mina%lapsia
CALL etsi(mina%lapset(i)%p, nimi)
END DO
END SUBROUTINE etsi
END MODULE sukupuu
14.8
Optimointitehtvien ratkaiseminen:
evoluutiostrategiat
Evoluutiostrategiat ovat noin 30 vuotta sitten kehitetty optimointitehtvien ratkaisumenetelm. Dierentiaalievoluutio (DE) on yksinkertainen ver-
264
Fortran 95/2003
Globaalissa optimoinnissa etsitn kohdefunktion f paikallisista minimikohdista arvoltaan pienint, mik on usein erittin vaikeaa. Onneksi usein
riitt likimrisen minimin lytminen.
Dierentiaalievoluutio eli DE soveltuu vaikeiden optimointitehtvien ratkaisumenetelmksi, mutta DE:ss on omat hankaluutensa. Onneksi menetelmss ei kuitenkaan ole yht paljon viriteltvi parametreja kuin esimerkiksi monissa geneettisiss algoritmeissa. DE-menetelm nyttisi mys olevan
melko riippumaton algoritmissa kytetyist parametreista.
14. Esimerkkiohjelmia
265
MODULE de_kind
IMPLICIT NONE
INTEGER, PARAMETER, PUBLIC :: &
prec = SELECTED_REAL_KIND(12,100)
END MODULE de_kind
266
Fortran 95/2003
14. Esimerkkiohjelmia
267
IF (MOD(iter,step) == 0) THEN
WRITE (*,(A,I4,G14.6)) Iteraatio, minimi: , &
iter, MINVAL(cost)
END IF
END DO
END SUBROUTINE optimize
268
Fortran 95/2003
f (x) = 1 + (xi 100)2 /4000
cos(xi 100)/ i.
i
14. Esimerkkiohjelmia
269
ja ajaa seuraavasti:
%
%
%
%
%
f90 -c de_kind.f90
f90 -c de_opt.f90
f90 -c fun.f90
f90 de_test.f90 de_kind.o de_opt.o fun.o
./a.out
14.8.5 Listietoa
DE-menetelm on esitelty lehdess Dr. Dobbs Journal (April 1997, sivut 1824). Optimointimenetelmi on esitelty CSC:n oppaissa Optimointitehtvien
ratkaiseminen [Haa04] ja Numeeriset menetelmt kytnnss [HHL+ 02].
14.9
Liittogradienttimenetelm (conjugate gradient method) on usein tehokas tapa ratkaista lineaarisia yhtlryhmi
Ax = b.
270
Fortran 95/2003
rk , rk
pk , Apk
xk+1 = xk + k pk
rk+1 = rk k Apk
k
rk+1 , rk+1
rk , rk
pk+1 = rk+1 + k pk
k
END DO
= k+1
14. Esimerkkiohjelmia
271
REAL(prec) :: rnorm
! Residuaalin normin neli
REAL(prec) :: rnnorm
! Uuden residuaalin normin neli
REAL(prec) :: rnorm0
! Alkuresiduaalin normin neli
INTEGER :: k
! Iteraatiokierros
CALL matr_mult(n, x,res) ! Laske alkuresiduaali b-Ax
res = b - res
p = res
! Etsintsuunta on alkuresiduaali
k = 1
rnorm = DOT_PRODUCT(res,res)
rnorm0 = rnorm
! Alkuresiduaalin normin neli
DO WHILE(k < itmax .AND. SQRT(rnorm)/SQRT(rnorm0) > eps)
CALL matr_mult(n, p, ap)
alpha = rnorm / DOT_PRODUCT(p,ap)
x = x + alpha * p
! Pivit iteraattia
res = res - alpha * ap ! Pivit residuaalia
rnnorm = DOT_PRODUCT(res,res)
beta = rnnorm / rnorm
p = res + beta * p
! Pivit etsintsuuntaa
rnorm = rnnorm
WRITE(*,*) k, SQRT(rnorm)
k = k + 1
END DO
WRITE (*, (/,A,I3,A,/)) CG suppeni , &
k-1, iteraatiossa
END SUBROUTINE cg
END MODULE cg_alg
Liittogradienttialgoritmissa tarvitaan matriisi-vektoritulon laskeva aliohjelma. Vlitmme aliohjelmaan cg tmn aliohjelman muodollisessa argumentissa matr_mult.
Seuraavassa moduulissa mrittelemme matriisitulon laskevan aliohjelman
cg_matrix_mult. Moduulissa on lisksi aliohjelma cg_matrix_init matriisin alustamiseen. Matriisi talletetaan moduulin yksityiseen muuttujaan
coeffmat.
MODULE cg_matrix
USE cg_precision, ONLY : prec
IMPLICIT NONE
REAL(prec), DIMENSION(:,:), ALLOCATABLE, PRIVATE :: &
coeffmat
CONTAINS
SUBROUTINE cg_matrix_init(n)
! Aliohjelma alustaa kerroinmatriisin
INTEGER, INTENT(IN) :: n
INTEGER :: allocstat, i, j
ALLOCATE(coeffmat(n, n), STAT=allocstat)
IF (allocstat /= 0) STOP muistinvaraus eponistui!
DO j=1, n
DO i=1, n
coeffmat(i,j) = 1/(1.0_prec+ABS(i-j))
END DO
END DO
END SUBROUTINE cg_matrix_init
272
Fortran 95/2003
SUBROUTINE cg_matrix_mult(n, x, y)
! Aliohjelma laskee matriisi-vektoritulon y=A*x
INTEGER, INTENT(IN) :: n
REAL(prec), INTENT(IN) :: x(n)
REAL(prec), INTENT(OUT) :: y(n)
y = MATMUL(coeffmat, x)
END SUBROUTINE cg_matrix_mult
END MODULE cg_matrix
Olemme sijoittaneet matriisitulon laskevan aliohjelman erilliseen moduuliin, jolloin ohjelman muuttaminen myhemmin on helpompaa. Tarvittaessa voisimme muuttaa tt moduulia vaikkapa tallettaen matriisin nauhamatriisina tai harvana matriisina. Mys rinnakkaistetun version tekeminen on
helpompaa [HM01].
Moduulien cg_alg ja cg_matrix avulla voimmekin nyt toteuttaa liittogradienttimenetelmn. Tarvittava pohjelma on esitetty seuraavassa:
PROGRAM cg_iterate
! Ohjelma ratkaisee tihen lineaarisen yhtlryhmn Ax=b
! liittogradienttialgoritmilla
USE cg_precision, ONLY : prec
USE cg_matrix, ONLY : cg_matrix_init, cg_matrix_mult
USE cg_alg, ONLY : cg
IMPLICIT NONE
INTEGER :: n
REAL(prec), DIMENSION(:), ALLOCATABLE :: rhs, x
INTEGER :: allocstat, u, t1, t2
WRITE (*,(A), ADVANCE=no) Anna matriisin koko n:
READ (*,*) n
CALL SYSTEM_CLOCK(count_rate=u)
CALL SYSTEM_CLOCK(count=t1)
ALLOCATE (rhs(n), x(n), STAT=allocstat)
IF (allocstat /= 0) STOP Muistinvaraus eponistui!
CALL cg_matrix_init(n)
rhs = 1
x = 0
CALL cg(n, rhs, x, 100, 1e-5_prec, cg_matrix_mult)
CALL SYSTEM_CLOCK(count=t2)
WRITE (*,(A,I4,A,F6.2)) Koko: , n, &
Aika: , REAL(t2-t1)/u
END PROGRAM cg_iterate
14. Esimerkkiohjelmia
273
16 iteraatiossa
500 Aika:
0.23
Siis 500 500 -kokoisen yhtlryhmn ratkaisuun kului aikaa noin 0.2 sekuntia.
14.9.1 Listietoja
Lineaaristen yhtlryhmien ratkaisusta kerrotaan CSC:n oppaassa Numeeriset menetelmt kytnnss [HHL+ 02]. Rinnakkaistettu versio liittogradienttialgoritmista lytyy CSC:n julkaisemasta MPI-oppaasta [HM01].
Harjoitustehtvi
1. Muuta kappaleen 14.1 (sivu 234) pinomoduulia siten, ettei pinolla ole
kiinte maksimikokoa.
2. Lis nelilaskimeen potenssiinkorotusoperaatio ^. Voit kytt komentona mys Fortranin potenssiinkorotusoperaattoria **, mutta tllin
joudut ksittelemn mys kahdesta merkist koostuvia komentoja.
3. Jos lajiteltavana on suuri mr dataa, kannattaa kytt esimerkiksi
Quicksort-algoritmia (katso vaikkapa teoksia [CLR90, Sed84]). Toteuta
kappaleen 14.2.1 lajittelumoduuli kytten Quicksortia.
4. Muuta kappaleen 14.3 sokkelonteko-ohjelman tulostusproseduuria siten, ett tulostuksessa ei kytet taulukko-operaatioita vaan sokkelo
tulostetaan suoraan kytten WRITE-lausetta.
5. Muuta sokkelonteko-ohjelman tulostusproseduuria siten, ett se tulostaa mys sokkelon ratkaisun. Vihje: aloita polun loppupst.
6. Kirjoita ohjelma, joka ratkaisee valmiin sokkelon. Sokkelon voi sytt
ohjelmalle esimerkiksi merkkijonotaulukkona.
7. Tutki kappaleessa 14.4 esiteltyj yksiulotteisia soluautomaatteja. Miten
kyttytyy totalistinen soluautomaatti (k = 2, r = 1), sntnumero
10? Ent (k = 5, r = 1)-soluautomaatti, snt 80092580? (Voit tulostaa
soluautomaatin vreiss kyttmll esim. PPM-tiedostomuotoa.)
274
Fortran 95/2003
x1
x13 x25 )
5
1
exp((x1 + 1)2 x22 ) + 10.
3
Muuta tehtv minimointitehtvksi ja kyt kappaleessa 14.8 esitelty DE-menetelm. Funktiolla on kolme lokaalia maksimia lytk
menetelm aina globaalin maksimin?
12. Tutki kappaleessa 14.9 esitellyn liittogradienttimenetelmn suppenemisnopeutta. Miten menetelmn tehokkuus riippuu alkuarvauksen hyvyydest?
13. Pohjustus (preconditioning) nopeuttaa liittogradienttimenetelmn suppenemista. Toteuta kappaleen 14.9 liittogradialgoritmiin jokin sopiva
pohjustusmenetelm [HHL+ 02].
15
275
Siirtyminen Fortran 95
-kieleen
15.1
276
15.2
Fortran 95/2003
Kymme aluksi lpi Fortran 95:n suurimmat muutokset aikaisempaan FORTRAN 77 -standardiin verrattuna.
Lhdekoodin vapaa syttmuoto tarjoaa luontevan tavan kirjoittaa ohjelmakoodia. Samalla vltyt turhilta sarakesidonnaisuuteen liittyvilt virheilt.
Fortran 95 tarjoaa moduulien ja sisisten proseduurien kyttmahdollisuuden, jolloin proseduurien argumentit voidaan tarkistaa knnsaikana. Lisksi voit kirjoittaa rekursiivisia proseduureja.
Fortran 95:n lajiparametrit mahdollistavat muuttujien lukualueen ja tarkkuuden mrittelyn laitteistosta riippumattomalla tavalla. Tllin koodin
siirrettvyys paranee.
Fortran 95:ss on mahdollisuus mritell omia muuttujatyyppej ja yleist
standardiproseduurit ja -operaattorit kohdistumaan uuden tyyppisiin muuttujiin. Lisksi voit mritell omia operaattoreita. Geneeristen proseduurien
avulla voit ksitell saman nkisell proseduurin kutsulla eri tyyppisi argumentteja.
Taulukkosyntaksi ja osoitinmuuttujat mahdollistavat tehokkaamman ja joustavamman tavan ksitell suuria tietomri. Dynaamisen muistinksittelyn
ansiosta proseduureille ei en tarvitse vlitt argumentteina tytiloja.
SELECT CASE -ohjausrakenne sek DO-toistorakenteen yleisemmt muodot
helpottavat ohjelmakoodin logiikan ilmaisemista.
Sytt- ja tulostusproseduurien ominaisuuksia on laajennettu. Esimerkiksi
tiedonsiirto NAMELIST-ryhmien avulla kuuluu nyt standardiin.
Fortran 95 sislt paljon uusia standardifunktioita ja -aliohjelmia (yhteens
standardiproseduureja on 115). Useimmat nist standardiproseduureista
ovat geneerisi eli niit voi kytt ksittelemn eri tyyppisi argumentteja.
Tmn lisksi Fortran 95 -kntj tarjoaa aikaisempaa tarkemmat ilmoitukset virheelliselle tai epstandardille lhdekoodille. Kntjn on mm. ilmoitettava vanhentuvien Fortranin piirteiden kytst.
15.3
277
Urbaani legenda kertoo, ett ers avaruusluotain menetettiin tllaisen Fortran-koodissa olleen kirjoitusvirheen vuoksi.
Onneksi nykyisess Fortran-standardissa vlilynnit ovat merkitsevi. Lisksi lause IMPLICIT NONE suojaa mahdollisilta muuttujien nimien kirjoitusvirheilt. Seuraavassa esimerkki:
INTEGER ARV0, ARV1
ARVO = 12
ARV1 = FUN(ARVO)
278
Fortran 95/2003
Huomasitko, ett koodissa oli kirjoitusvirhe? Muuttujan nimen piti olla ARV0
eik ARVO (tai pienill kirjaimilla: arv0 eik arvo). Jos tss tapauksessa olisi
kytss Fortranin tunnusten etumerkkisnt, vlitettisiin funktioon FUN
kokonaislukumuuttujan arv0 sijaan alustamaton reaalilukumuuttuja arvo.
Tuloksena on arvaamattomasti kyttytyv ohjelma.
279
COMMON-alueiden sijasta. EQUIVALENCE-lauseet voi korvata osoitinmuuttujilla tai vaikkapa standardifunktiolla TRANSFER.
Seuraava FORTRAN 77 -koodi saattaa knty ilman varoituksia:
PROGRAM HUH
REAL LUKU, A, B
COMMON /HUPS/ LUKU, A, B
CALL NURJA
WRITE (*,*) LUKU,A,B: , LUKU, A, B
END
SUBROUTINE NURJA
COMMON /HUPS/ LUKU, A, B
LUKU = 3
A = 4
B = 5
END
0.0000000E+00
4.000000
5.000000
Vaikka muuttujalle LUKU annettiin arvoksi luku 3, tulosti ohjelma arvon nolla. Tm johtuu siit, ett aliohjelmassa NURJA kytettiin alkukirjainsnt,
ja muuttuja LUKU oletettiin kokonaislukutyyppiseksi! Tllin pohjelmassa
kytettyyn COMMON-alueeseen tallettui tmn kokonaislukumuuttujan arvo.
15.4
ACTSCA
280
Fortran 95/2003
GRA(10,20),NGRA(20),LSCA
C
IF(LSCA.EQ.0)LSCA = 1
C
RETURN
END
ACTSCA
Tss muutimme kommenttimerkiksi huutomerkin !. Lisksi kytimme Fortran 95:n tapaa ilmaista jatkorivi merkill &. Koodi on nyt vapaan lhdekoodin
muotoista.
Seuraava versio voisi nytt tlt:
SUBROUTINE actsca
! actsca activates the rescaling
USE scale_mod, ONLY : lsca
IMPLICIT NONE
IF (lsca == 0) lsca = 1
END SUBROUTINE actsca
Tss siirsimme COMMON-alueen SCALE tiedot moduuliin scale_mod. Aliohjelmassa otimme tst moduulista kyttn vain tunnuksen lsca. Aliohjelma yksinkertaistui huomattavasti.
l kyt Fortranin implisiittist tyypinmrittely eli alkukirjainsnt.
Kyt sen sijaan lausetta IMPLICIT NONE ohjelmayksikkjen alussa. Tllin
mahdolliset tunnusten kirjoitusvirheet tulevat useimmiten esiin jo knnsaikana.
Selkeyt ja yhtenist muuttujamrittelyt. l kyt erillisi DIMENSION- ja
PARAMETER-lauseita, vaan vastaavia tyyppimreit. Siis mrittelyt
INTEGER N
PARAMETER (N = 100)
REAL X
DIMENSION X(N)
281
DO 100 I = 1, N
PRINT (F10.6), X(I)
15.5
Ohjausrakenteiden kytt
FORTRAN 77:ss ei ollut kytettviss END DO -lausetta silmukan lopettamiseen, mik johti seuraavan kaltaisiin vaikeasti luettaviin silmukoihin:
DOUBLE PRECISION A, X
282
Fortran 95/2003
100
DO 100 I=2,N
X(I)=1D30
DO 100 II=1,N
A(II,I)=0D0
100
200
500
Tmn esimerkin voi kirjoittaa selkemmin SELECT CASE -rakennetta kytten seuraavasti:
INTEGER :: i, m, a, b
SELECT CASE (i)
CASE (1)
m = m + b
CASE (3)
m = m - b
CASE DEFAULT
m = m + a
END SELECT
283
INTEGER :: i, m, a, b
IF (i == 1) THEN
m = m + b
ELSE IF (i == 3) THEN
m = m - b
ELSE
m = m + a
END IF
10
11
15.6
284
Fortran 95/2003
MODULE globaalit_muuttujat
IMPLICIT NONE
INTEGER, SAVE :: n, ntot, nc
REAL, SAVE :: abstol, reltol
END MODULE globaalit_muuttujat
Muuttujien mre SAVE on tarpeen, jos moduulin arvojen halutaan silyvn mys proseduurikutsujen vlill! Jos SAVE-mrett ei kytet, silyvt
moduulissa mriteltyjen muuttujien arvot ohjelman suorituksen ajan ainoastaan silloin, kun moduuli otetaan kyttn mys pohjelmassa.
Moduulia voi kytt vaikkapa seuraavasti:
USE globaalit_muuttujat
USE globaalit_muuttujat, ONLY : n, ntot
Ensimminen USE-lause otti kyttn kaikki moduulin oliot. Toisessa lauseessa otettiin kyttn vain muuttujat n ja ntot.
Edell sijoitettiin kaikki globaalit muuttujat samaan moduuliin. Tmn sijasta voi tietysti kytt erillisi moduuleja, joiden kytt vastaa alkuperisten
COMMON-alueiden kytt.
15.7
285
lausefunktiot
suoritettavien lauseiden joukossa olevat DATA-lauseet
oletetun mittaiset merkkijonot (assumed length)
sarakesidonnainen lhdekoodin muoto
CHARACTER*-tyyliset merkkijonojen mrittelyt.
Seuraavassa kuvataan lyhyesti joitakin standardin vanhentuvista ja poistetuista piirteist. Niden kytt tulee vltt.
100
Fortran 90 -standardissa tytyy hyppylauseen osoitteena olla END IF -lausetta seuraava lause (esimerkiksi CONTINUE-lause).
Hyppylauseet kannattaa useimmiten korvata kehittyneemmill ohjausrakenteilla.
voidaan suorittaa 10 tai 11 kertaa riippuen reaalilukujen esitystavasta. Reaalilukutyyppisten silmukkamuuttujien sijaan on syyt kytt kokonaislukutyyppisi lausekkeita, koska tllin toistokertojen mr on sama riippumatta liukulukuaritmetiikan tarkkuudesta.
286
Fortran 95/2003
100
DO 100 I=2,N
X(I)=1D30
DO 100 II=1,N
A(II,I)=0D0
Tmn sijaan kannattaa kytt END DO -lausetta silmukkojen lopettamiseen. Tt on havainnollistettu kappaleessa 15.5 (sivu 281).
Mys silmukan pttminen muuhun kuin END DO tai CONTINUE-lauseeseen
on mritelty vanhentuvaksi piirteeksi.
100
200
PROGRAM kutsu
...
CALL ali(i, j, *100, *200)
...
CONTINUE
...
CONTINUE
...
END
SUBROUTINE ali(i, j, *, *)
...
RETURN 1
...
RETURN 2
...
END
287
15.7.7 PAUSE-lause
PAUSE-lause keskeytt ohjelman suorituksen, kunnes nppint painamalla
annetaan lupa jatkaa suoritusta. Tmn sijaan kannattaa tulostaa kehote
WRITE- tai PRINT-lauseella ja lukea ptteelt syte READ-lauseella merkiksi
siit, ett ohjelman suoritusta saa jatkaa:
CHARACTER(LEN=80) :: rivi
DO
WRITE (*,*) Jatketaanko suoritusta (K,k)?
READ (*,(A)) rivi
rivi = ADJUSTL(rivi)
IF (rivi(1:1) == K .OR. rivi(1:1) == k) EXIT
END DO
15.7.8 Hollerith-merkkijonovakiot
Hollerith-merkkijonovakioita kytettiin osana FORMAT-lauseden muotoilukoodia. Tmn sijaan voi kytt lainausmerkkeihin sijoitettua merkkijonovakiota.
Seuraavassa on esimerkki vanhentuvasta mrittelyst:
100
PRINT 100, X
FORMAT (5HArvo:,F10.6)
15.8
288
Fortran 95/2003
100
PROGRAM HULLU
INTEGER N
PARAMETER (N = 10)
REAL A(N,N+1)
CALL ALUSTA(A,N,N+1)
WRITE (*,*) A(1,1), A(2,3)
END
SUBROUTINE ALUSTA(V,N,M)
INTEGER N, M
REAL V(N*M)
INTEGER I
DO 100 I = 1, N*M
V(I) = I
CONTINUE
END
289
22.00000
Harjoitustehtvi
1. Muunna seuraava sarakesidonnaista FORTRAN 77 -syttmuotoa kyttv ohjelma vapaaseen syttmuotoon. Kyt ohjelman alussa lausetta IMPLICIT NONE ja silmukoissa ohjausrakennetta DO ... END DO. Sisenn ohjelmakoodi selkesti.
PROGRAM SILMUKAT
REAL X(100,100), Y(100), Z(100), A, S
INTEGER I, J, K
3
2
5
DO 1 J = 1, 100
Y(J) = 0.1*J
DO 1 I = 1, 100
X(I,J) = 1.0 + Y(J)
CONTINUE
DO 2 J = 1, 100
S = 0.0
DO 3 I = 1, 100
S = S + X(I,J)
CONTINUE
Z(J) = SQRT(Y(J))/S
CONTINUE
DO 5 J = 1, 100
IF (Z(J) .LT. 0.001) Z(J) = 0.0
A = Z(1)
K = 1
290
Fortran 95/2003
DO 6 I = 2, 100
IF (Z(I) .GT. A) THEN
K = I
A = Z(I)
ENDIF
CONTINUE
WRITE (*,*) A, K
END
2. Muunna edellisen tehtvn ohjelmakoodi taulukkosyntaksiksi jos mahdollista. Kyt Fortran 90 -kielen sisnrakennettuja funktioita SUM,
MAXVAL ja MAXLOC.
3. Esit seuraava haarautuvaa hyppylausetta kyttv ohjelmakoodi IFrakennetta kytten:
INTEGER EHTO
REAL X, Y, Z
10
11
16
291
Fortran 2003
Nykyinen Fortran-standardi on nimeltn Fortran 2003. Standardi on huomattava laajennus verrattuna aiempiin standardeihin. Esitmme tiiviin katsauksen standardin uusiin piirteisiin.
Uusien piirteiden mrst johtuen standardia tysin noudattavia kntji
ei tt kirjoittaessa (vuoden 2007 kevll) ole saatavilla. Sosittelemme, ett Fortran-ohjelmoinnissa kytetn Fortran 95 -standardin piirteit, jotka
sisltyvt Fortran 2003:een.
Seuraava standardi, tynimeltn Fortran 2008, on jo valmisteilla. Tm
standardi tuo lis uusia piirteit Fortran-kieleen. Nit uusia ominaisuuksia
ymmrtvi kntji saamme odottaa luultavasti useita vuosia.
16.1
292
Fortran 95/2003
293
294
Fortran 95/2003
Geneeriseksi mritellyn proseduurin x%g tytyy kutsuttaessa olla yksiksitteinen argumenttiensa suhteen.
16.1.8 PASS-mre
Kun rakenteisen tyypin alkioon liittyv proseduuria kutsutaan, tarvitsee se
usein psyn kyseisen olion sisltn. Oletuksena olio vlitetn ensimmisen argumenttina:
CALL x%pros1(x,y)
295
16.2
Fortran 2003:n suurimpana ksitteellisen uudistuksena on tuki olio-ohjelmoinnin periaatteiden toteuttamiseksi Fortran-kielell. Kuitenkaan Fortran 2003 -kielt ei voi pit varsinaisesti olio-ohjelmointikielen vaan pikemminkin jonkinlaisena semi-oliokielen.
Olio-ohjelmoinnin paradigma perustuu ksiteanalyysiin, jossa kuvataan sovelluskohteen loogiset yksikt sek niden vliset suhteet perustuen kohdemaailman tietomalliin. Tm paradigma eroaa perinteisemmst proseduraalisesta lhestymistavasta eli niin sanotusta osittavasta ohjemistosuunnittelusta (top down), jossa modularisoinnin periaatteita noudattamalla tarkennetaan toimintoja aliohjelmien ja perusrakenteiden kautta aina yksittisten
kskyjen tasolle asti. Kiinnostunut lukija lyt mainion johdatuksen olioajatteluun esimerkiksi Koskimiehen teoksesta [Kos97].
Osittavan ohjelmistosuunnittelun merkittvin etu suhteessa kohdemaailman tietomalliin perustuvaan lhestymistapaan on se, ett ohjelmiston kehittminen etenee ainakin pieniss sovelluksissa nopeammin. Toisaalta osittavan ohjelmistosuunnittelun merkittvin heikkous on se, ett ohjelmiston
korkean tason muutokset heijastuvat suureen osaan ohjelmistoa eli ohjelmiston rakenne on epjatkuva.
Valistuneen oliomallintamisen ern suurimpana etuna nhdnkin se, ett ohjelmiston muutostarpeet kohdentuvat paikallisiin komponentteihin ja
niiden toteutukseen. Tllin paikalliset muutokset eivt propagoidu ympri ohjelmistoa eli ohjelmiston rakenne on jatkuva, mik helpottaa ohjelmiston yllpitoa. Lisksi valistunut olio-ohjelmointi mahdollistaa ohjelmakoodin useissa sovelluskohteissa esiintyvien korkean tason komponenttien
jlleenkytn (reusability). Usein esiintyvist abstrakteista komponenteista
kytetn nimityst suunnittelumalli (design pattern [GHJV95]).
Kurinalaisella ohjelmoinnilla oliomallintamisen oppeja voidaan soveltaa
mys proseduraalisilla kielill ohjelmoitaessa. Tosin tllin ohjelmointi on
teknisesti tylmp kuin puhtaammilla oliokielill, sill oliokielet mahdollistavat teknisesti helpommin perintmekanismin toteuttamisen, abstraktien tietotyyppien (luokkien) kuvaamisen ja niden ilmentymien (olioiden)
kytn osana dynaamista ymprist. Lisksi klassisen tietoabstraktion perusperiaatteen erota toteutus ja tietorakenteen operaatiot toisistaan noudattaminen on yleens jouhevinta oliokielill.
Fortran 95 -kieless luokka vastaa lhinn moduulin eli siihen kuuluvien
toimintojen ja tietorakenteiden ksitett (abstrakti tietotyyppi). Periytymismekanismia ei tueta suoraan kielen korkealla tasolla. Fortran 2003:ssa rakenteisille tyypeille voi mritell perinthierarkian.
296
Fortran 95/2003
16.3
Niden mrittelyjen ansiosta voimme luoda kaksi- ja kolmiulotteisia vektoreita vastaavat muuttujat v2d ja v3d:
TYPE(vector_2d) :: v2d
TYPE(vector_3d) :: v3d
297
16.3.2 Monimuotoisuus
Fortran 2003 -kielen muuttujat voivat olla monimuotoisia (polymorsia).
Monimuotoisuudella tarkoitetaan, ett muuttuja voi viitata annettua rakenteista tyyppi vastaavaan ilmentymn (eli olioon) sek tmn ilmentymn
tyypin laajennettujen tyyppien ilmentymiin. Tllin alkioiden valinta liittyy
dynaamisesti ilmentymn tyyppiin, eik muuttujan tyyppiin. Seuraava esimerkki selvent monimuotoisuuden ideaa:
CLASS(vector_2d), POINTER :: p2
CLASS(vector_3d), POINTER :: p3
TYPE(vector_2d), TARGET :: t2
TYPE(vector_3d), TARGET :: t3
=>
=>
=>
=>
t2
t3
t3
p3
298
Fortran 95/2003
END TYPE
TYPE, EXTENDS(piste) :: rgb_piste
INTEGER :: r, g, b
END TYPE
TYPE(piste), TARGET :: p
TYPE(piste3d), TARGET :: p3d
TYPE(rgb_piste), TARGET :: pc
CLASS(piste), POINTER :: p_olio
p_olio => pc
SELECT TYPE (t => p_olio)
TYPE IS (piste3d)
PRINT *, t%x, t%y, t%z
CLASS IS (piste)
PRINT *, t%x, t%y
END SELECT
16.4
Listietoa
Fortran 2003 -kielen ksikirjana voi kytt teosta Fortran 95/2003 Explained [MRC04]. Artikkelissa The New Features of Fortran 2003 [Rei] kuvataan
tiiviiss muodossa Fortran 2003:n uudet piirteet. Johdatukseksi kieleen sek
oppikirjaksi sopii teos Introduction to Programming with Fortran [CS06].
17
17.1
299
Rinnakkaislaskenta
HPF:ll ja OpenMP:ll
Vlineit rinnakkaislaskentaan
HPF (High Performance Fortran) on Fortran 95:een perustuva datarinnakkainen ohjelmointikieli. Datarinnakkaisessa ohjelmoinnissa suoritetaan samoja operaatioita tietorakenteen (tyypillisesti taulukon) eri alkioille. Siten HPF
ei ole rinnakkaislaskennan yleistykalu, mutta se sopii erityisesti tehtviin,
joissa suoritetaan snnllisi taulukko-operaatioita. HPF soveltuu hienosyiseen (silmukkatason) rinnakkaistamiseen, mutta tllin rinnakkaiskoneessa
tytyy olla nopea viestinvlitys prosessorien vlill.
Kappaleessa 17.3 sivulla 305 kerrotaan rinnakkaistamisesta OpenMP:n avulla. Tm standardi soveltuu vain yhteisen muistin koneille, mutta on usein
HPF: tehokkaampi ja monipuolisempi rinnakkaistusvline.
Rinnakkaistamisen voi tehd mys viestinvlityst kytten. Esimerkiksi MPI
(Message-Passing Interface) mahdollistaa rinnakkaisohjelmoinnin viestinvlityst kytten [HM01]. Mys vanhempaa PVM-jrjestelm voi kytt rinnakkaisohjelmointiin [Saa95].
17.2
HPF-ohjelmoinnin perusteet
HPF-ohjelmointi poikkeaa Fortran 95:st pasiallisesti vain datan jakamista ja taulukko-operaatioiden rinnakkaistusta ohjaavien kntjdirektiivien
osalta.
Ohjelmoija jakaa taulukot prosessoreille kntjdirektiivien avulla, ja kntj huolehtii kaikesta tarvittavasta viestinvlityksest. Koska direktiivit ovat
syntaksiltaan Fortran 95 -kommentteja, ohjelma voidaan periaatteessa knt mys Fortran 95 -kntjll, jolloin tuloksena on HPF-rinnakkaisversion
kanssa samoja tuloksia tuottava tavallinen perkkisohjelma.
Kntjdirektiivit ovat esimerkiksi muotoa
!HPF$ direktiivi
300
Fortran 95/2003
Lause USE HPF_LIBRARY ohjelman alussa mahdollistaa HPF-kirjaston aliohjelmien kytn. Monipuolisten bitinksittely- ja taulukkorutiinien lisksi kirjastossa on funktioita, joilla saa tietoa prosessorihilasta ja taulukoiden jaosta.
Seuraavassa on esimerkki yksinkertaisesta HPF-ohjelmasta:
PROGRAM piste
IMPLICIT NONE
INTEGER :: n
REAL, DIMENSION(:), ALLOCATABLE :: a, b
REAL :: d
!hpf$ distribute a(block)
!hpf$ align b(:) with a(:)
WRITE (*,*) Input the number of points:
READ (*,*) n
ALLOCATE (a(n), b(n))
a = 1.0
b = 2.0
d = SUM(a*b)
WRITE (*,*) d
END PROGRAM piste
Lause
!HPF$ ALIGN B WITH A
puolestaan mr, ett vektoreiden B ja A vastinalkiot tallennetaan samoihin prosessoreihin. Huomaa, ett Fortranin standardifunktio SUM on HPF:ss
rinnakkaistettu.
301
302
Fortran 95/2003
303
antaa taulukon ensimmisen rivin ensimmiselle prosessorille, toisen toiselle ja niin edelleen. Jos ohjelmaa ajettaisiin neljll prosessorilla, rivi viisi
olisi taas ensimmisell prosessorilla.
Direktiivin DISTRIBUTE lisksi taulukoiden jakamiseen voi kytt direktiivi ALIGN, jolla taulukko voidaan jakaa jo jaetun taulukon avulla. Esimerkkiohjelmassa globaalit taulukot b ja f on hajautettu samoin kuin a. Formaatilla * on sama merkitys kuin DISTRIBUTE-direktiivin yhteydess. Niinp
esimerkiksi direktiivi
!HPF$ ALIGN b(:,*) WITH a(*,:)
liitt taulukon b rivit taulukon a sarakkeisiin. Taulukon b alkioiden lopullinen jakautuminen prosessorien kesken riippuu taulukon a hajautuksesta.
Direktiiveill DISTRIBUTE ja ALIGN voi toteuttaa erittin monipuolisia datan
jakoja [KLS+ 94]. Jakoa ja kohdistusta voi mys muuttaa ohjelman suorituksen aikana direktiiveill REDISTRIBUTE ja REALIGN. Tm ei kuitenkaan ole
suositeltavaa ohjelman suorituskyvyn kannalta.
304
Fortran 95/2003
17.2.4 Datarinnakkaisuus
HPF:n datarinnakkaisuus toteutuu seuraavilla tavoilla:
Fortran 95:n taulukko-operaatiot ja -sijoitukset (WHERE-rakenne mukaan
lukien). Esimerkkiohjelmassa taulukkojen alustaminen nollalla initaliohjelmassa tapahtuu rinnakkain.
Fortran 95:n taulukkofunktiot. Esimerkiksi funktiossa diff taulukon
alkioiden summa lasketaan rinnakkaisesti SUM-funktiolla.
HPF-kirjaston taulukkofunktiot. Moduuli HPF_LIBRARY sislt monia
funktioita mm. taulukoiden reduktioon ja lajittelemiseen.
FORALL-lause. Vaikka FORALL-lause muistuttaa silmukkaa, oikeampi tulkinta on pit sit yleistettyn rinnakkaisena taulukkosijoituksena. Sijoituslauseen oikean puolen arvot lasketaan ensin kaikilla indeksien arvoilla, ja sijoitus tapahtuu vasta tmn jlkeen. Sek evaluointi ett sijoitus tehdn rinnakkain. Esimerkin aliohjelmissa diff ja sweep taulukkosijoitukset on toteutettu FORALL-lauseilla.
INDEPENDENT-direktiivi DO- ja FORALL-lauseiden yhteydess. DO-silmukoiden rinnakkaistamiseen kytetn INDEPENDENT-direktiivi, jolla ohjelmoija kertoo kntjlle, ett silmukan eri kierroksilla suoritettavat
operaatiot ovat toisistaan riippumattomia. Koska tm on rinnakkaistamisen edellytys, kaikkia DO-silmukoita ei voi rinnakkaistaa. Tyypillinen
rinnakkaistumaton silmukka on
DO i = 1,n
a(i) = a(i-1)
END DO
305
17.2.5 EXTRINSIC-aliohjelmat
EXTRINSIC-aliohjelmien avulla HPF:n voidaan liitt muilla ohjelmointikielill ja rinnakkaisohjelmointimalleilla toteutettuja osia. Kytettviss olevat liittymt riippuvat HPF-toteutuksesta.
EXTRINSIC-aliohjelman kutsussa prosessorit saavat omat osansa taulukoista, ja ohjelmoijan on itse huolehdittava tarvittavasta viestinvlityksest prosessorien kesken.
17.3
OpenMP on rinnakkaislaskennan uusi ohjelmointimalli yhteisen muistin tietokoneille. OpenMP mrittelee joukon direktiivej, kirjastorutiineja ja ympristmuuttujia, joita voidaan kytt Fortran- ja C/C++-ohjelmien rinnakkaistamiseen.
Yhteisen muistin koneissa jokainen prosessori nkee koko muistiavaruuden. Rinnakkaisohjelmoinnin standardi, joka hydyntisi yhteisen muistin
306
Fortran 95/2003
17.3.1 Kntjdirektiivit
OpenMP-ohjelmointi perustuu ensisijaisesti kntjdirektiivien kyttn.
Lhdekoodissa merkitn rinnakkaisesti suoritettavat osat ja annetaan rinnakkaistamiseen liittyvi ohjeita. Rinnakkainen osa voi olla silmukkarakenne, jonka suoritus jaetaan eri prosessoreiden kesken, tai joukko erillisi ohjelmalohkoja. OpenMP:ll on siis suhteellisen helppo tehd rinnakkaistettu
versio vanhasta perkkiskoodista.
OpenMP-direktiivit kirjoitetaan kommenttirivein. Rinnakkaistettavat alueet
merkitn direktiiveill
!$OMP PARALLEL mreet
ohjelmalohko
!$OMP END PARALLEL
Ellei toisin mritell, alueen lopussa sikeet jvt odottamaan muita sikeit. Rinnakkaistettavien alueiden ulkopuolella vain yksi sie jatkaa ohjelman suoritusta. Perusmreit rinnakkaistettaville alueille ovat mm. PRIVATE
ja SHARED, joilla annetaan lista yksityisist ja yhteisist muuttujista, sek
REDUCTION, jolla mritelln reduktio-operaatio ja -muuttuja.
Tynjakoa stelevist rakenteista trkein on
!$OMP DO mreet
DO-silmukka
!$OMP END DO
Tll mritelln rinnakkaistettava silmukka. Lisksi erillisi ohjelmalohkoja voidaan luetella !$OMP SECTIONS -rakenteella.
307
17.3.2 OpenMP-esimerkki
Kytmme esimerkkin kappaleessa 3.16 (sivu 38) esitelty simulointitehtv, jossa yksikknelin sijoitetaan pistepareja ja lasketaan niiden etisyyden keskiarvo.
Alkuperiseen perkkiskoodiin ei tehd muita muutoksia kuin kommentteina nkyvt !$OMP-direktiivit. Edell esitetyt !$OMP PARALLEL ja !$OMP
DO -direktiivit on yhdistetty !$OMP PARALLEL DO -direktiiviksi OpenMP:n
yksittiselle silmukalle salliman syntaksin mukaisesti. Lisksi kytmme direktiivin jatkorivimerkint.
PROGRAM points
IMPLICIT NONE
INTEGER, PARAMETER :: n = 1000000
INTEGER, PARAMETER :: &
prec = SELECTED_REAL_KIND(12,100)
REAL(KIND=prec), DIMENSION(2) :: a, b
REAL(KIND=prec) :: d, s = 0.0_prec
INTEGER :: i
WRITE (*,*) Number of pairs:, n
!$OMP PARALLEL DO PRIVATE(a,b,i) &
!$OMP REDUCTION(+:s)
DO i = 1, n
CALL RANDOM_NUMBER(a)
CALL RANDOM_NUMBER(b)
s = s + SQRT(SUM((a - b)**2))
END DO
!$OMP END PARALLEL DO
d = s/n
WRITE (*,*) Mean distance:, d
END PROGRAM points
Rinnakkaistettava silmukka jaetaan ohjelman suoritusvaiheessa mritellylle lukumrlle prosessoreita. Silmukan indeksien jakotapa prosessoreiden
kesken voidaan mritell. Yll nin ei ole tehty, jolloin jako on kntjriippuvainen.
Muuttujat a, b ja i ovat yksityisi, eli kullakin prosessorilla tai sikeell on
oma kopionsa nist. Muuttuja s on mritelty reduktiomuuttujaksi. Tllin
kullakin sikeell on oma kopionsa kyseisest muuttujasta, kunnes rinnakkaisen osan lopussa paikalliset muuttujat yhdistetn reduktio-operaatiolla.
Esimerkiss reduktio-operaatio on +, jolloin paikalliset summat lasketaan
lopuksi yhteen, kuten alkuperisess perkkiskoodissa. Oletusarvoisesti
muuttujat ovat yhteisi, kuten tss n.
308
Fortran 95/2003
Valitsin -np mr suorittavien prosessorien lukumrn. Periaatteessa lukumr voidaan mritell mys dynaamisesti lhdekoodin sisll kullekin
rinnakkaistettavalle alueelle.
Huomaa, ett HPF:st puuttuva reduktiorakenne olisi estnyt esimerkkimme silmukan rinnakkaistuksen, koska silmukka ei olisi ollut muodollisesti
riippumaton. Vaikka summaus onkin todellisuudessa jrjestyksest riippumaton, HPF:n syntaksi kielt direktiivin !HPF$ INDEPENDENT kytn.
MPI:ll ohjelmoijan olisi puolestaan pitnyt huolehtia eksplisiittisesti viestinvlityksest ja tynjaosta.
Harjoitustehtvi
1. Rinnakkaista kappaleessa 3.16 sivulla 38 esitelty pisteparit-simulointiohjelma kytten HPF:.
2. Kirjoita kappaleessa 14.4 sivulla 247 esitellyst yksiulotteisesta soluautomaatista HPF:ll rinnakkaistettu versio.
3. Kirjoita kappaleessa 14.5 sivulla 253 esitellyst Life-pelist HPF:ll rinnakkaistettu versio.
4. Kirjoita kappaleessa 14.8 sivulla 263 esitellyst dierentiaalievoluutioalgoritmista HPF:ll rinnakkaistettu versio.
5. Kirjoita kappaleessa 14.9 sivulla 269 esitellyst liittogradienttialgoritmista HPF:ll rinnakkaistettu versio.
6. Tutki Poissonin menetelmn ajoajan kyttytymist, kun prosessorien
mr on esimerkiksi 4, 8, 16 tai 32. Ent miten mallikoko vaikuttaa
laskenta-ajan kyttytymiseen?
7. Toteuta tehtvt 16 kytten OpenMP:t.
Liite
310
Fortran 95/2003
Ohjelmoinnin kultaiset
snnt
A.1 Yleisohjeita
Kun ohjelmakoodi on sinulle itsellesi selkesti luettavaa, ymmrrettv
ja helposti yllpidettv, on se mys kntjlle helppoa ksitell.
Kirjoita jsennetty, selke ja luettavaa ohjelmakoodia. Ohjelmasi seuraava tulkitsija ja lukija olet mit todennkisemmin sin itse muutaman unohduskuukauden jlkeen.
Sano se mit haluat yksinkertaisesti, suoraan ja selkesti; vlt kikkoja.
Anna ohjelman ja tietokoneen tehd likainen ty. Kyt valmiita aliohjelmakirjastoja, l keksi pyr uudestaan.
A.2 Ohjausrakenteet
Vlt sotkuista ohjelmalogiikkaa. Kyt Fortran 95:n kehittyneit ohjausrakenteita harkiten!
Vlt huonoja ja vanhentuvia Fortranin rakenteita. Useimmat nist rakenteista ovat mys koodin optimoinnin esteit. Kyt sen sijaan kielen
hyvi piirteit, kuten ohjausrakenteita
IF . . .
THEN . . .
ELSE . . .
END IF
SELECT CASE . . .
CASE . . .
END SELECT
DO . . .
END DO
DO WHILE . . .
END DO
l numeroi mitn muita lauseita kuin mahdolliset FORMAT-lauseet sek I/O-rutiinien virheenksittelyyn liittyvt lauseet. Ohjelmasi luettavuus paranee.
311
A.3 Mrittele
Mrittele kaikki kyttmsi muuttujat. Kyt lausetta IMPLICIT NONE,
jolloin mahdolliset kirjoitus- ja tyyppivirheet paljastuvat yleens jo
knnsaikana.
Mrittele kyttmsi proseduurit moduuleissa jos mahdollista, tai kyt INTERFACE-rakennetta. Nin saat kyttsi tehokkaan knnsaikaisen virheentarkistuksen.
Mrittele ohjelmassa esiintyville vakioille (esimerkiksi taulukoiden dimensioiden koot) symboliset nimet PARAMETER-mreill. Nin kannattaa tehd vhintnkin silloin, kun vakio esiintyy useassa kohdassa ohjelmaa.
Kyt yhdenmukaisia tyyppimrittelyj, esimerkiksi:
IMPLICIT NONE
INTEGER, PARAMETER :: short = SELECTED_REAL_KIND(6,30)
REAL (KIND=short) :: a
REAL (KIND=short), DIMENSION(100) :: b
A.4 Strukturoi
Koeta erist asiat tehtvsi kannalta loogisiksi ja samalla riittvn pieniksi kokonaisuuksiksi. Ohjelmoi sitten nm kokonaisuudet moduuleihin sijoitetuiksi proseduureiksi. Toisin sanoen: tee ohjelmistasi modulaarisia. Anna tehtvsi mrt ohjelman rakenne.
Jokaisen proseduurin tulee tehd yksi ja vain yksi asia ja tehd se hyvin.
Jokaisen proseduurin tulee piilottaa ohjelman jonkin yksityiskohdan
toteutustekniikka kutsuvilta ohjelmilta. Tee kunkin proseduurin liittymt muihin ohjelmiin mahdollisimman selkeiksi. Toisaalta: l tee turhia rajoituksia proseduuriesi yleisyyden suhteen, jos mahdollista.
A.5 Standardoi
Kirjoita standardia, luettavaa, muutettavaa ja siirrettv ohjelmateksti. Pyri eristmn kone- ja kntjriippuvat asiat omiin, helposti
lydettviin ja muutettaviin paikkoihin, jos niit ylipns tarvitset, ja
dokumentoi ne. l paikkaa huonoa koodia, vaan kirjoita se uusiksi.
A.6 Dokumentointi
Dokumentoi ohjelmasi kunnolla, mys sen kyttm data ja tiedostot.
312
Fortran 95/2003
A.7 Luettavuus
l kirjoita ptkspagettia. Kirjoita selkesti, kyt mielekkit nimi,
sisenn ohjelmateksti oikein. Kirjoita ohjelmat siten, ett ne etenevt ylhlt alaspin oikeassa jrjestyksess. Voit jopa kirjoittaa ne ensin jrkevll pseudo-Fortranilla ja knt ne sitten standardi-Fortraniksi.
Kyt selkeit ja mielekkit muuttujien nimi. Fortran 90 -standardi
rajoittaa nimen pituuden korkeintaan 31 merkkiin.
l kyt sarkain- eli tabulaattorimerkkej. Toisaalta voit kytt pieni kirjaimia koodin selkeyden parantamiseksi. Skandinaavisia merkkej (, jne.) ei voi kuitenkaan kytt muuten kuin kommenteissa tai
merkkijonoissa.
Ohjelmakoodin kirjoittamista ja editointia helpottaa Fortran 95
-kielen syntaksia ymmrtv editori, esimerkiksi Emacs, jolla voi mys
muotoilla koodia luettavampaan muotoon.
313
IMPLICIT NONE
INTEGER, PARAMETER :: short = SELECTED_REAL_KIND(6,30)
REAL (KIND=short) :: a = 0, t = -1, u
REAL (KIND=short), DIMENSION(100) :: b = 1
...
u = SIN(t + a)
...
Varo pyristysvirheit: 10.0 0.1 on tuskin koskaan 1.0! l vertaa liukulukujen (reaalilukujen) yhtsuuruutta. Kyt numeerisesti luotettavia algoritmeja (tm ei ole triviaali asia!). Kyt apuna asiantuntijoita
ja tunnettuja aliohjelmakirjastoja!
314
Fortran 95/2003
Vlt mys FORMAT-lauseita ja niiden numerointia. Vain kerran tai kahdesti kytettvn FORMAT-lauseenkin voi sijoittaa nimettyn merkkijonovakiona suoraan sit kyttvn WRITE- tai READ-lauseeseen, jolloin
kyseinen I/O-lause ja sit vastaava formaatti ovat samassa paikassa helposti lydettviss.
Tarkkaile sytt- ja tulostustoimintoja. Tm voi usein olla tehottomin
osa ohjelmaasi. Kyt jrkevi ja tehokkaita I/O-menetelmi. Suunnittele sytt ja tulostus huolella.
Jos luet tai tulostat suuria datamri, saat ohjelmastasi tehokkaamman
kyttmll binrist sytt ja tulostusta.
A.11 Yhteenveto
Trkeimpn kaikista ohjeista:
Harkitse kyttmsi algoritmi tarkkaan!
Aiheesta lytyy lis luettavaa mm. seuraavasta hauskasta ja hydyllisest
kirjasesta: The Elements of Programming Style [KP78].
315
selkeyttvt koodia.
Lajiparametrit (kind) parantavat koodien siirrettvyytt.
Fortran 95:n ohjausrakenteet helpottavat ohjelmointia.
Lhdekoodin vapaa syttmuoto parantaa luettavuutta.
Moduulit tekevt ohjelmoinnista luotettavampaa ja tehokkaampaa (esimerkiksi proseduurien argumenttilistojen knnsaikainen tarkistus).
Dynaaminen muistinvaraus helpottaa ohjelmointityt.
Proseduurien argumenttien INTENT-mreet parantavat knnsaikaisia tarkistuksia.
Uudet operaattorimerkinnt (<, >, <=, >=, == ja /=) parantavat koodin
luettavuutta.
Taulukkosyntaksi helpottaa ja tehostaa koodaamista sek parantaa koodin luettavuutta.
316
Fortran 95/2003
317
Yhteenveto Fortran 95
-kielen lauseista
Merkinttavat
Esitmme Fortran 95 -kielen omat tunnukset isoilla kirjaimilla, esimerkiksi
PROGRAM tunnus
aliohjelma
aliohjelma(arg1)
aliohjelma(arg1, arg2)
aliohjelma(arg2=arvo, arg1=arvo)
318
Fortran 95/2003
[sisinen_proseduuri]...]
END [PROGRAM [tunnus]]
[RECURSIVE] SUBROUTINE tunnus[([argumentti][, argumentti]...])]
[mrittelylauseet]
[suoritettavat_lauseet]
[CONTAINS
sisinen_proseduuri
[sisinen_proseduuri]...]
END [SUBROUTINE [tunnus]]
[tyyppi] [RECURSIVE] [tyyppi] FUNCTION tunnus([argumentti] &
[, argumentti]...) [RESULT(tunnus)]
[mrittelylauseet]
[suoritettavat_lauseet]
[CONTAINS
sisinen_proseduuri
[sisinen_proseduuri]...]
END [FUNCTION [tunnus]]
MODULE tunnus
[mrittelylauseet]
[CONTAINS
moduulin_proseduuri
[moduulin_proseduuri]...]
END [MODULE [tunnus]]
BLOCK DATA [tunnus]
[mrittelylauseet]
END [BLOCK DATA [tunnus]]
Alkukirjainsnnn kumoaminen:
IMPLICIT NONE
Alkukirjainsnnn asettaminen:
IMPLICIT tyyppi (kirjainmrittely[, kirjainmrittely]...)
DOUBLE PRECISION
TYPE (tunnus)
Erillisi mrittelylauseita:
ALLOCATABLE [::] taulukko_lista
COMMON [/ tunnus /] lista_olioita
DATA lista_olioista / lista_arvoja /
DIMENSION taulukon_dimensiomrittely
EQUIVALENCE lista
IMPLICIT mrittely
NAMELIST /namelist_ryhmn_nimi/ lista_jsenist
POINTER [::] taulukko_lista
TARGET [::] taulukko_lista
Taulukkojen mrittely:
tyyppi, DIMENSION(arvo[, arvo]...) :: tunnus[, tunnus]...
tyyppi[[, mre]... ::] tunnus(arvo[, arvo]...)
tyyppi, DIMENSION(arvo[, arvo]...), ALLOCATABLE :: &
tunnus[, tunnus]...
tyyppi, DIMENSION(arvo[, arvo]...), TARGET :: &
tunnus[, tunnus]...
tyyppi, DIMENSION(arvo[, arvo]...), POINTER :: &
tunnus[, tunnus]...
Nimetyt vakiot:
tyyppi, PARAMETER :: tunnus[, tunnus]...
PARAMETER ( mrittelylista )
319
320
Fortran 95/2003
Proseduurien mrittelylauseet:
EXTERNAL [::] tunnus[, tunnus]...
INTRINSIC [::] tunnus[, tunnus]...
Moduulin kyttminen:
USE moduuli[, paikallinen_nimi => nimi_moduulissa]...
USE moduuli, ONLY : [[paikallinen_nimi =>] nimi_moduulissa &
[, [paikallinen_nimi =>] nimi_moduulissa]...]
Toistorakenteet:
[tunniste:] DO
lohko
END DO [tunniste]
[tunniste:] DO muuttuja = lauseke, lauseke[, lauseke]
lohko
END DO [tunniste]
[tunniste:] DO WHILE (ehto)
lohko
END DO [tunniste]
EXIT [tunniste]
CYCLE [tunniste]
FORALL-rakenne ja -lause:
[tunniste:] FORALL (kolmikko[, kolmikko]...[, maski])
lohko
END FORALL [tunniste]
FORALL (kolmikko[, kolmikko]...[, maski]) muuttuja = lauseke
FORALL (kolmikko[, kolmikko]...[, maski]) osoitin => kohde
Ehtorakenteet:
[tunniste:] IF (ehto) THEN
lohko
[ELSE IF (ehto) THEN [tunniste]
lohko]
[ELSE [tunniste]
lohko]
END IF [tunniste]
IF (ehto) lause
IF (numeerinen_lauseke) lausenro, lausenro, lausenro
Tapausrakenne:
[tunniste:] SELECT CASE (lauseke)
[CASE (arvo[, arvo]...) [tunniste]
lohko]...
[CASE DEFAULT [tunniste]
lohko]
END SELECT [tunniste]
WHERE-rakenne:
WHERE (ehto) muuttuja = arvo
321
322
Fortran 95/2003
WHERE (ehto)
[sijoituslause]...
[ELSEWHERE
[sijoituslause]...]
END WHERE
Hyppylause:
GO[ ]TO lausenumero
GO[ ]TO (lausenumero_lista) kokonaislukulauseke
GO[ ]TO kokonaislukumuuttuja[[,] (lausenumero_lista)]
[lausenumero] CONTINUE
Suoritettavia lauseita:
ALLOCATE (lista[, STAT=kokonaislukumuuttuja])
DEALLOCATE (lista[, STAT=kokonaislukumuuttuja])
NULLIFY (osoitinmuuttuja_lista)
ASSIGN lausenumero TO kokonaislukumuuttuja
Sijoituslauseet:
muuttuja = lauseke
osoitinmuuttuja => kohde
Tiedostojen ksittely:
OPEN ([UNIT=]kanava[, FILE=lauseke][,STATUS=lauseke] &
[, ACCESS=lauseke][, RECL=lauseke][, FORM=lauseke] &
[, BLANK=lauseke][, ERR=lausenumero][, IOSTAT=muuttuja])
CLOSE ([UNIT=]kanava[, STATUS=lauseke][, ERR=lausenumero] &
[, IOSTAT=muuttuja])
INQUIRE (FILE=tiedoston_nimi, argumenttilista)
INQUIRE (UNIT=kanava, argumenttilista)
BACKSPACE kanava
BACKSPACE ([UNIT=]kanava[, IOSTAT=iostat][, ERR=err-lause])
REWIND kanava
REWIND ([UNIT=]kanava[, ERR=lausenumero][, IOSTAT=muuttuja])
ENDFILE kanava
ENDFILE ([UNIT=]kanava[, ERR=lausenumero][, IOSTAT=muuttuja])
Tiedon sytt:
READ muotoilukoodi, muuttujalista
READ *, muuttujalista
READ
[,
READ
[,
READ
[,
READ
[,
READ
[,
READ
[,
READ
[,
Tiedon tulostaminen:
PRINT *, tulostuslista
PRINT muotoilukoodi, tulostuslista
WRITE ([UNIT=]kanava, [FMT=]muotoilukoodi[, ERR=lauseke] &
[, IOSTAT=lauseke]) tulostuslista
WRITE ([UNIT=]kanava, [FMT=]*[, ERR=lauseke] &
[, IOSTAT=lauseke]) tulostuslista
WRITE ([UNIT=]*, [FMT=]muotoilukoodi[, ERR=lauseke] &
[, IOSTAT=lauseke]) tulostuslista
WRITE ([UNIT=]*, [FMT=]*[, ERR=lauseke] &
[, IOSTAT=lauseke]) tulostuslista
WRITE ([UNIT=]kanava[, ERR=lauseke] &
[, IOSTAT=lauseke]) tulostuslista
WRITE ([UNIT=]kanava, [FMT=]muotoilukoodi, REC=lauseke &
[, ERR=lauseke][, IOSTAT=lauseke]) tulostuslista
WRITE ([UNIT=]kanava, REC=lauseke[, ERR=lauseke] &
[, IOSTAT=lauseke]) tulostuslista
Muotoilukoodin mrittely:
lausenumero FORMAT (muotoilukoodi)
323
324
Fortran 95/2003
ASCII-merkist
0
10
20
30
40
50
60
70
80
90
100
110
120
^@
^J
^T
RS
(
2
<
F
P
Z
d
n
x
^A
^K
^U
US
)
3
=
G
Q
[
e
o
y
^B
^L
^V
^C
^M
^W
!
+
5
?
I
S
]
g
q
{
^D
^N
^X
"
,
6
@
J
T
^
h
r
|
^E
^O
^Y
#
7
A
K
U
_
i
s
}
^F
^P
^Z
$
.
8
B
L
V
j
t
^G
^Q
ESC
%
/
9
C
M
W
a
k
u
DEL
^H
^R
FS
&
0
:
D
N
X
b
l
v
^I
^S
GS
1
;
E
O
Y
c
m
w
*
4
>
H
R
\
f
p
z
E. Sanasto
325
Sanasto
326
Fortran 95/2003
E. Sanasto
327
tms.)
quote: heittomerkki
range: vaihteluvli
rank: ulottuvuuksien lukumr
real number: reaaliluku
record: tietue, jono arvoja joita
ksitelln yhten kokonaisuutena
tiedostossa
recursive: rekursiivinen
relational operator: vertailuoperaattori
reshape: muokata
return: paluu proseduurista,
rivinvaihto
return value: funktion palauttama
arvo
scalar variable: skalaarimuuttuja
scope, scoping unit: nkyvyysalue
selector: (tapauslauseen) valitsin
sequence: jono
sequential: perkkinen
shape: muoto
side-eect: sivuvaikutus
sign: etumerkki
size: (taulukon) koko, alkioiden
lukumr
source form: lhdekoodin syttmuoto
source program: lhdekielinen
ohjelma, lhdekoodi
specic name: erityisnimi
specication expression:
mrittelylauseke
specication statement:
mrittelylause
statement: lause
statement function: lausefunktio
statement label: lausenumero
storage association: alkioiden yhteinen
sijoittelujrjestys muistissa
stride: askelpituus
structure: rakenne
structure constructor: rakenteen
alustin
subarray: osataulukko
subexpression: osalauseke
subroutine: aliohjelma
subscript: (taulukko)indeksi
subscript triplet: taulukon lohko, joka
koostuu alkuarvosta,
loppuaskeleesta ja askeleesta
kaksoispisteell (:) erotettuna
substring: osamerkkijono,
alimerkkijono
target: kohde
transformational function:
muunnosfunktio
328
type: tyyppi
type declaration statement: tyypin
esittelylause
type parameter: tyypin parametri
unary operator: yksiargumenttinen
operaattori
undened: mrittelemtn
undened variable: mrittelemtn
muuttuja
unformatted input/output: binrinen
tiedonsiirto
Fortran 95/2003
unit: kanava
unit number: kanavanumero
upper bound: ylraja
user-dened assignment: kyttjn
mrittelem sijoituslause
user-dened operator: kyttjn
mrittelem operaattori
variable: muuttuja
variable declaration: muuttujan
esittely
vector subscript: vektori-indeksi
Kirjallisuutta
329
Kirjallisuutta
[ABM+ 92] Jeanne C. Adams, Walter S. Brainerd, Jeanne T. Martin, Brian T. Smith ja
Jerrold L. Wagener. Fortran 90 Handbook. Complete ANSI/ISO Reference.
McGraw-Hill, 1992.
[ABM+ 97] Jeanne C. Adams, Walter S. Brainerd, Jeanne T. Martin, Brian T. Smith ja
Jerrold L. Wagener. Fortran 95 Handbook. Complete ISO/ANSI Reference.
The MIT Press, 1997.
[BGA94]
Walter S. Brainerd, Charles H. Goldberg ja Jeanne C. Adams. Programmers Guide to Fortran 90. UNICOMP, 1994.
[CLR90]
[CS06]
[EPL94]
[Geh96]
[GHJV95] Erich Gamma, Richard Helm, Ralph Johnson ja John Vlissides. Design
Patterns. Addison-Wesley, 1995.
[Haa98]
Juha Haataja, toim. Matemaattiset ohjelmistot. CSC Tieteellinen laskenta Oy, 1998. URL http://www.csc.fi/oppaat/mat.ohj/.
[Haa02]
Juha Haataja, toim. Alkurjhdyksest knnykkn nkkulmia laskennalliseen tieteeseen. CSC Tieteellinen laskenta Oy, 2002.
[Haa04]
[HHL+ 02] Juha Haataja, Jussi Heikonen, Yrj Leino, Jussi Rahola, Juha Ruokolainen
ja Ville Savolainen. Numeeriset menetelmt kytnnss. CSC Tieteellinen laskenta Oy, 2002.
[HJKR02] Juha Haataja, Jari Jrvinen, Jari Koponen ja Peter Rback, toim. Laskennallinen tuotekehitys: suunnittelun uusi ulottuvuus. CSC Tieteellinen
laskenta Oy, 2002.
[HJL00]
Juha Haataja, Jari Jrvinen ja Yrj Leino. Sillanrakennuksesta lkeainesuunnitteluun Matemaattinen mallintaminen suomalaisissa yliopistoissa. CSC Tieteellinen laskenta Oy, 2000. http://www.csc.fi/
raportit/mallinnus/.
[HM01]
[Kar01]
330
Fortran 95/2003
[Ker93]
[KLS85]
[KLS+ 94]
[Kos97]
[KP78]
[MR96]
[MRC04]
Michael Metcalf, John Reid ja Malcolm Cohen. Fortran 95/2003 Explained. Oxford University Press, 2004.
[Rei]
[RR96]
[Saa95]
[Sed84]
Hakemisto
331
Hakemisto
Symbolit
!, 45, 46
!HPF$, 299
", 46, 53
, 46
, 53
(, 46
(/, 168, 241
), 46
*, 46, 67, 142, 143, 193, 194, 197
**, 67, 142, 143
+, 46, 67, 142, 143
,, 46
-, 46, 67, 142, 143
., 46
/, 46, 67, 142, 143
/), 168, 241
//, 53, 73, 143
/=, 77
:, 46, 164166, 179, 203, 320
::, 53, 318
;, 44, 46
<, 46, 7779
<=, 77
=, 46, 147, 320, 322
==, 7779
=>, 320, 322
>, 46, 7779
>=, 77
?, 46
$, 46
%, 46, 152
&, 36, 44, 46
_, 26
A
ABS, 222, 230
abstrakti tietorakenne, 126
ACHAR, 79, 223
ACOS, 113, 220, 230
ADJUSTL, 74, 223
ADJUSTR, 74, 223
ADVANCE=NO, 204
332
aritmeettiset lausekkeet, 67
array, 164
array constructor, 168
array element order, 169
ASCII-merkist, 46, 56, 79, 223, 324
ASIN, 113, 220, 230
ASSIGN, 286, 322
assigned goto, 284, 286
ASSOCIATED, 186, 217
assumed length, 285
assumed-shape array, 171
assumed-size array, 172
asteriski, 46
asuntolainan lyhennykset, 35
ATAN, 113, 220, 230
ATAN2, 70, 220, 230
automaattinen taulukko, 165
automatic array, 165
avainsana-argumentti, 118, 120
B
BACKSPACE, 204, 322
binripuu, 256
binritiedostot, 206
bisection, 135
BIT_SIZE, 226, 227
bittien ksittely, 226
BLOCK DATA, 47, 127, 281, 288, 317
bottom up, 99
BTEST, 226, 227
C
CALL, 39, 216, 317, 320
CASE, 88, 321
CASE DEFAULT, 88, 89, 321
CEILING, 71, 222
CHAR, 79, 223, 254
CHARACTER, 51, 55, 73, 318
CLASS, 297
CLASS IS, 297
CLOSE, 204, 206, 322
CMPLX, 81, 221
COMMON, 127, 278, 280, 281, 288, 319
korvaus moduuleilla, 283
compiler, 17
COMPLEX, 51, 318
computed goto, 283, 284, 288
conformable, 190
CONJG, 222, 230
conjugate gradient method, 269
CONTAINS, 31, 47, 48, 101, 108, 129,
317
CONTINUE, 95, 286, 322
COS, 220, 230
COSH, 220, 230
Fortran 95/2003
D
DATA, 319
datarinnakkaisuus, 304
DATE_AND_TIME, 217
DBLE, 221
DE-menetelm, 263
DEALLOCATE, 179, 189, 322
debugger, 21, 192
deferred-shape array, 165
deleted feature, 284
derived type, 152
desimaaliesitys, 199
desimaalipiste, 27, 52
dierenssimenetelm, 300
dierentiaalievoluutio, 263
DIGITS, 221
DIM, 222, 230
DIMENSION, 33, 164, 189, 280, 319
disassociated, 158
DISTRIBUTE, 302, 304
DO WHILE, 9294, 321
DO-rakenne, 90, 91, 93, 321
DO-silmukka, 32
dokumentointi, 19
dollarin merkki, 46
DOT_PRODUCT, 175, 225
DOUBLE PRECISION, 60, 278, 281, 288,
318
DPROD, 222, 230
DSIN, 288
dynaaminen tilanvaraus, 178
dynaamisesti varattava taulukko, 165
dynamic array, 165
E
ehdollinen suoritus, 86
ehtolause, 37
ehtorakenne, 321
eksponenttiesitys, 27, 199
eksponenttifunktiot, 71, 220
eksponenttinotaatio, 52, 57
ELEMENTAL, 115
elemental, 215
ELSE, 87, 321
ELSE IF, 87, 321
ELSEWHERE, 176, 255
Emacs, 20
Hakemisto
END, 47
END BLOCK DATA, 317
END DO, 90, 93, 286, 321
END FUNCTION, 100, 317
END IF, 87, 321
END INTERFACE, 147, 320
END MODULE, 129, 317
END PROGRAM, 25, 26, 47, 317
END SELECT, 88, 321
END SUBROUTINE, 104, 317
END TYPE, 319
ENTRY, 288
EOSHIFT, 177, 224
EPSILON, 132, 221
epsuora hyppylause, 286
.EQ., 77
EQUIVALENCE, 278, 279, 281, 288, 319
.EQV., 77, 78
Erastotheneen seula, 182
erikoismerkit, 46, 79
erisuuruus, 77
erityisnimi, 229231, 288
Esc -merkki, 255
esimerkkiohjelmat, 234
et-merkki, 46
etsint, 257
etumerkin vaihto, 67
etumerkki, 27
Euklideen algoritmi, 93
evoluutiostrategiat, 263
exclusive or, 76
EXIT, 91, 92, 94, 321
EXP, 220, 230
explicit interface, 116
explicit-shape array, 164, 171
EXPONENT, 221
EXTENDS, 296, 297
EXTERNAL, 47, 110, 113, 319, 320
external procedure, 108
EXTRINSIC, 305
F
FINAL, 294
xed source form, 44
FLOOR, 71, 222
FORALL, 177, 304, 305, 321
FORMAT, 47, 197, 284, 286, 323
format, 35
formatoimaton tiedonsiirto, 206
formatoitu tiedonsiirto, 206
Fortran 2003, 291
FORTRAN 66 -kieli, 23
FORTRAN 77 -kieli, 23
huonoja puolia, 276
333
G
.GE., 77
geneerinen
aliohjelma, 320
funktio, 320
nimi, 140
operaattori, 320
proseduuri, 140, 238
globaali data, 128
globaali muuttuja, 109
globaali optimointi, 264
GOTO-lause, 95, 322
.GT., 77
H
haarautuva hyppylause, 283, 284, 288
hakuavain, 257
heittomerkki, 46
High Performance Fortran, 25, 299
Hollerith-merkkijonovakiot, 287
host, 108
HPF, 25, 299
!HPF$, 299
HPF_LIBRARY, 300, 304
HUGE, 221, 282
huutomerkki, 46
hyppylause, 86, 95, 322
haarautuva, 283, 284, 288
I
IACHAR, 79, 223
IAND, 226, 227
IBCLR, 226
IBITS, 226
IBSET, 226
ICHAR, 79, 223
IEEE-liukulukuaritmetiikka, 69
IEOR, 226
IF-lause, 88
334
J
jakojnns, 94
jakolasku, 27, 67
jatkorivi, 36, 279, 280
jatkorivin merkki, 44
julkiset tunnukset, 133
julkisuus, 126, 131, 132, 159, 320
juurisolmu, 257
K
kaksiargumenttinen operaattori, 143,
147
Fortran 95/2003
kaksoispiste, 46
kaksoistarkkuus, 60
kanava, 35, 204, 323
ominaisuuksien kysely, 207
kanavanumero, 196, 204
karteesiset koordinaatit, 69
katkaisuoperaatiot, 71
kellonaika, 217, 219
kentn leveys, 144, 197
kertolasku, 27, 67
keskiarvo, 33, 34, 118
keskusmuisti, 18
keskusyksikk, 17
KIND, 221
kind, 56
KIND-parametri, 69
kirjoitus merkkijonoihin, 209
kokonaisluku, 51, 198
jakolasku, 27, 68
kokonaislukulaji, 52
kokonaislukumuuttuja, 28
kokonaislukutyyppi, 29, 51
kokonaislukuvakio, 27, 51
kommentti, 45
kommenttimerkki, 279, 280
kompleksiargumentti, 71
kompleksiluku, 51, 52, 58, 200
kompleksilukuvakio, 52, 217
komponenttiajattelu, 99
konekieli, 17
koneksky, 17
koodin optimointi, 21
koordinaattimuunnokset, 69
kosini, 71
kutsumuoto, 116, 136
mrittely, 116
kutsurajapinta, 99
kyselyfunktiot, 215
kysymysmerkki, 46
kyttjn mrittelem operaattori, 143
knnsaikaiset tarkistukset, 31, 110
knnslistaus, 20
kntj, 17
kntminen, 13, 19, 26, 40, 128
L
lainausmerkki, 27, 46, 53
laji, 52
lajimre, 56, 63
lajiparametri, 57, 58, 69
lajittelu, 80, 126, 237
nousuindeksi, 240
laskentajrjestys, 81
lause, 44
jrjess, 47
Hakemisto
jrjestys, 47
tiivistelm lauseista, 317
lausefunktio, 281, 288
lauseke, 67
lausenumero, 95, 322
LBOUND, 175, 179, 225
.LE., 77
LEN, 73, 74, 223, 230
LEN_TRIM, 74, 75, 223
LGE, 79, 223
LGT, 79, 223
Life-peli, 253
Life-soluautomaatti, 253
liitosoperaatio, 53, 73, 143
liittogradienttimenetelm, 269, 270
lineaariset yhtlryhmt, 269
linkitys, 19, 21
linkitystaulu, 21
list-directed formatting, 194
listan ohjaama muotoilu, 194
liukulukuesitys, 57
LLE, 79, 223
LLT, 79, 223
LOG, 220, 230
LOG10, 220, 230
logaritmifunktiot, 71, 220
LOGICAL, 51, 221, 318
looginen ekvivalenssi, 77
looginen epekvivalenssi, 77
looginen ja, 77
looginen negaatio, 77
looginen tai, 77
loogiset lausekkeet, 76, 77
loogiset operaatiot, 77
lopettaminen, 294
lopetusehto, 111
.LT., 77
luku merkkijonoista, 209
lhdekoodin muoto, 24, 44
lhdekooditiedosto, 19
M
matemaattiset funktiot, 222
MATMUL, 174, 225
matriisi, 168, 169
alkioiden summa, 174
alkioiden tulo, 174
tulo, 174
MAX, 222, 231
MAXEXPONENT, 221
MAXLOC, 175, 225
MAXVAL, 175, 225
MERGE, 176, 224
merkkien jrjestys, 79
merkkijono, 51, 53, 201
335
336
Fortran 95/2003
omat funktiot, 30
ominaisuuksien kysely, 207
ONLY, 133, 320
OPEN, 204206, 210, 322
OpenMP, 305
operaation mrittelyalueen laajentaminen, 140
operaattori, 83, 126
kaksiargumenttinen, 143
kyttjn mrittelem, 143
mrittely, 142, 147
yksiargumenttinen, 143, 144
ylilataaminen, 142
operator overloading, 142
optimointi, 21, 83, 84
optimointitehtvien ratkaiseminen, 263
OPTIONAL, 47, 119, 319, 320
optional, 118
.OR., 77, 78
osoitin, 183
kohde, 190
kohteesta irroitettu, 158
muuttuja, 178, 180, 183, 185, 186,
190
otsikkolause, 47, 101, 102
otsikkorivi, 31
overloading, 140
objektikooditiedosto, 19, 21
obsolescent feature, 284
ohjauskoodi, 202
ohjausrakenteet, 86
ohjelma, 17
ajaminen, 13, 40
konekielinen, 17
ohjelmayksikk, 127
perusrakenne, 44
pohjelma, 127
suorituksen keskeytys, 322
ohjelmakoodi, 19
rakenne, 44
ohjelmalohko, 86
ohjelmayksikiden mrittely, 317
ohjelmayksikk, 20, 127
ohjelmisto, 16
ohjelmointi, 16, 17
eri vaiheet, 18
ohjelmointikieli, 17
oikea sulje, 46
oletetun kokoinen taulukko, 172
oletetun muotoinen taulukko, 171
oletusarvoinen kutsumuoto, 116
oletusmuotoilu, 35, 194
olio-ohjelmointi, 295
Hakemisto
Q
Quicksort-algoritmi, 273
R
RADIX, 221
rakenteinen tietotyyppi, 152
rakenteinen tyyppi, 33, 34
mrittely, 319
rakenteiset tyypit, 296
random walk, 244
RANDOM_NUMBER, 39, 138, 139, 218,
245, 249
RANDOM_SEED, 218
RANGE, 221
rank, 164
reaaliluku, 27, 51, 52, 199
reaalilukulaji, 131
reaalilukutyyppi, 29
reaalilukuvakio, 27, 52
laji, 58
READ, 193, 196, 204, 323
337
S
sarakesidonnainen syttmuoto, 44,
277
sarjan summa, 60
satunnaiskulku, 244
satunnaisluvut, 218, 219
normaalijakautuneet, 138
SAVE, 108, 319, 320
SCALE, 221
SCAN, 74, 223
scope, 121
SELECT CASE, 88, 321
SELECT TYPE, 297
SELECTED_INT_KIND, 56, 57, 221
SELECTED_REAL_KIND, 57, 118, 221
selection sort, 80
SEQUENCE, 155, 296, 319
SET_EXPONENT, 221
SHAPE, 171, 175, 225
shape, 164
Shellsort-algoritmi, 241
sidontajrjestys, 67, 83
SIGN, 69, 222, 230
siirrettvyys, 17, 24
sijoituslajittelu, 237
sijoituslause, 29, 67, 81, 322
sijoitusoperaatio, 142
mrittely uudelleen, 146
sijoitusoperaattori, 147
silmukka, 90
silmukkamuuttuja, 32, 90
reaalilukutyyppi, 285
simulointi, 38
338
T
TAN, 220, 230
TANH, 220, 230
Fortran 95/2003
tapausrakenne, 321
tapausten ksittely, 88
TARGET, 184, 190, 319
tarkkuus, 69
taulukko, 33, 164
alkio, 166
alkioiden summa, 34
alkiojrjestys, 169
alustin, 168, 241
automaattinen, 165
dynaaminen, 165
indeksointi, 167
mrittely, 319
mukautuva, 165
muoto, 164
oletettu koko, 172
oletettu muoto, 171
operaatiot, 39, 174, 224, 225
rajojen tarkistukset, 21
standardifunktiot, 174
tunnettu muoto, 164, 171
ulottuvuudet, 164
vlitys, 170
vakio, 165
testaus, 19, 21
THEN, 87, 321
tiedon hakeminen, 257
tiedon jrjestminen, 256
tiedon sytt, 192, 198, 323
tiedon tulostaminen, 192, 323
tiedonsiirto, 193
erikoistilanteet, 95
tiedosto, 18
avaaminen, 204
ksittely, 204, 322
ominaisuuksien kysely, 207
tietoabstraktio, 257
tietokone, 17
tietotyypit
abstraktit, 152
perustyypit, 51
rakenteiset, 152
tietueen osan tulostaminen tai lukeminen, 204
tiivistelm lauseista, 317
tilapistiedosto, 206
TINY, 221
todellinen argumentti, 31, 101
toisen asteen yhtl, 72
toisto, 86, 90
toistolista, 168
toistorakenne, 32, 321
top down, 99
totuusarvo, 51, 52
TRANSFER, 224, 279
Hakemisto
U
UBOUND, 175, 225
ulkoinen proseduuri, 108, 110, 123,
127
geneerinen nimi, 142
ulottuvuudet, 164
unit, 35
UNPACK, 177, 224
USE, 47, 128, 132, 320
USE-lause, 133
uudet piirteet, 276
V
vaihtelevan pituinen merkkijono, 73
vaihtoehtoinen paluukohta, 286
vakio, 27
mrittely, 128
nimi, 46
tyyppi, 51
vakiotaulukko, 128, 165
valinnainen argumentti, 118, 119
valinta, 86
valintalajittelu, 80
vanhentuvat piirteet, 284
vapaa lhdekoodin muoto, 24, 44, 280
vasen sulje, 46
VERIFY, 74, 75, 223
339
versionhallintajrjestelm, 279
vertailuoperaatio, 77
vertailuoperaattori, 77, 78
vinoviiva, 46
virheenjljitysohjelma, 21
virheentarkistus, 110
virhetilanne, 94
virhetilanteiden ksittely, 210, 211
VT100, 255
vhennyslasku, 27, 67
vlilynti, 45, 46, 277
vltettvt piirteet, 287
W
WHERE, 176, 246, 255, 267, 321
World Wide Web, 14
WRITE, 25, 196, 204, 323
www, 14
Y
yhteenlasku, 27, 67
yhtlisyysmerkki, 46
yhtsuuruus, 77
yksiargumenttinen operaattori, 143,
144, 147
yksityisyys, 126, 131, 159, 320
yleinen muotoilukoodi, 201
ylilataaminen, 140, 156
yllpito, 19