4. Fält

4.0 Inledning

För att lagra dimensionerade variabler användes fält. En vektor kan lagras i ett fält med rangen 1 och ett omfång som är minst lika stort som antalet element i vektorn, medan en matris kräver rangen 2 och tensorer kan ha ännu högre rang. Ett fält (eng. array) definieras att ha ett mönster (eng. shape) eller en form given av dess antal dimensioner, kallad rang (eng. rank), och omfång (eng. extent) för var och en av dessa. Rangen av ett fält har inget med den matematiska rangen för en matris att göra.

Utrymme för flyttalsvektorn a(i), i = 1, 2, ... , 20, reserveras med satsen

        REAL, DIMENSION(20) :: A
och för flyttalsmatrisen b(i,j), i = 1, 2, ... , 10, j = 1, 2, ... , 10, med satsen
        REAL, DIMENSION(10,10) :: B
dvs fältet har nu rangen 2.

I stället för ordet REAL kan man använda något av CHARACTER, COMPLEX, DOUBLE PRECISION, INTEGER eller LOGICAL, varvid fältet får angiven typ.

Från och med Fortran 77 behöver fältet ej längre börja i position 1, man anger då exempelvis

        INTEGER, DIMENSION(-7:5) :: C
för heltalsvektorn c(-7), c(-6), ..., c(-1), c(0), c(1), ..., c(5) och motsvarande vid högre ordning. Om man vill att fältet skall börja i position ett skriver man till exempel (1:10) eller enklare (10), däremot kan kompileringsfel fås för (:10). I deklarationen av omfång (dimensionen) kan normalt endast konstanter användas (siffror eller PARAMETER-storheter). Vi skall senare i detta kapitel diskutera olika former av dynamisk minnesallokering och i vilka fall som dimensionsgränserna får vara variabler.

Elementen i ett fält lagras i en entydigt bestämd ordning, jämför nedanstående tabell

Rang Deklarerad dimension   Index vid   Plats
                              anrop

1   (j1:k1)                  (s1)      1+(s1-j1)

2   (j1:k1, j2:k2)         (s1, s2)    1+(s1-j1) +(s2-j2)*d1

3   (j1:k1, j2:k2, j3:k3) (s1, s2, s3) 1+(s1-j1) +(s2-j2)*d1
                                        +(s3-j3)*d1*d2
Maximal rang är 7, storheten di = ki-ji+1 anger omfånget (längden) av respektive dimension. Notera att den "sista" di ej ingår i någon formel för beräkning av plats.

Vi tittar nu på ett vektor-fält och ett matris-fält.

        REAL, DIMENSION(-1:8)  :: A
        REAL, DIMENSION(10,10) :: B
        A(2) = B(1,2)
Här identifierar A(2) det fjärde elementet i fältet A, och sättes till värdet av B(1,2), det elfte elementet i fältet B.

Ovanstående formler innebär att ett fält A(I,J) lagras så att först kommer alla element svarande mot att det andra indexet har lägsta värde, sedan alla element med andra index med näst lägsta värde osv. Lagringen av en matris sker därför kolumn för kolumn, medan matematiker oftast tänker sig matriser lagrade rad för rad.

MINNESREGEL I FORTRAN: Första index varierar snabbast!

Titta på en 2*2 matris och en 4*4 matris


                    11  12  13  14

      11  12        21  22  23  24
  A =          B =
      21  22        31  32  33  34

                    41  42  43  44
Dessa är lagrade i fältet A med följande ordning, nämligen 11, 21, 12, 22 och i fältet B med 11, 21, 31, 41, 12, 22, 32, 42, 13, 23, 33, 43, 14, 24, 34, 44. Detta innebär att den 2*2 matris som "sitter i början av B", dvs i övre vänstra hörnet, och som överenstämmer med 2*2 matrisen A, ej är lagrad som de första fyra elementen i fältet B. Man måste därför skilja på den matematiska ordningen på en matris, och hur motsvarande fält är dimensionerat.

I Fortran 90 bör man notera att inte alla fält är lagrade på detta enkla sätt. En möjlighet finns till exempel att som argument vid funktions- eller subrutinanrop använda en fältsektion bestående av vartannat element i ett visst fält. Då kommer "avståndet" mellan elementen att vara dubbelt så stort som normalt. Detta problem kan åtgärdas genom mellanlagring. En ytterligare komplikation uppstår vid High Performance Fortran (HPF, se Appendix 9), nämligen ett behov av att låta elementen i ett fält vara fördelade över de olika processorerna i ett parallellt system.

