A Fortran programozási nyelv

Alprogramok

Amikor egy program több száz sor hosszú, már nehéz követni. Sőt, a valódi mérnöki (vagy akármilyen más) számításoknál sokszor több ezer sorból álló programokat kell alkalmazni. Az egyetlen módja, hogy e hatalmas "kód-zuhatagot" kezelni tudjuk a modulátorok és a programba beágyazott alprogramok használata, amikkel programunk szövegét több kisebb részre bonthatjuk. Az alprogram egy kisebb kódrészlet, ami egy konkrét részfeladatot 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 alprogramot, 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 FORTRAN program szegmensekből áll, amelyek közül az egyik a főszegmens, a fennmaradók háromfélék lehetnek: függvények (FUNCTION), eljárások (SUBROUTINE), és lehet a programban egy adatszegmens.(BLOCK DATA) A szegmensekben használt azonosítók (kivéve a szegmens nevét és a COMMON adatmezőket) lokálisak. A szegmensek a nyelv fordítási egységei. A nyelv nem tartalmaz elemet a szegmensek közötti kapcsolatok leírására, fordítás közben nincs mód a kapcsolatok helyességének ellenőrzésére.

A szegmensek elején deklarációs sorok állnak, utánuk következik a végrehajtható rész. A deklarációs rész kiértékelése statikus, a változók leképezése a memóriába fordítási időben történik. Sem az eljárások, sem a függvények nem hívhatják meg önmagukat, de az F(F(X)) függvényhívás legális. A fordító az eljárás hívásakor csak a formális paraméterek számának egyezését vizsgálja, a típusukat nem! A paraméterátadás: szám és logikai változókra címszerinti, a kifejezésekre érték szerinti (ekkor a formális paramétert lokális változóként lehet használni), tömbökre szintén címszerinti. A tömbök átadásánál többféle lehetőségünk is lehet:

SUBROUTINE, FUNCTION

A SUBROUTINE és a FUNCTION szintaxisa nagyon hasonló. Az előbbi SUBROUTINE S(A1, A2, ..., AN) vagy SUBROUTINE S, az utóbbinak FUNCTION F(A1, A2, ... , AN) vagy t FUNCTION F(A1, A2, ... , AN) . Az S illetve F névnek mindig szerepelnie kell, függvény esetén legalább egy formális paraméterre mindig szükség van. A formális paraméterek és a t visszatérési értékek az alaptípusok lehetnek.

Az alprogram hívására a CALL, a visszatérésre a RETURN utasítás szolgál.

SUBROUTINE ORTOG (X,Y,U,V,FI) U=X*COS(FI)+Y*SIN(FI) V=-X*SIN(FI)+Y*COS(FI) RETURN END ... CALL ORTOG (1.0, 2.0, A, B, ALFA)

A példából is látható, hogy az elemi matematikai függvények megvalósítását a nyelv tartalmazza. A függvényt mindig valamilyen (aritmetikai vagy logikai) kifejezésbe beleírva lehet meghívni. Függvényeknél a visszatérési értéket úgy állíthatjuk be, ha a függvény nevének értéket adunk. Például:

C ------------------------- INTEGER FUNCTION SUMM(MM, MN) C ------------------------- INTEGER MM, MN C SUMM = 0 DO 98 I = MM, MN SUMM = SUMM + I 98 CONTINUE RETURN END

Habár FORTRAN alprogramokban lehetőség van lokális tömbök definiálásra, de ezt nem szokták használni. Általában a főprogramban deklaráljuk az összes tömböt, és ezekre hívjuk meg az alprogramokat.

Eljárás paraméterlista: intent

A paramétereket a szubrutin nevét követő zárójelben felsorolt belső változónevekkel jelöljük. Ezeket a változókat ugyanúgy deklarálni kell, mint a eljárások saját változóit. A szándék (intent) tulajdonsággal adhatjuk meg, hogy az egyes paraméterek információt adnak át az eljárásnak (intent(in)), vagy információt adnak vissza a meghívó program egységnek (intent(out)), esetleg mindkettőt (intent(inout)). A paraméterek a szokásos változótípusokon kívül lehetnek eljárások, függvények, vagy mutató típusú argumentumok. Ezeknél az intent tulajdonság nem adható meg.

