Fortran
Procedures - Functies en subroutines
Zoeken…
Opmerkingen
Functies en subroutines zijn in combinatie met modules de hulpmiddelen om een programma in eenheden op te splitsen. Dit maakt het programma beter leesbaar en beheersbaar. Elk van deze eenheden kan worden beschouwd als onderdeel van de code die, idealiter, afzonderlijk zou kunnen worden gecompileerd en getest. De hoofdprogramma's kunnen dergelijke subprogramma's (functies of subroutines) aanroepen (of aanroepen) om een taak te volbrengen.
Functies en subroutines zijn verschillend in de volgende zin:
- Functies retourneren een enkel object en veranderen meestal de waarden van de argumenten niet (dwz ze werken net als een wiskundige functie!);
- Subroutines voeren meestal een meer gecompliceerde taak uit en wijzigen gewoonlijk hun argumenten (indien aanwezig), evenals andere variabelen (bijv. Die welke zijn gedeclareerd in de module die de subroutine bevat).
Functies en subroutines vallen gezamenlijk onder de naam procedures . (In het volgende zullen we het werkwoord "aanroep" gebruiken als synoniem van "aanroepen", zelfs als technisch de aan te call
procedures subroutine
, terwijl function
als rechterkant van de toewijzing of in uitdrukkingen verschijnen.)
Syntaxis van de functie
Functies kunnen worden geschreven met behulp van verschillende soorten syntaxis
function name()
integer name
name = 42
end function
integer function name()
name = 42
end function
function name() result(res)
integer res
res = 42
end function
Functies retourneren waarden via een functieresultaat . Tenzij de functie-instructie een result
heeft, heeft het result
de functie dezelfde naam als de functie. Met result
het functieresultaat dat gegeven door het result
. In elk van de eerste twee voorbeelden hierboven wordt het functieresultaat gegeven door name
; in de derde door res
.
Het functieresultaat moet worden gedefinieerd tijdens de uitvoering van de functie.
Met functies kunnen enkele speciale voorvoegsels worden gebruikt.
Pure functie betekent dat deze functie geen bijwerking heeft:
pure real function square(x)
real, intent(in) :: x
square = x * x
end function
Elementaire functie wordt gedefinieerd als scalaire operator, maar kan worden opgeroepen met array als actueel argument, in welk geval de functie elementair wordt toegepast. Tenzij het impure
voorvoegsel (geïntroduceerd in Fortran 2008) is opgegeven, is een elementaire functie ook een pure functie.
elemental real function square(x)
real, intent(in) :: x
square = x * x
end function
Retourverklaring
De return
instructie kan worden gebruikt om de functie en subroutine af te sluiten. In tegenstelling tot veel andere programmeertalen wordt het niet gebruikt om de retourwaarde in te stellen.
real function f(x)
real, intent(in) :: x
integer :: i
f = x
do i = 1, 10
f = sqrt(f) - 1.0
if (f < 0) then
f = -1000.
return
end if
end do
end function
Deze functie voert een iteratieve berekening uit. Als de waarde van f
negatief wordt, retourneert de functie waarde -1000.
Recursieve procedures
In Fortran moeten functies en subroutines expliciet als recursief worden verklaard, als ze zichzelf weer direct of indirect moeten noemen. Zo kan een recursieve implementatie van de Fibonacci-serie er zo uitzien:
recursive function fibonacci(term) result(fibo)
integer, intent(in) :: term
integer :: fibo
if (term <= 1) then
fibo = 1
else
fibo = fibonacci(term-1) + fibonacci(term-2)
end if
end function fibonacci
Een ander voorbeeld is toegestaan om faculteit te berekenen:
recursive function factorial(n) result(f)
integer :: f
integer, intent(in) :: n
if(n == 0) then
f = 1
else
f = n * f(n-1)
end if
end function factorial
Opdat een functie zichzelf recursief zou kunnen verwijzen, moet de definitie het result
achtervoegsel gebruiken. Het is niet mogelijk dat een functie zowel recursive
als elemental
.
De bedoeling van dummyargumenten
Het kenmerk intent
van een dummy-argument in een subroutine of functie verklaart het beoogde gebruik. De syntaxis is er een van
intent(IN)
intent(OUT)
intent(INOUT)
Overweeg bijvoorbeeld deze functie:
real function f(x)
real, intent(IN) :: x
f = x*x
end function
De intent(IN)
specificeert dat de (niet-pointer) dummy argument x
niet kan worden bepaald of worden undefined gehele functie of de initialisatie. Als een pointer dummy-argument het kenmerk intent(IN)
, is dit van toepassing op de associatie.
intent(OUT)
voor een niet-pointer dummy-argument betekent dat dummy-argument ongedefinieerd wordt bij aanroep van het subprogramma (behalve voor componenten van een afgeleid type met standaardinitialisatie) en moet worden ingesteld tijdens de uitvoering. Het feitelijke argument dat als dummyargument wordt doorgegeven, moet definieerbaar zijn: het doorgeven van een benoemde of letterlijke constante, of een uitdrukking, is niet toegestaan.
Op dezelfde manier als hiervoor, wordt de associatiestatus van de aanwijzer ongedefinieerd als een pointer dummy-argument intent(OUT)
is. Het eigenlijke argument hier moet een pointervariabele zijn.
intent(INOUT)
geeft aan dat het eigenlijke argument definieerbaar is en geschikt is voor zowel het doorgeven als retourneren van gegevens uit de procedure.
Ten slotte kan een dummyargument zonder het kenmerk intent
zijn. Het gebruik van zo'n dummyargument wordt beperkt door het feitelijk doorgegeven argument.
Overweeg bijvoorbeeld
integer :: i = 0
call sub(i, .TRUE.)
call sub(1, .FALSE.)
end
subroutine sub(i, update)
integer i
logical, intent(in) :: update
if (update) i = i+1
end subroutine
Het argument i
kan geen intent
kenmerk hebben dat beide subroutine-aanroepen van het hoofdprogramma toestaat.
Verwijzen naar een procedure
Om een functie of subroutine nuttig te maken, moet hiernaar worden verwezen. Naar een subroutine wordt verwezen in een call
statement
call sub(...)
en een functie binnen een uitdrukking. Anders dan in veel andere talen, vormt een uitdrukking geen volledige instructie, dus een functieverwijzing wordt vaak gezien in een toewijzingsinstructie of op een andere manier gebruikt:
x = func(...)
y = 1 + 2*func(...)
Er zijn drie manieren om een procedure aan te wijzen waarnaar wordt verwezen:
- als de naam van een procedure of procedurewijzer
- een procedurecomponent van een afgeleid type object
- een type gebonden procedure bindende naam
De eerste kan worden gezien als
procedure(), pointer :: sub_ptr=>sub
call sub() ! With no argument list the parentheses are optional
call sub_ptr()
end
subroutine sub()
end subroutine
en de laatste twee als
module mod
type t
procedure(sub), pointer, nopass :: sub_ptr=>sub
contains
procedure, nopass :: sub
end type
contains
subroutine sub()
end subroutine
end module
use mod
type(t) x
call x%sub_ptr() ! Procedure component
call x%sub() ! Binding name
end
Voor een procedure met dummy-argumenten vereist de verwijzing overeenkomstige werkelijke argumenten, hoewel optionele dummy-argumenten mogelijk niet worden gegeven.
Overweeg de subroutine
subroutine sub(a, b, c)
integer a, b
integer, optional :: c
end subroutine
Hiernaar kan op de volgende twee manieren worden verwezen
call sub(1, 2, 3) ! Passing to the optional dummy c
call sub(1, 2) ! Not passing to the optional dummy c
Dit is zogenaamde positiereferentie : de feitelijke argumenten zijn gekoppeld op basis van de positie in de argumentlijsten. Hier wordt de dummy a
geassocieerd met 1
, b
met 2
en c
(indien gespecificeerd) met 3
.
Als alternatief kan trefwoordverwijzing worden gebruikt wanneer voor de procedure een expliciete interface beschikbaar is
call sub(a=1, b=2, c=3)
call sub(a=1, b=2)
die hetzelfde is als hierboven.
Met zoekwoorden kunnen de feitelijke argumenten echter in willekeurige volgorde worden aangeboden
call sub(b=2, c=3, a=1)
call sub(b=2, a=1)
Positionele en trefwoordreferenties kunnen beide worden gebruikt
call sub(1, c=3, b=2)
zolang een trefwoord wordt gegeven voor elk argument na de eerste verschijning van een trefwoord
call sub(b=2, 1, 3) ! Not valid: all keywords must be specified
De waarde van trefwoordverwijzingen is met name uitgesproken wanneer er meerdere optionele dummy-argumenten zijn, zoals hieronder te zien als in de subroutine-definitie hierboven b
ook optioneel was
call sub(1, c=3) ! Optional b is not passed
De argumentlijsten voor typegebonden procedures of componentprocedure-verwijzingen met een doorgegeven argument worden afzonderlijk beschouwd.