Alla variabler i Fortran är normalt lokala för varje underprogram. Man kan kommunicera mellan olika underprogram på tre olika sätt, nämligen antingen utnyttjande COMMON eller moduler eller argumentlistan.

Om man överför fält utnyttjande COMMON måste fälten ha samma utseende i alla underprogrammen. Man måste då deklarera dimensionerna med konstanter, och samma konstanter (samma värden) i alla underprogrammen. Begreppet COMMON anses numera föråldrat. Jag återkommer till användning av COMMON i kapitel 13. Begreppet modul kan ersätta en del av funktionaliteten i COMMON, och behandlas i kapitel 14.

Jag skall nu utförligt diskutera det viktiga begreppet överföring av fält mellan huvudprogram, subrutiner och funktioner utnyttjande argument vid anrop. Under Fortran 77 rådde vissa allvarliga begränsningar i dessa möjligheter, men eftersom många gamla program och programbibliotek utnyttjar dessa metoder är kännedom om dessa väsentlig. I de följande avsnitten diskuterar jag därför först möjligheterna i Fortran 77 och sedan de tillkommande faciliteterna i Fortran 90.

4.1 Överföring av fält som argument utnyttjande Fortran 77

Det finns ett flertal olika möjligheter att överföra fält som argument redan i Fortran 77. Jag behandlar dem här med början med den enklaste metoden för att så småningom komma fram till ganska generella metoder. Jag använder dock i nedanstående exempel i övrigt modern programmeringsteknik utnyttjande de nya möjligheterna i Fortran 90.

Den grundläggande begränsningen i Fortran 90 är att i huvudprogrammet (egentligen den överordnade anropande programenheten) måste dimensioneringen ha skett med konstanter och ej med variabler.

4.1.1 Fix dimensionering

Den enklaste metoden är om fältet har identisk (och konstant) dimensionering i de båda aktuella programenheterna, som i följande exempel. Då kan man ha fix dimensionering i de båda programenheterna och bara överföra fältet.
        PROGRAM MAIN
        REAL, DIMENSION(20,10) :: A
! BERÄKNING
        CALL SUB(A)
! BERÄKNING
        END

        SUBROUTINE SUB(B)
        REAL, DIMENSION(20,10) :: B
! BERÄKNING I SUBRUTINEN
        RETURN
        END
Denna metod tillåter ingen som helst flexibilitet. Subrutinen måste passa exakt mot dimensioneringen i den anropande programenheten.

Alternativt kan man utnyttja COMMON med fix dimensionering av fälten. Detta innebär dock ingen fördel, och bör undvikas. Begreppet COMMON behandlas i kapitel 13.

        PROGRAM MAIN
        REAL, DIMENSION(20,10) :: A
        COMMON /ARG/ A
! BERÄKNING
        CALL SUB
! BERÄKNING
        END

        SUBROUTINE SUB
        REAL, DIMENSION(20,10) :: B
        COMMON /ARG/ B
! BERÄKNING I SUBRUTINEN
        RETURN
        END

4.1.2 Variabel dimensionering i subrutinen utnyttjande justerbart fält

Om man utnyttjar argumentöverföring kan man nöja sig med en verklig specifikation av dimensionerna i den anropande programenheten, medan man kan använda variabler som specifikation i det anropade underprogrammet (subrutin eller funktion). Överföringen av dimensionerna måste då ske i argumentlistan, ej via COMMON.
        PROGRAM MAIN
        REAL, DIMENSION(20,10) :: A
! BERÄKNING
        CALL SUB(A,20,10)
! BERÄKNING
        END

        SUBROUTINE SUB(B,N,M)
        REAL, DIMENSION(N,M) :: B
! BERÄKNING I SUBRUTINEN
        RETURN
        END
Denna metod med justerbart fält är mycket användbar, eftersom den innebär att samma subrutin kan utnyttjas vid olika dimensionering hos det verkliga argumentet (vid olika anrop av subrutinen).

4.1.3 Förenklad variabel dimensionering i subrutinen

