SUBROUTINE naam ( parameterlijst )
declaraties
statements
END
De statements kunnen executeerbare en comment statements zijn, maar ook
CALL statements en functiereferenties. Een subprogramma wordt
afgesloten door het woord END. Zoals we al gezien hebben geeft
END tijdens executie een return naar het aanroepende programmma.
Voorbeeld:
Stel we hebben drie subroutines, genaamd SUB1, SUB2, SUB3 die we
afhankelijk van de input willen uitvoeren. Het hoofdprogramma
functioneert dan als een ``monitor''. Het volgende is een kompleet,
maar triviaal, FORTRAN programma.
10 CONTINUE
WRITE (6, *) ' GEEF EEN INTEGER WAARDE TUSSEN 1 EN 3: '
READ (5, *, END=20) IPROG
IF (IPROG .EQ. 1) THEN
CALL SUB1
GO TO 10
ELSE IF (IPROG .EQ. 2) THEN
CALL SUB2
GO TO 10
ELSE IF (IPROG .EQ. 3) THEN
CALL SUB3
GO TO 10
ELSE
WRITE (6, *) ' DEZE WAARDE IS FOUT: ', IPROG
GO TO 10
ENDIF
20 END
SUBROUTINE SUB1
WRITE (6, *) ' ENTRY SUB1 '
END
SUBROUTINE SUB2
WRITE (6, *) ' ENTRY SUB2 '
END
SUBROUTINE SUB3
WRITE (6, *) ' ENTRY SUB3 '
END
In dit voorbeeld treffen we de eenvoudigste vorm
van subroutines, nl. subroutines zonder parameters.
We kunnen een subroutine een parameterlijst meegeven, zoals in het
volgende voorbeeld:
DIMENSION A(100)
WRITE (6, *) ' ENTER N <= 100'
READ (5, *) N
DO 10 I=1,N
A(I) = REAL(I)
10 CONTINUE
CALL SUM (A, N, S)
WRITE (6, 600) N,S
600 FORMAT (' SUM OF FIRST ', I3, ' NUMBERS OF A IS ', F5.0)
END
SUBROUTINE SUM (A, N, S)
C A EN N ZIJN INPUT PARAMETERS, S IS EEN OUTPUT PARAMETER.
DIMENSION A(100)
S = 0.
DO 10 I=1,N
S = S + A(I)
10 CONTINUE
END
In dit voorbeeld krijgt de subroutine twee waarden via de parameters
A en N en geeft er één weer terug via parameter S.
In zo'n geval (één waarde terug) is een FUNCTION vaak handig te
gebruiken.
Hetzelfde programma als boven, maar dan in dubbele precisie en
met een function reference, i.p.v. een subroutine call, ziet er als
volgt uit:
DOUBLE PRECISION A(100), SUM
WRITE (6, *) ' ENTER N <= 100'
READ (5, *) N
DO 10 I=1,N
A(I) = DBLE(I)
10 CONTINUE
S = SUM (A, N)
WRITE (6, 600) N, S
600 FORMAT(' SUM OF FIRST ', I3, ' NUMBERS OF A IS ', F5.0)
END
DOUBLE PRECISION FUNCTION SUM (A, N)
C A EN N ZIJN INPUT PARAMETERS, FUNCTIEWAARDE SUM IS HET RESULTAAT
DOUBLE PRECISION A(100)
SUM = 0.D0
DO 10 I=1,N
SUM = SUM + A(I)
10 CONTINUE
END
Merk op dat de naam van de functie (in dit voorbeeld SUM)
een waarde krijgt binnen de functie (aan de linkerkant van een
assignment statement staat). Dit is de (enige) manier om een waarde toe
te kennen aan een functie.
Een functiereferentie kan in het aanroepende programma deel uit maken
van expressies.
Voorbeelden van referenties naar de bovenstaande functie SUM:
S = - SUM(A,N)
IF ( ABS(SUM(A,N)) .LT. 1.D-7 ) GO TO 100
S2 = SUM(A,N)**2
T = 1.D0/SUM(A,N) + B + SQRT(SUM(A,N))
In het geval van een functie moet de functiewaarde van hetzelfde type zijn
in het refererende (sub)programma als in de functie.
Het type van een FUNCTION wordt als volgt gedefinieerd:
type FUNCTION naam (arg1, arg2, )
Dus bijvoorbeeld:
DOUBLE PRECISION FUNCTION INTEGR (F, X1, X2)
LOGICAL FUNCTION TEST (I)
CHARACTER*10 FUNCTION VOORN (NAAM)
INTEGER FUNCTION INDEX (A)
REAL FUNCTION VALUE
Als het type van de functie niet op deze manier gedefinieerd wordt,
wordt de default (integer: I-N, real: A-H, O-Z) aangenomen.
Denk erom dat het type van de functie ook in het aanroepende
programma gedeklareerd moet worden, tenzij de naam ervan met de default klopt!
Functies en subroutines worden onafhankelijk gecompileerd, d.w.z. dat de compiler zich niets herinnert van de compilatie nadat het END statement gepasseerd is. Dit houdt in dat elke variabele die niet het default type heeft in elke functie en subroutine opnieuw gedeklareerd moet worden. Ook zal dezelfde variabele naam in verschillende subprogramma's een verschillende geheugenlocatie aanduiden.
Alle variabelen zijn lokaal, tenzij zij argument van de functie of de subroutine zijn. Als een variabele doorgegeven wordt als een argument, moet het type in aanroepende en aangeroepen programma kloppen. Dit is de verantwoordelijkheid van de programmeur, alweer omdat de compiler niet over de grenzen van subprogramma's heen kan kijken. De naam van een argument hoeft echter niet hetzelfde te zijn.
Voorbeeld:
CHARACTER*1 A
LOGICAL BIT
BIT = .TRUE.
A = 'A'
CALL COMPUT (A)
C HIER HEEFT DE LOGICAL BIT NOG STEEDS DE WAARDE .TRUE.
END
SUBROUTINE COMPUT (ALFA)
C ALFA ADRESSEERT DEZELFDE GEHEUGENLOCATIE ALS A IN HOOFDPROGRAMMA
C DE CHARACTER VARIABELE BIT IN DEZE SUBROUTINE HEEFT NIETS
C TE MAKEN MET DE LOGICAL VARIABELE BIT IN HOOFDPROGRAMMA
CHARACTER*1 BIT, ALFA
C HIER KRIJGT BIT DE WAARDE 'A' (DE WAARDE VAN ALFA):
BIT = ALFA
END
Het grote voordeel van functies en subroutines is dat men
een FORTRAN programma kan stuctureren. Men kan
de subprogramma's onafhankelijk schrijven en testen en ze zo
klein houden dat ze overzichtelijk blijven. Men kan
ook subprogramma's aanroepen die geen deel van het eigen
FORTRAN programma uitmaken, maar ergens in gecompileerde
vorm op schijf staan.
Voorbeelden hiervan zijn de functies die bij FORTRAN horen. De belangrijkste FORTRAN functies zijn:
LOG natuurlijke logarithme
EXP e-macht
ASIN arcsinus
ACOS arccosinus
ATAN arctangens
SIN sinus
COS cosinus
TAN tangens
ABS absolute waarde
SQRT vierkantswortel
REAL maak real van integer
DBLE maak double precision van integer of real
MAX maximum van twee of meer getallen
MIN minimum van twee of meer getallen
Deze functienamen zijn z.g. ``generic'' namen, d.w.z. dat zij
de naam zijn van een aantal verwante functies, namelijk functies die
van elkaar verschillen in hun type. De compiler bepaalt uit de
context welke functie precies bedoeld wordt en roept die aan.
Tot nu toe hebben we steeds voorbeelden gezien waarbij we via END
terugkeerden, dus in het laatste statement van het subprogramma. We
kunnen echter ook eerder terugkeren, met behulp van het executeerbare
statement RETURN. Stel de onderstaande subroutine TASK
heeft drie verschillende taken, en heeft als input parameter de integer
ITASK, die de gewenste taak specificeert. TASK heeft de
volgende schematische vorm:
SUBROUTINE TASK (ITASK)
IMPLICIT DOUBLE PRECISION (A-H, O-Z)
IF (ITASK .EQ. 1 ) THEN
C perform task1
RETURN
ELSE IF (ITASK .EQ. 2 ) THEN
C perform task2
RETURN
ELSE IF (ITASK .EQ. 3 ) THEN
C perform task3
RETURN
ELSE
WRITE (6, *) ' ILLEGAL ITASK, EXECUTION STOPS'
STOP
ENDIF
END
Dit voorbeeld laat ook zien dat we executie overal kunnen
beeindigen waar we willen met behulp van STOP. Dit is handig als
een fout ontdekt wordt tijdens executie.
OPGAVEN:
x = r cos phi sin theta
y = r sin phi sin theta
z = r cos theta
Geef beide coördinaatstellen door als een array.
Denk eraan dat de FORTRAN functies hoeken in radialen verwachten.
Het getal pi kan je berekenen via: PI=ACOS(-1.D0).
p_x = \sqrt{\alpha^5 \over \pi} x \exp^{-\alpha r}
hier is $r$ de lengte van de vector $(x,y,z)$, en $\alpha$ de orbital
exponent. De functie heeft als input parameters $\alpha$ en een array
met $x$, $y$ en $z$.