subrutine sub(a,b,c,d,e,f) implicit none real, intent(in) :: a ! bejövő adat real, intent(out) :: b ! kimenő adat character(len=10), intent(inout) :: c ! be és kimenő adat real, pointer :: d ! pointer, nincs intent external :: e ! eljárás real, external :: f ! függvény integer :: i ! lokális változó write(*,*)'a=',a ! a használható, de nem változtatható b = (/1.0, 2.0/) ! b bejövő értéke nem használható c(1:1) = 'A' ! c értéke olvasható és változtatható d = d + 1 ! d pointer értéke változtatható call e(5) ! e eljárás meghívása read(*,*) i ! i lokális változó használata write(*,*)'f(i=)',f(i) ! f függvény használata end subrutine sub

Függvény visszatérési érték: result

A függvény paraméterei általában mind intent(in) szándékúak, hiszen az eredményt a függvény adja vissza.

A függvények visszatérési érték megadásának módozatai:

! a visszaadott érték típusa a function előtt real function integral(xMin,xMax) real, intent(in) :: xMin, xMax integral = ... ! a függvény érték megadása end function

! result(nev) megadása, más néven hivatkozunk a függvény eredményére real function integral(xMin,xMax) result(res) real :: res real, intent(in) :: xMin, xMax res = ... ! az eredmény megadása end function

A függvényben is szerepelhet return utasítás, de ügyelnünk kell arra, hogy a függvény mindig értéket kapjon.

Rekurzív eljárások

Mind az eljárások, mind a függvények meghívhatják önmagukat akár közvetlenül, akár közvetett módon más eljárások és függvényeken keresztül. A rekurzív alprogramok esetében a subrutine illetve a function elé kell írni, hogy recursive.

A faktoriális kiszámítása rekurzív módon:

recursive function factorial(n) result(res) integer :: res intiger, intent(in) :: n if(n<=1)then res = 1 else res = n*factorial(n-1) end if end function factorial

Opcionális argumentumok

Egy alprogramnak nagyon sok argumentuma lehet. Gyakran ezeknek egy része mindig ugyanolyan értékű, vagy a hívások nagy részében nincsenek befolyással az eredményre. Az ilyen argumentumokat célszerű optional tulajdonsággal deklarálni.

subrutine write_array(a backward) implicite none real, intent(int) :: a(:) logical, intent(in), optional :: backward ... end subrutine

Az eljárást meghívhatjuk egy vagy két paraméterrel.

call write_array(a) call write_array(a, .true.)

Az eljáráson belül a present függvény segítségével dönthető el, hogy egy opcionális paraméter szerepelt-e a külső paraméter listában vagy sem.

subrutine write_array(a backward) implicite none real, intent(int) :: a(:) logical, intent(in), optional :: backward if(present(backward))then ... else ... end if end subrutine

Név szerinti argumentumok

Ha opcionális paraméterek vannak az argumentumlistában, akkor a külső argumentumok sorrendje nem feltétlenül adja meg, hogy melyik belső argumentumhoz tartoznak. Ilyenkor név szerint lehet hivatkozni az argumentumokra.

call write_array(a=x, backward=.true.)

Változók megőrzése

A főprogramban deklarált változók értéke nem veszhet el, azonban az eljárásokban deklarált lokális változók értéke nem őrződik meg a vezérlés visszatérése után. Ha a deklarációban szerepel a save tulajdonság, akkor a változó értéke megmarad.

Például írjuk ki, hogy egy eljárást hányszor hívták meg.

subrutine sub implicit none integer, save :: counter=0 counter=counter+1 write(*,*)'Total number of calls:', counter end subrutine sub