Eftersom Fortran räknar ut platsen för ett viss element utnyttjande en formel, där omfånget (längden) i den sista dimensionen ej ingår, kan subrutinen skrivas med asterisk som sista dimension, dvs vi kan få en viss förenkling genom att utnyttja vad som kallas antagen dimension (assumed-size array).
        PROGRAM MAIN
        REAL,DIMENSION(20,10) :: A
! BERÄKNING
        CALL SUB(A,20)
! BERÄKNING
        END

        SUBROUTINE SUB(B,N)
        REAL, DIMENSION(N,*) :: B
! BERÄKNING I SUBRUTINEN
        RETURN
        END
Innan asterisken infördes i samband med Fortran 77 "fuskade" man i stället med att ge en etta (1) för den sista dimensioneringen. Båda dessa varianter innebär att den sista dimensioneringen är ospecificerad. Notera dessutom att om man utnyttjar möjligheten i vissa Fortan system till indexkontroll kan detta ej fungera bra vid antagen dimension. Problemet är att varken * eller 1 känner till den verkliga dimensioneringen i anropande programenhet (om inte systemet är mycket avancerat så att det automatiskt överför korrekt dimensioneringsinformation). Metoden med en etta för den sista dimensioneringen fungerar inte alls under de flesta Fortran 90 system!

4.1.4 Variabel "överdimensionering" i subrutinen

En annan metod, som även den utnyttjar att Fortran använder en väldefinierad formel för att bestämma platsen för ett fältelement, användes ofta i samband med matriser i programbibliotek. Metoden handlar dels om att använda begreppet ledande dimension, dels att låta dimensioneringen ibland vara större än vad som är matematiskt berättigat. Vi inskränker diskussionen till vektorer och matriser, motsvarande gäller vid högre ordning. Vektorer och matriser lagras i endimensionella respektive tvådimensionella fält. Dessa fält måste ha minst en dimension (respektive två dimensioner) som svarar mot den (de) matematiska, men inget hindrar att fälten har deklarerats med större dimension. För en vektor räcker det att motsvarande fält rymmer den matematiska vektorn, för en matris måste dessutom den första dimensioneringsgränsen vara känd, den så kallade ledande dimensionen.

Följande subrutin multiplicerar en matris C med en vektor V, den enda dimensioneringsinformation som måste överföras är den ledande dimension av det fält som innehåller matrisen C. Notera att vi här måste skilja på matematisk dimensionering av vektorer och matriser gentemot programmeringsteknisk dimensionering av fält som skall rymma dessa.

        SUBROUTINE MATVEK(C, V, W, N, M, LED_DIM_C)
        INTEGER :: N, M, LED_DIM_C
        REAL, DIMENSION(*) :: V, W
        REAL, DIMENSION(LED_DIM_C,*) :: C

! Beräknar W som produkten av C med V, 
! där C är en N gånger M matris i fältet C 
! med första dimensionen LED_DIM_C.
! Vektorn V antas ha längden M.
! Vektorn W antas ha längden N.

! Lokala variabler

        INTEGER :: I, J

        DO I = 1, N         ! Nollställning av produkten
           W(I) = 0.0
        END DO

        DO J = 1, M         ! Beräkning av produkten
           DO I = 1, N
              W(I) = W(I) + C(I,J)*V(J)
           END DO
        END DO
        RETURN
        END
Notera att MATVEK kräver dels rad- och kolumn-dimensioneringen av matrisen C (matematiska begrepp, storheterna N och M) och dels rad-dimensioneringen av fältet C (datatekniskt begrepp, storheten LED_DIM_C). Notera även att ingen automatisk kontroll av dimensioneringen sker i subrutinen, utan måste läggas in explicit i huvudprogrammet.

Ett tillhörande anropande program kan se ut på följande sätt. Här måste således matriser och vektorer (som fält) ges explicita dimensioneringar.

        INTEGER IDIM, JDIM
        PARAMETER (IDIM=50, JDIM=40)
        INTEGER N, M
        REAL,     DIMENSION(IDIM,JDIM)      :: A
        REAL,     DIMENSION(JDIM) :: X
        REAL,     DIMENSION(IDIM) :: Y

        WRITE(*,*) ' Ge dimensionen för vektorn X '
        READ(*,*) M
        WRITE(*,*) ' Ge dimensionen för vektorn Y '
        READ(*,*) N
        IF ( N < 1 .OR. N > IDIM .OR. &
             M < 1 .OR. M > JDIM ) THEN
                WRITE(*,*) ' Felaktig dimensionering '
        ELSE
