11. Tömbök a segédprogramokban

A Fortran szubprogramok meghívásának elvi alapja a call by reference. Ez azt jelenti, hogy a hívó paraméterek nem másolódnak a meghivanandó segédprogramba, hanem e helyett a paraméretek (váltózók) memóriacimjei kerülnek továbbításra. Tömbökkel programozva , ezzel sok memóriahelyet megspórolhatunk. Nincs szükség plussz tárolási helyre, mert a subroutine is, meg a hívó program is ugyanazon memória felületen dolgozik. Egy programozónak errõl is tudnia kell, és eszerint is kell mérlegelnie.

Lehetséges lokális tömbök definiálása a Fortran szubprogramokban, de nem ez a jellemzõ. Ehelyett inkább az összes tömböt és dimenziójukatm már a fõprogramban deklaráljuk, és ezekre alkalmazzuk a segédprogramokat.

Változó hosszúságú tömbök

Az egyik alapvetõ vektoroperátor a saxpy . Ez az alábbi kifejezést jelenti:
      y := alpha*x + y
ahol alpha skalár, de x és y vektor. Nézzünk egy egyszerûbb subroutine-t, felhasználva a fentit::
      subroutine saxpy (n, alpha, x, y)
      integer n
      real alpha, x(*), y(*)
c
c Saxpy: Szamold ki y := alpha*x + y,
c ahol x és y n hosszusagu vektorok 
c
c lokalis valtozok
      integer i
c
      do 10 i = 1, n
         y(i) = alpha*x(i) + y(i)
   10 continue
c
      return
      end
Az újdonságot a deklarációban megjelenõ csillagok jelentik: x(*) és y(*). Ezzel a jelöléssel az x és y vektorunk hossza tetszõleges lehet. Ennek elõnye, hogy ugyanazon segédprogramokat használhatjuk a különféle hosszúságú vektorokra. Utalva arra, hogy a Fortran call-by-reference típusú hivatkozáson alkalmazza, nem szükséges további memóriahelyeket lefoglalni, a segédprogram is a hívó programban definiált tömb elemein dolgozik.A programozó felelõssége az x és y vektorok hosszának helyes megválasztása, azaz hogy a program semelyik részén se forduljon elõ a vektor nem létezö elemére (megengedett elemszámnál nagyobb értékû helyre) való hivatkozás. Ennek elmulasztása gyakran visszatérõ hibának tûnik.

Így definiálhatunk a tömböket :

      real x(n), y(n)
A legtöbb programozó inkább a csillagos x(*) jelölést kedveli, hiszen nem mindig tudni elõre, hogy milyen hosszúságú vektorok kellenek majd. Néhány régebbi Fortran 77 programban ilyen deklarációt is láthatunk:
      real x(1), y(1)
Megtévesztõ lehet, de ez a jelölés akkor is helyes, ha a tömb mérete nagyobb, mint 1. Lehetõleg kerüljük e jelölés használatát.

Tömbök részleteinek átvitele

Segédprogramot kívánunk írni egy mátrix és egy vektor összeszorzására. Két módszer is lehetséges, az egyik beépített programokat alkalmaz, a másik a fenti saxphy kódot használja. Nézzük most a második esetet, melynek a formája:
      subroutine matvec (m, n, A, lda, x, y)
      integer m, n, lda
      real x(*), y(*), A(lda,*)
c
c szamold ki: y = A*x, ahol A egy (m x n) matrix 
c Az A fodimenzioja lda
c
c Lokalis valtozok
      integer i, j
      
c Induljon y
      do 10 i = 1, m
         y(i) = 0.0
   10 continue

c Matrix-vektor szorzas eredmenye a saxpy segitsegevel A oszlopaira
c Fontos, az egyes oszlopk hossza m es nem n!
      do 20 j = 1, n
         call saxpy (m, x(j), A(1,j), y)
   20 continue

      return
      end
