Fortran
Procedurer - funktioner och subroutiner
Sök…
Anmärkningar
Funktioner och subroutiner , tillsammans med moduler , är verktygen för att dela upp ett program i enheter. Detta gör programmet mer läsbart och hanterbart. Var och en av dessa enheter kan betraktas som en del av koden som helst skulle kunna sammanställas och testas isolerat. Huvudprogrammet kan anropa (eller åberopa) sådana delprogram (funktioner eller subroutiner) för att utföra en uppgift.
Funktioner och subroutiner är olika i följande mening:
- Funktioner returnerar ett enda objekt och - vanligtvis - ändrar inte värdena på dess argument (dvs. de fungerar precis som en matematisk funktion!);
- Subroutiner utför vanligtvis en mer komplicerad uppgift och de ändrar vanligtvis sina argument (om något finns), såväl som andra variabler (t.ex. de som deklareras i modulen som innehåller subroutinen).
Funktioner och subroutiner omfattas gemensamt av procedurer . (I det följande kommer vi att använda verbet "samtal" som synonym för "åkalla" även om tekniskt sett är procedurerna som ska call
upp subroutine
, medan function
s visas som höger sida av uppdraget eller i uttryck.)
Funktionssyntax
Funktioner kan skrivas med flera typer av syntax
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
Funktioner returnerar värden genom ett funktionsresultat . Såvida inte funktionsklaringen har en result
har funktionens resultat samma namn som funktionen. Med result
är funktionsresultatet det som ges av result
. I vart och ett av de två första exemplen ovan ges funktionsresultatet med name
; i den tredje av res
.
Funktionsresultatet måste definieras under körning av funktionen.
Funktioner gör det möjligt att använda vissa speciella prefix.
Ren funktion betyder att denna funktion inte har någon biverkning:
pure real function square(x)
real, intent(in) :: x
square = x * x
end function
Elementarfunktion definieras som skaläroperatör men den kan åberopas med matris som faktiskt argument, i vilket fall funktionen kommer att tillämpas elementärt. Om inte det impure
prefixet (introducerat i Fortran 2008) anges är en elementär funktion också en ren funktion.
elemental real function square(x)
real, intent(in) :: x
square = x * x
end function
Return statement
Den return
uttalande kan användas för att avsluta funktionen och subrutin. Till skillnad från många andra programmeringsspråk används det inte för att ställa in returvärdet.
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
Denna funktion utför en iterativ beräkning. Om värdet på f
blir negativt returnerar funktionen värdet -1000.
Rekursiva förfaranden
I Fortran-funktioner och subroutiner måste deklareras uttryckligen som rekursiva , om de ska kalla sig själva igen, direkt eller indirekt. Således kan en rekursiv implementering av Fibonacci-serien se ut så här:
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
Ett annat exempel är tillåtet att beräkna factorial:
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
För att en funktion ska direkt rekursivt referera till sig själv måste dess definition använda result
. Det är inte möjligt för en funktion att vara både recursive
och elemental
.
Syftet med dummy-argument
intent
för ett dummy-argument i en subroutine eller funktion förklarar dess avsedda användning. Syntaxen är antingen en av
intent(IN)
intent(OUT)
intent(INOUT)
Tänk till exempel på den här funktionen:
real function f(x)
real, intent(IN) :: x
f = x*x
end function
intent(IN)
specificerar att (icke-pekaren) dummy-argumentet x
aldrig får definieras eller bli odefinierat under hela funktionen eller dess initialisering. Om ett pekar-dummy-argument har attributens intent(IN)
, gäller detta dess associering.
intent(OUT)
för ett icke-pekande dummy-argument betyder att dummy-argumentet blir odefinierat vid anrop av delprogrammet (förutom alla komponenter av en härledd typ med standardinitialisering) och ska ställas in under körning. Det faktiska argumentet som skickas som dummy-argument måste vara definierbart: att passera en namngiven eller bokstavlig konstant, eller ett uttryck, är inte tillåtet.
På samma sätt som tidigare, om ett pekare-dummy-argument är intent(OUT)
blir pekarens associeringsstatus odefinierad. Det faktiska argumentet här måste vara en pekvariabel.
intent(INOUT)
anger att det faktiska argumentet är definierbart och är lämpligt för både att skicka in och returnera data från proceduren.
Slutligen kan ett övnings argument vara utan intent
attribut. Ett sådant dummy-argument har dess användning begränsat av det faktiska argumentet som har gått.
Tänk till exempel
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
Argumentet i
kan inte ha något intent
attribut som tillåter båda subroutine samtal i huvudprogrammet.
Hänvisar ett förfarande
För att en funktion eller subrutin ska vara användbar måste den hänvisas. En subroutine hänvisas till i ett call
call sub(...)
och en funktion inom ett uttryck. Till skillnad från på många andra språk bildar ett uttryck inte ett fullständigt uttalande, så en funktionsreferens ses ofta i ett uppdragsuttalande eller används på något annat sätt:
x = func(...)
y = 1 + 2*func(...)
Det finns tre sätt att beteckna en procedur som refereras till:
- som namnet på en procedur eller procedurpekare
- en procedurkomponent för ett härledt typobjekt
- en typbunden procedur som binder namn
Den första kan ses som
procedure(), pointer :: sub_ptr=>sub
call sub() ! With no argument list the parentheses are optional
call sub_ptr()
end
subroutine sub()
end subroutine
och de sista två som
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
För en procedur med dummy-argument kräver referensen motsvarande faktiska argument, även om valfria dummy-argument kanske inte anges.
Tänk på subrutinen
subroutine sub(a, b, c)
integer a, b
integer, optional :: c
end subroutine
Det kan hänvisas till detta på följande två sätt
call sub(1, 2, 3) ! Passing to the optional dummy c
call sub(1, 2) ! Not passing to the optional dummy c
Detta är så kallad positionsreferens : de faktiska argumenten är associerade baserat på positionen i argumentlistorna. Här är dummy a
associerad med 1
, b
med 2
och c
(när det anges) med 3
.
Alternativt kan sökordsreferenser användas när proceduren har ett tydligt gränssnitt tillgängligt
call sub(a=1, b=2, c=3)
call sub(a=1, b=2)
vilket är samma som ovan.
Men med nyckelord kan de faktiska argumenten erbjudas i valfri ordning
call sub(b=2, c=3, a=1)
call sub(b=2, a=1)
Båda hänvisningar till positioner och nyckelord kan användas
call sub(1, c=3, b=2)
så länge ett nyckelord anges för varje argument efter det första nyckelordet visas
call sub(b=2, 1, 3) ! Not valid: all keywords must be specified
Värdet på nyckelordreferenser är särskilt uttalat när det finns flera valfria dummy-argument, som ses nedan om i subroutindefinitionen ovan b
också var valfritt
call sub(1, c=3) ! Optional b is not passed
Argumentlistorna för typbundna procedurer eller komponentprocesspekare med ett godkänt argument beaktas separat.