!   Bestämning av vektorn X och matrisen A
!   bör ske här.
                CALL MATVEK(A, X, Y, N, M, IDIM)
                WRITE(*,*) ' Vektorn Y = AX '
                WRITE(*,*) (Y(I), I = 1, N)
        END IF
        STOP 
        END

4.1.5 "Överdimensionering" i huvudprogrammet

Med överdimensionering menar jag att man explicit använder ett större omfång (antal element i en viss dimension) än som är sakligt motiverat. På detta sätt kan ett program användas av alla storlekar på ett problem upp till och med en viss högsta gräns.

En variant av föregående metod innebär att lagringsutrymme för aktuell matris skapas i huvudprogrammet, men att matrisen aldrig användes i huvudprogrammet utan bara i subrutiner och funktioner. Metoden innebär att matrisen aldrig är tillgänglig på ett normalt sätt i huvudprogrammet, och förutsätter därför att den ej heller användes där, ej ens för utmatning. Däremot måste matrisens matematiska dimension bestämmas i huvudprogrammet, eller i en speciell subrutin, innan anrop av någon av de subrutiner som innehåller aktuell matris kan ske.

        PROGRAM MAIN
        INTEGER :: N
        REAL, DIMENSION(20,20) :: A
        CALL SUBN(N)
        CALL SUB1(A,N)
        CALL SUB2(A,N)
        CALL SUB3(A,N)
        END

        SUBROUTINE SUBN(N)
        INTEGER :: N
        DO
          WRITE(*,*) ' Ge aktuell dimension '
          READ (*,*) N
          IF ( N < 1 .OR. N > 20 ) THEN
                WRITE(*,*) ' Felaktig dimension '
          ELSE
                EXIT
          END IF
        END DO
        END

        SUBROUTINE SUB1(B,M)
        REAL, DIMENSION(M,M) :: B
! BERÄKNING I SUBRUTINEN
        RETURN
        END

        SUBROUTINE SUB2(C,L)
        REAL, DIMENSION(L,L) :: C
! BERÄKNING I SUBRUTINEN
        RETURN
        END

        SUBROUTINE SUB3(D,K)
        REAL, DIMENSION(K,K) :: D
! BERÄKNING I SUBRUTINEN
        RETURN
        END
I subrutinen SUBN har satsen EXIT den funktionen att den vid ett acceptabelt värde på dimensionen N avbryter den "eviga" slingan. Subrutinen ger då återhopp till huvudprogrammet.

Jag upprepar att matrisen A är lagrad på ett onormalt sätt i huvudprogrammet (jämfört med lagringen i subrutinerna), om inte N råkar vara just 20. Utnyttjande bara första index vid beräkningen, dvs A(i+(j-1)*N, 1), kan man dock få fram rätt värde på elementet i den i-te raden och den j-te kolumnen. Däremot ger A(i,j) fel värde, nämligen uträknat som A(i+(j-1)*20, 1).

4.2 Överföring av fält som argument utnyttjande Fortran 90

Det finns ett flertal olika tillkommande möjligheter att överföra fält som argument i Fortran 90. Endast den första av de tillkommande metoderna är dock enkel.

4.2.1 Automatiskt fält

Ett automatiskt fält, "automatic array", är mycket likt fallet med variabel dimensionering i subrutinen (avsnitt 4.1.2). Det är dock en mycket väsentlig skillnad i att med ett automatisk fält överföres inget fält från en rutin till en annan, utan ett lokalt fält (arbetsutrymme) skapas. I Fortran 77 där dynamisk minnesallokering saknades var man i stället tvungen att överföra arbetsareor i argumentlistan, varför i nedanstående exempel även X måste vara med i argumentlistan (och vara allokerat i anropande programenhet).
        PROGRAM HUVUD
        INTEGER :: N, K
        N = 3
        K = 17
        CALL SUB(N, K, 2*K+N*N)
        END

        SUBROUTINE SUB (I, J, K)
        INTEGER :: I, J, K
        REAL, DIMENSION (I, J, K) :: X
        Inne i subrutinen kan fältet X användas
        RETURN
        END