Néhány megjegyzést kell tennünk. A mátrix méretét (itt n és m) általánosan is megválaszthatjuk a csillagos kóddal, de a fõdimenziót továbbra is pontosan kell definiálni. Miért? Mert a (máshol változtatható méretre vonatkozó) * jelölés ebben az esetben a tömb utolsó dimenziójára alkalmazható. Erre magyarázatot a Fortran 77 sokdimenziós tömbtárolási mechanizmusa adhat (lsd a tömbökrõl szóló fejezetet)

Amikor kiszámítjuk a saxpy operátorral az y = A*x by értéket, szükségünk van A oszlopainak értékeire is. Az A mátrix j-edik oszlopa A(1:m,j). Azonban a Fortran 77 nem tudja kezelni ezt az összetett indexezést (a Fortran 90 már igen!). Ezért szükségünk van egy közelítésre, a mutatóvektorra, amivel az oszlop elsõ elemére A(1,j) hivatkozunk. (nem pontos a fogalom, de a megértést segítheti). Tudjuk, hogy a következõ memóriahelyeken, ezen oszlop elemei lesznek. A saxpy segédprogram az A(1,j)-t egy vektor elsõ elemének fogja kezelni, mit sem tudva arról, hogy ebben az esetben ez a vektor egy mátrix oszlopát jelenti.

Végül azt is meg kell jegyeznünk, hogy a konvenció alapján a mátrixok m sorból és n oszlopból állnak. Az i indexet sorindexként (1-tõl m-ig), a j indexet oszlopindexként (1-tõl n-ig) használjuk. A legtöbb lineáris algebrás számításra írt Fortran-program ezeket a jelöléseket használja, ami megkönnyíti a programszöveg olvasását.

Különbözõ dimenziók

Sokszor megéri az egydimenziós tömböt kétdimenziósként kezelni vagy fordítva. Az dimenziók közti "átváltás" elég könnyû, sõt sokak szerint túl könnyû.

Nézzünk egy könnyen érthetõ példát. A másik alapvetõ vektromûvelet a nyújtás (=skale), amikor a vektor minden elemét egy konstans számmal megszorozzuk. Ez programnyelven így szól:

      subroutine scale(n, alpha, x)
      integer n
      real alpha, x(*)
c
c Lokalis valtozok
      integer i

      do 10 i = 1, n
         x(i) = alpha * x(i)
   10 continue

      return
      end
Miután megkaptuk az m x n -es mátrixunkat, meg szerenénk "nyújtani". Ahelyett, hogy erre is írnánk egy másik segédprogramot, elég ezt a mátrixok vektorként kezelve megnyújtani, alkalmazva a scale subroutine-t. Kézenfekvõ az alábbi metódus:
      integer m, n
      parameter (m=10, n=20)
      real alpha, A(m,n)

c Nehany utasitassal defininalni az A-t...

c Most megnyujtjuk A-t
      call scale(m*n, alpha, A)
Fontos megjegyezni, hogy a fenti példa mûködik, mert az eredetileg deklarált dimenziója A-nak megegyezik, azzal a mátrixéval, amiben éppen (számítás közben) tároljuk az A-t. Ha ez nem így van, akkor a fenti metódus nem jó. Rendszerint e kétfajta mátrix dimenzió nem egyezik meg, ilyenkor körültekintõen kell eljárnunk.Ebben az esetben a programunk így lesz korrekt:
      subroutine mscale(m, n, alpha, A, lda)
      integer m, n, lda
      real alpha, A(lda,*)
c
c Lokalis valtozok
      integer j

      do 10 j = 1, n
         call scale(m, alpha, A(1,j) )
   10 continue

      return
      end
Így már minden esetben mûködõképes lesz a programunk: a számításhoz szükségtelen sorok és oszlopok (amivel nagyobb az eredeti mátrix, mint az aktuális) elemeihez nem nyúl.

 

Copyright © 1995-7 by Stanford University. All rights reserved.

Fordították: Seres András Tamás és Szalai Szilvia (ELTE-TTK)


[Tovább] [Tartalomjegyzék]