A szubprogram egy kisebb kódrészlet, ami egy konkrét segédfeladatot old meg. Egy nagyobb programban elõfordulhat, hogy ugyanazt azt alproblémát kell megoldani többször, de különbözõ adattokkal. Ilyenkor is alkalmazhatunk szubprogramot, a parancsok ismétlése helyett, azaz az egyszer megírt segédprogramot kell elõhívni, miután a bemenõ adatokat megfelelõen módosítottuk.
A Fortranban kétféle szubprogram van: a függvények és a subroutine-ok.
Egy egyszerû példa a függvények használatára:
x = cos(pi/3.0)Itt a cos a cosinus függvény, tehát x értékére 0.5 adódik majd. (feltéve ha pi értékét korrekten definiáltuk, mivel a Fortran 77-nek nincsenek beépített konstans értékei). Nézzünk példákat a Fortran 77 saját, beépített függvényeire:
abs abszolútérték min minimum érték max maximum érték sqrt gyökvonás sin sinus cos cosinus tan tangens atan cotanges exp exponenciális (természetes, e) log logaritmus (természetes alapú, ln)Általában a függvényeknek típusuk van. A legtöbb beépített függvény, amiket elõbb is is láttunk, általános tipusú. Azaz, például a fenti esetet tekintve a pi és x értéke lehet real vagy double precision is. A programolvasó ellenõrzi az adatok típusát és a helyes cos verziót fogja alkalmazni (real vagy double precision-t). Sajnos a Fortran nem elég rugalmas nyelv e téren, ezért nagyon fontos a változók típusainak és a függvények korrekt megválasztása!
Most térjünk vissza a felhasználó által írt függvényekre. Tekintsük az alábbi problémát: Egy meteorológus miután tanulmányozta a Balaton-vidék havi csapadék viszonyait, segítségével egy modellt alkot:: r(m,t)-et, ahol r a havi csapadékösszeg, az m a hónap száma, és t a földrajzi helyre utaló paraméter, Ha r-re egy formulát és t-nek egy értéket adunk az éves csapadékösszeget kiszámolhatjuk.
A legegyszerübb megoldás egy ciklus megírása, ami havonként összegzi a csapadékmennyiségeket. Itt most r-et nem mérjük, hanem számítjuk. Az r kiszámítása egy külön elszigetelt probléma, ezért célszerû egy szubprogram megírása értékének meghatározásához. A fõprogram alakja az alábbi (más megoldás is lehet):
program eso real r, t, sum integer m read (*,*) t sum = 0.0 do 10 m = 1, 12 sum = sum + r(m, t) 10 continue write (*,*) 'Eves csapadekosszeg ', sum, 'mm' stop endMegjegyzés: r-et egy valós változónak definiáltuk (hiszen egy konkrét értéket ad) A szubprogramban majd r-et Fortran függvénynek kell definiálni. A meteorológus az alábbi formulát találta:
r(m,t) = t/10 * (m**2 + 14*m + 46) (ha ez pozítiv) r(m,t) = 0 (egyébként)Ez Fortranban lekódolva:
real function r(m,t) integer m real t r = 0.1*t * (m**2 + 14*m + 46) if (r .LT. 0) r = 0.0 return endLáttuk, hogy egy függvény formailag szinte teljesen megegyezik a fõprograméval. Azonban vannak különbségek, melyek közül a fontosabbak:
típus function név (kül. változó típusok szerint) deklarációk utasítások return endA függvény típusát pontosan kell megadni a hívó programban. Ha olyan függvényt alkalmazunk, amit elõtte nem deklaráltunk, a Fortran pótlásképp saját maga fogja deklarálni, nem kizárt, hogy hibásan. Egy függvényt nevének és paramétereinek leírásával (a paramétereket zárójelben a név mögött soroljuk föl) hívhatjuk meg.
Meg kell jegyezni, hogy a gyári, alapértelmezett Fortran 77 nem engedi meg a rekurzív (önmagát generáló számításokat), de némelyik fordító már elfogadja használatukat.
subroutine név (argumentumok listája) deklarációk utasítások return endFontos, hogy a subroutin-oknak nincsen típusuk és nem is lehet deklarálni a fõprogramban. Ezért meghívásuk is más, mint a függvényeknél: a call (=hívás) szót kell leírnunk nevük és paramétereik elé.
Nézzünk egy egyszerû subroutine-t. A feladat két egész szám megcserélése:
subroutine csere (a, b) integer a, b c Lokalis valtozok integer tmp tmp = a a = b b = tmp return endItt kétféle deklarációt is alkalmazunk. Elõször a bemenõ/kimenõ paramétereket kell, amik közösek a hívó és a hívott programban. De ezután deklarálni kell a lokális (helyi) változókat, amiket csak ebben a szubprogramban használhatunk. Ezért nyugodtan használhatunk ugyanolyan változó-neveket a különbözõ segédprogramokban, a programfordító tudni fogja, hogy ezek különbözõ változók, habár nevük formailag ugyanaz.
program callex integer m, n c m = 1 n = 2 call csere(m, n) write(*,*) m, n stop endEnnek a programnak az eredménye "2 1", ahogy el is várjuk. De, ha a Fortran 77 call-by-value típusú hívást alkalmazott volna az eredmény "1 2" lenne, azaz m és n felcseréletlen maradt volna! Ennek az az oka, hogy a második esetben csak az értéket másolta volna a csere subroutine-ba, ahol habár a és b értékét megcserélte volna, az új (felcserélt) értékeket nem adta volna vissza a fõprogramba.
A fenti példa is rávilágosított, hogy jobb a call-by-reference hívás De bánjunk óvatosan ezzel is, mert könnyen elronthatjuk vele programunkat. Például néha csábító lehet a szubprogramba bemenõ változót egyben lokális változónak is használni, és így változtatni meg az értékét. Azonban a szubprogramból kimenõ érték már ez a megváltozott lesz, ami többnyire nem kívánatos. Bizonyos esetektõl eltekintve (amikor direkt akarjuk megváltoztatni a fõprogrambeli változónk értékét, lásd elõzõ példa) kerüljük ezt a megoldást.
Késõbb még folytatjuk e téma taglalását, de elõtte tisztáznunk kell a tömbök (mint argumentumok) szerepét a segédprogramokban.
Copyright © 1995-7 by Stanford University. All rights reserved.
Fordították: Seres András Tamás és Szalai Szilvia (ELTE-TTK)