Dimensioneringen för X hämtas från heltalen i det anropande programmet. Automatiskt fält är mycket praktiskt för arbetsareor i subrutiner och funktioner. De skapas automatiskt (dynamisk minnesallokering) och försvinner likaså automatiskt vid uthopp ur programenheten. Arbetsareor vid utnyttjande av programbibliotek var tidigare en stor administrativ börda vid programmeringen.

4.2.2 Antaget mönster hos ett fält

Antaget mönster, "assumed-shape array", är ett mycket kraftfullt och användbart begrepp. Lagringen definieras i den anropande proceduren, där även allokering sker, och i den anropade programenheten behöver endast typ, rang och namn ges. Dock krävs ett explicit gränssnitt i den anropande programenheten för att överföra dimensioneringsinformationen. Det hela kan se ut som följer, i exemplet kan fältet B från huvudprogrammet användas under namnet A i subrutinen, där inga dimensioneringsgränser getts.

Gränssnittet har till uppgift att tala om för systemet att dimensioneringsinformationen i anropande programenhet skall överföras automatiskt till den anropade programenheten. Detta sker medelst INTERFACE.

        PROGRAM HUVUD

        INTERFACE
                SUBROUTINE SUB(A)
                REAL, DIMENSION (:,:,:) :: A
                END SUBROUTINE SUB
        END INTERFACE

        REAL, DIMENSION(1:20,1:12,-3:7) :: B
        ...
        CALL SUB(B)
        ...
        END PROGRAM HUVUD

        SUBROUTINE SUB (A)
        REAL, DIMENSION(:, :, :) :: A
        ...
        END SUBROUTINE SUB

4.3 Dynamisk minneshantering

Det finns fyra olika sätt att göra dynamisk minnesallokering i Fortran 90.

I Fortran 77 kan dynamisk minnesallokering egentligen ej ske, men den simuleras ibland genom att utrymme allokeras redan i den anropande programenheten, och både fältnamn och erforderlig dimensionering finns med i anropet, justerbart fält, avsnitt 4.1.2. En förenklad variant är där den sista dimensioneringen ges med en * i deklarationen, antagen dimension, avsnitt 4.1.3.

Nu tillkommer, förutom de redan diskuterade automatiskt fält, avsnitt 4.2.1, och antaget mönster, avsnitt 4.2.2, de båda ytterligare möjligheterna allokerbart fält och användning av fält utnyttjande pekare.

4.3.1 Allokerbart fält

Den enklaste metoden att göra dynamisk minnesallokering är att använda ett allokerbart fält, "allocatable array", dvs att med satserna ALLOCATE och DEALLOCATE erhålla respektive återlämna lagringsutrymme för ett fält vars typ, rang och namn (och andra attribut) tidigare har deklarerats. Notera att båda dessa satser kräver att fältnamnet ges inom parentes, vid allokering skall det dessutom förses med explicit dimensioneringsinformation.

En ytterligare förutsättning är att aktuellt fält deklarerats med attributet ALLOCATABLE, vilket talar om för systemet att dynamisk minnesallokering kommer att ske.

        REAL, DIMENSION(:), ALLOCATABLE :: X
        ...
        ALLOCATE(X(N:M)) ! N och M är heltalsuttryck
                         ! Ge båda gränserna eller bara
                         ! den övre och då utan kolon!
        ...
        X(J) = Q
        CALL SUB(X)
        ...
        DEALLOCATE (X)
        ...
        END
Deallokering av lokala fält förekommer automatiskt i en subrutin eller funktion (om ej attributet SAVE getts) när man når RETURN eller END.

4.3.2 Allokering av fält med pekare

Pekare diskuteras närmare i kapitel 12, men tillämpningen på allokering av fält är så pass enkel att den kan ges redan nu. Ett fält som skall allokeras med hjälp av pekare måste vid deklarationen ges attributet POINTER för pekare. Vid lämpligt tillfälle sker sedan allokering på vanligt sätt med kommandot ALLOCATE. Skillnaden mellan de båda metoderna är således att den första kräver attributet ALLOCATABLE och den andra attributet POINTER.

För att kunna deklarera med pekare i huvudprogrammet och sedan allokera ett utrymme i subrutinen krävs användning av ett gränssnitt eller INTERFACE i huvudprogrammet.

På detta sätt erhålles i nedanstående exempel en dynamisk minnesallokering av vektorn B i subrutinen, och den kan även användas som vektorn A i huvudprogrammet. Storleken på vektorn bestäms i subrutinen. Gränssnittet är i huvudsak en upprepning av deklarationen i subrutinen. Det har till uppgift att informera huvudprogrammet om att verklig dimensioneringsinformation kan erhållas ur subrutinen.