Fontos megjegyezni, hogy a kezdeti értékadás csak az első meghívásra vonatkozik.

Belső eljárások

A belső eljárások általánosításaként itt már nincs megkötve, hogy csak egy soros lehet a definíció. Nézzük a következő példát:

SUBROUTINE polygon_area(vertices) IMPLICIT NONE ... area1 = triangle_area(a, b, x) ... area2 = triangle_area(x, c, d) ... CONTAINS REAL FUNCTION triangle_area(a, b, c) ! belső függvény REAL, INTENT(IN) :: a, b, c REAL :: s ! lokális változó a függvényben s = 0.5 * (a + b + c) triangle_area = sqrt(s * (s-a) * (s-b) * (s-c)) END FUNCTION triangle_area END SUBROUTINE polygon_area

Szabályok a belső eljárások alkalmazásához:

Megjegyzés: A belső eljárások látják a befogadó szegmens változóit, ez azonban visszafelé nem igaz!

DATA BLOCK

A data utasítás

Az olyan változók, amelyek már a program megírásánál is ismertek, a data (=adat) utasítással is bevihetők. Formalizmusban nagyon hasonló az elnevezéses utasításokhoz. A metódus a következő:

data változók listája/ értékek listája/, ...

ahol a három pont azt jelenti, hogy ezen beírás akárhányszor megismételhető, például:

data m/10/, n/20/, x/2.5/, y/2.5/

De össze is vonhatók:

data m,n/10,20/, x,y/2*2.5/

A "hagyományos" elnevezéses utasítással a fenti m,n,x,y változókat így írtuk volna:

m = 10 n = 20 x = 2.5 y = 2.5

Ez a data utasítás tömörebb, mint a hagyományos, ezért széles körben elterjedt a használata. Azonban főleg az összevont esetnél, ügyelnünk kell arra, hogy ugyanazon értékeket nem elég egyszer leírni.

A data utasítást elég egyszer, közvetlenül a végrehajtó utasítások előtt, a program elején alkalmaznunk. Ezért ezt a data utasítást általában a főprogramban használják, és nem a subroutinokban.

Természetesen a data utasítással tömböket (vektorokat, mátrixokat) is definiálhatunk. A következő programrészlet biztosítja, hogy a mátrix elemei mind zérusok, mikor a program futtatás megindul.

real A(10,20) data A/ 200 * 0.0/

Néhány fordító automatikusan alkalmazza ezt a tömbökre, de nem mind, ezért ha ragaszkodunk, hogy az elemek mind nullák legyenek, akkor a fenti szintaktikát kell beírnunk. Természetesen zérustól különböző tömb elemeket is megnevezhetünk, akár így:

data A(1,1)/ 12.5/, A(2,1)/ -33.3/, A(2,2)/ 1.0/

de akár így is, kilistázva egy kis tömbben:

integer v(5) real B(2,2) data v/10,20,30,40,50/, B/1.0,-3.7,4.3,0.0/

Többdimenziós esetben oszlopok szerint rendezi és kezeli a tömb elemeit.

A block data utasítás

A data utasítást nem alkalmazhatjuk egy közös tömb/blokk elemeire. Erre egy speciális "subroutine" áll rendelkezésünkre: a block data utasítás. Igazából ez nem egy segédprogram, de hasonló fogalom, mert egy önálló programrészként jelenik meg. Nézzünk rá egy példát is:

block data integer nmax parameter (nmax=20) real v(nmax), alfa, beta common /vector/v,alfa,beta data v/20*100.0/, alfa/3.14/, beta/2.71/ end

A Fortran 77 fordító a data utasításhoz hasonlóan, a block data-t is program elején hajtja végre, mielőtt még a főprogram futtatása elindulna. A block data elhelyezése a forráskód szempontjából közömbös, persze csak addig, amíg nem beágyazott utasításként szerepel vagy a főprogramban vagy egy segédprogramban. Ezért célszerű mindig ezek elejére írnunk.