Detta är en bra metod att föra en dimension uppåt i anropskedjan. Man kan naturligtvis i stället "fuska" genom att ha en subrutin som bestämmer dimensionen, hoppa tillbaks till huvudprogrammet och där göra en allokering av ett ALLOCATABLE fält, för att därefter anropa en annan subrutin som kan utnyttja det nu skapade fältet.

        PROGRAM HUVUD

        INTERFACE
                SUBROUTINE SUB(B)
                REAL, DIMENSION (:), POINTER :: B
                END SUBROUTINE SUB
        END INTERFACE

        INTEGER :: N
        REAL, DIMENSION (:), POINTER :: A
!   Här har vektorn A ännu ej fått någon dimensionering!
        CALL SUB(A)
!   Använd nu vektorn A, den har nu fått dimensionering
!   och även tilldelats värden i subrutinen SUB
        N = SIZE(A)         ! N är nu dimensionen av A
        STOP
        END PROGRAM HUVUD

        SUBROUTINE SUB(B)
        REAL, DIMENSION (:), POINTER :: B
        INTEGER :: I, M
        WRITE(*,*) " Tilldela nu en dimension till vektorn"
        READ(*,*) M
        IF (M < 1 ) M = 1
        ALLOCATE (B(M))  
        DO I = 1, M
           B(I) = 17.0*I + 3.0*I**2 - 1.0/I
        END DO
        RETURN
        END SUBROUTINE SUB      
En alternativ metod att föra dimensionering uppåt i anropskedjan är användning av en modul med ett allokerat och sparat SAVEd fält. Ett enkelt exempel på detta förfarande för en vektor finns här.

	MODULE DYNA
	IMPLICIT NONE
	REAL, DIMENSION(:), ALLOCATABLE, SAVE :: ARBETE
	END MODULE DYNA

	PROGRAM TEST_AV_DYNAMIK
	USE DYNA
	IMPLICIT NONE
	PRINT *, 'MAIN'
	CALL SUB1
	CALL SUB2
	PRINT *, 'MAIN'
	END PROGRAM TEST_AV_DYNAMIK
	
	SUBROUTINE SUB1
	USE DYNA
	IMPLICIT NONE
!	Storleken av vektorn ARBETE bestäms här
	INTEGER :: I
	REAL, DIMENSION(5) :: A, B
	PRINT *, 'SUB1'
        A = 1.0
	B = (/ (3.0, I = 1, 5) /)
	ALLOCATE ( ARBETE(SIZE(B)) )
	ARBETE = A
        WRITE(*,*) A
        WRITE(*,*) B
        WRITE(*,*) ARBETE
	END SUBROUTINE SUB1
	
	SUBROUTINE SUB2
	USE DYNA
	IMPLICIT NONE
!	Vektorn ARBETE används här
	REAL :: B
	REAL, DIMENSION(:), ALLOCATABLE :: A
	PRINT *, 'SUB2'
	ALLOCATE ( A(SIZE(ARBETE)) )
        A = 2.*ARBETE
	B = SUM(ARBETE)
	ARBETE = A
        WRITE(*,*) A
        WRITE(*,*) B
        WRITE(*,*) ARBETE
	END SUBROUTINE SUB2

4.4 Fältoperationer

Redan i Fortran 77 fanns det viss möjlighet att operera på ett helt fält utan att behöva specificera dessa element för element. Detta kunde dock bara utnyttjas vid in- och utmatning. En hel matris kan exempelvis skrivas ut med följande kommando,
        REAL, DIMENSION(10,10) :: MATRIS
        WRITE(*,*) MATRIS
vilket är mycket effektivare, både vad gäller tidsåtgång och erforderligt lagringsutrymme (om skrivningen i stället sker till fil), jämfört med det explicita anropet av varje element.
        REAL, DIMENSION(10,10) :: MATRIS
        DO I = 1, 10
           DO J = 1, 10
              WRITE(*,*) MATRIS(I,J)
           END DO
        END DO
eller, med en implicit slinga för kolumnerna, varvid varje rad av matrsen skrives ut på en rad på "papperet". I ovanstående exempel kommer i stället varje element på egen rad.
        REAL, DIMENSION(10,10) :: MATRIS
        DO I = 1, 10
           WRITE(*,*) (MATRIS(I,J), J = 1, 10)
        END DO
Ovanstående kan enklare skrivas
        REAL, DIMENSION(10,10) :: MATRIS
        DO I = 1, 10
           WRITE(*,*) MATRIS(I,:)
        END DO

4.4.1 Enkla fältoperationer

Ett fält (eng. array) definieras att ha ett mönster (eng. shape) given av dess antal dimensioner, rang (eng. rank) och omfång (eng. extent) för var och en av dessa. Två fält överensstämmer om de har samma mönster. Man kan då utföra fältuttryck (eng. array assignment). Operationer sker normalt på element för element bas! De elementära funktionerna fungerar således på detta sätt, element för element, i Fortran.
        REAL, DIMENSION(5,20)    :: X, Y
        REAL, DIMENSION(-2:2,20) :: Z
        :
        Z = 4.0*SIN(Y)*SQRT(X)
Vi kanske här vill skydda oss för negativa element i X. Detta sker genom
        WHERE ( X >= 0.0 )
                Z = 4.0*SIN(Y)*SQRT(X)
        ELSEWHERE
                Z = 0.0
        END WHERE
Notera att ELSEWHERE måste vara i ett ord!

Med fältsektion menas en del av ett fält. Om fältet A är deklarerat med

        REAL, DIMENSION(-4:0,7) :: A
så väljer A(-3,:) ut hela den andra raden, medan A(0:-4:-2, 1:7:2) väljer i omvänd ordning ut vartannat element i varannan kolumn. Liksom variabler kan bilda fält, så kan även konstanter det.
        REAL, DIMENSION(6) :: B
        REAL, DIMENSION(2,3) :: C
        B = (/ 1, 1, 2, 3, 5, 8 /)
        C = RESHAPE( B, (/ 2,3 /) )
där det första argumentet till den inbyggda funktionen RESHAPE ger värdena och det andra argumentet ger det nya mönstret. Ytterligare två argument finns som möjliga till denna funktion.

I följande mycket enkla exempel visar jag hur man kan tilldela matriser med satser av typ

     B = A
utnyttja den inbyggda matrismultiplikationen MATMUL (denna multiplicerar inte element för element utan efter reglerna för matrismultiplikation) och fältadderaren SUM (som adderar samtliga element i fältet), samt utnyttja fältsektioner (i exemplet av typ vektorer).
PROGRAM FALT
        IMPLICIT NONE
        INTEGER                 :: I, J
        REAL, DIMENSION (4,4)     :: A, B, C, D, E
        DO I = 1, 4         ! Beräkna en test matris.
                DO J = 1, 4
                        A(I,J) = (I-1.2)**J
                END DO
        END DO
        B = A*A           ! Element för element multiplikation.
        CALL SKRIV(A,4) 
        CALL SKRIV(B,4)
        C = MATMUL(A,B)   ! Inbyggd matris-multiplikation.
        DO I = 1, 4       ! Explicit matris-multiplikation
                          ! utnyttjande fältsektion för
                          ! den inre slingan.
                DO J = 1, 4
                        D(I,J) = SUM( A(I,:)*B(:,J) )
                END DO
        END DO
        CALL SKRIV(C,4)
        CALL SKRIV(D,4)
        E = C - D   ! Jämförelse av de två metoderna.
        CALL SKRIV(E,4)
END PROGRAM FALT

SUBROUTINE SKRIV(FALT,N)
        Generell rutin för utskrift av en flyttalsmatris.
        IMPLICIT NONE
        INTEGER                 :: N, I
        REAL, DIMENSION (N,N)   :: FALT
        DO I = 1, N
                WRITE(*,'(5E15.6)') FALT(I,:) 
        ! Samtliga värden i matrisens i:te rad skrives ut, 
        ! med (högst) fem värden per utskriftsrad).
        END DO
        WRITE(*,*)                ! Skriv en blank rad.
        END SUBROUTINE SKRIV
END SUBROUTINE SKRIV

Övning.

(4.1) Skriv en rutin för lösning av ett linjärt ekvationssystem, utnyttjande Gausselimination med partiell pivotering.
Lösning.

Grunder i Fortran 90 Innehåll Funktioner och subrutiner


Senast modifierad: 26 juli 1999
boein@nsc.liu.se