Fortran
Prozeduren - Funktionen und Unterprogramme
Suche…
Bemerkungen
Funktionen und Unterprogramme zusammen mit Modulen sind die Werkzeuge, um ein Programm in Einheiten zu zerlegen. Dies macht das Programm lesbarer und überschaubarer. Jede dieser Einheiten kann als Teil des Codes betrachtet werden, der idealerweise isoliert zusammengestellt und getestet werden könnte. Die Hauptprogramme können solche Unterprogramme (Funktionen oder Unterprogramme) aufrufen (oder aufrufen), um eine Aufgabe auszuführen.
Funktionen und Unterprogramme unterscheiden sich in folgendem Sinn:
- Funktionen geben ein einzelnes Objekt zurück und ändern normalerweise die Werte ihrer Argumente nicht (dh sie wirken wie eine mathematische Funktion!);
- Subroutinen führen normalerweise eine kompliziertere Aufgabe aus und ändern normalerweise ihre Argumente (falls vorhanden) sowie andere Variablen (z. B. diejenigen, die in dem Modul deklariert sind, das die Subroutine enthält).
Funktionen und Unterprogramme werden kollektiv als Prozeduren bezeichnet . (Im Folgenden wird das Verb verwenden „call“ als Synonym für „aufzurufen“ , auch wenn die Verfahren technisch sein call
ed sind subroutine
s, während die function
S als rechte Seite der Zuweisung angezeigt oder in Ausdrücken.)
Funktionssyntax
Funktionen können mit verschiedenen Arten von Syntax geschrieben werden
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
Funktionen geben Werte über ein Funktionsergebnis zurück . Wenn die Funktionsanweisung keine result
, hat das result
der Funktion denselben Namen wie die Funktion. Mit result
das result
der Funktion das result
. In jedem der ersten beiden obigen Beispiele wird das Funktionsergebnis durch den name
. im dritten durch res
.
Das Funktionsergebnis muss während der Ausführung der Funktion definiert werden.
Funktionen erlauben die Verwendung einiger spezieller Präfixe.
Reine Funktion bedeutet, dass diese Funktion keine Nebenwirkung hat:
pure real function square(x)
real, intent(in) :: x
square = x * x
end function
Die Elementfunktion ist als Skalaroperator definiert, sie kann jedoch mit array als aktuellem Argument aufgerufen werden. In diesem Fall wird die Funktion elementweise angewendet. Wenn nicht das impure
Präfix (eingeführt in Fortran 2008) angegeben wird, ist eine Elementfunktion ebenfalls eine reine Funktion.
elemental real function square(x)
real, intent(in) :: x
square = x * x
end function
Rückgabeanweisung
Die return
Anweisung kann zum Beenden von Funktion und Unterprogramm verwendet werden. Im Gegensatz zu vielen anderen Programmiersprachen wird der Rückgabewert nicht festgelegt.
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
Diese Funktion führt eine iterative Berechnung aus. Wenn der Wert von f
negativ wird, gibt die Funktion den Wert -1000 zurück.
Rekursive Prozeduren
In Fortran müssen Funktionen und Unterprogramme explizit als rekursiv deklariert werden , wenn sie sich direkt oder indirekt erneut aufrufen möchten. Eine rekursive Implementierung der Fibonacci-Serie könnte also folgendermaßen aussehen:
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
Ein anderes Beispiel ist erlaubt, Fakultät zu berechnen:
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
Damit eine Funktion sich selbst rekursiv referenzieren kann, muss ihre Definition das result
. Es ist nicht möglich, dass eine Funktion sowohl recursive
als auch elemental
.
Die Absicht von Dummy-Argumenten
Das intent
Attribut eines Dummy-Arguments in einer Subroutine oder Funktion gibt die beabsichtigte Verwendung an. Die Syntax ist entweder eine von
intent(IN)
intent(OUT)
intent(INOUT)
Betrachten Sie zum Beispiel diese Funktion:
real function f(x)
real, intent(IN) :: x
f = x*x
end function
Der intent(IN)
gibt an, dass das (Nichtzeiger-) Dummy-Argument x
während der gesamten Funktion oder ihrer Initialisierung niemals definiert werden oder undefiniert werden darf. Wenn ein Pointer-Dummy-Argument die Attributintent intent(IN)
, gilt dies für seine Zuordnung.
intent(OUT)
für ein Nicht-Zeiger-Dummy-Argument bedeutet, dass das Dummy-Argument beim Aufruf des Unterprogramms (mit Ausnahme von Komponenten eines abgeleiteten Typs mit Standardinitialisierung) undefiniert wird und während der Ausführung festgelegt wird. Das als Dummy-Argument übergebene tatsächliche Argument muss definierbar sein: Das Übergeben einer benannten Konstante oder eines Literalkonstanten oder eines Ausdrucks ist nicht zulässig.
Ähnlich wie zuvor wird der Zuordnungsstatus des Zeigers undefiniert, wenn ein Zeiger-Dummy-Argument intent(OUT)
. Das eigentliche Argument muss hier eine Zeigervariable sein.
intent(INOUT)
gibt an, dass das tatsächliche Argument definierbar ist und sich sowohl für die Übergabe als auch für die Rückgabe von Daten aus der Prozedur eignet.
Schließlich kann ein Dummy-Argument ohne das intent
Attribut sein. Ein solches Dummy-Argument wird durch das tatsächlich übergebene Argument eingeschränkt.
Zum Beispiel betrachten
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
Das Argument i
kann kein intent
Attribut haben, das beide Unterprogrammaufrufe des Hauptprogramms zulässt.
Prozedur referenzieren
Damit eine Funktion oder ein Unterprogramm nützlich ist, muss darauf verwiesen werden. Ein Unterprogramm wird in einer referenzierten call
- Anweisung
call sub(...)
und eine Funktion innerhalb eines Ausdrucks. Im Gegensatz zu vielen anderen Sprachen bildet ein Ausdruck keine vollständige Anweisung. Daher wird eine Funktionsreferenz häufig in einer Zuweisungsanweisung gesehen oder auf andere Weise verwendet:
x = func(...)
y = 1 + 2*func(...)
Es gibt drei Möglichkeiten, eine referenzierte Prozedur festzulegen:
- als Name einer Prozedur oder eines Prozedurzeigers
- eine Prozedurkomponente eines abgeleiteten Typobjekts
- ein typgebundener Prozedurbindungsname
Der erste kann als gesehen werden
procedure(), pointer :: sub_ptr=>sub
call sub() ! With no argument list the parentheses are optional
call sub_ptr()
end
subroutine sub()
end subroutine
und die letzten beiden 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
Für eine Prozedur mit Dummy-Argumenten erfordert die Referenz entsprechende tatsächliche Argumente, obwohl optionale Dummy-Argumente möglicherweise nicht angegeben werden.
Betrachten Sie die Subroutine
subroutine sub(a, b, c)
integer a, b
integer, optional :: c
end subroutine
Darauf kann auf zwei Arten verwiesen werden
call sub(1, 2, 3) ! Passing to the optional dummy c
call sub(1, 2) ! Not passing to the optional dummy c
Dies ist die sogenannte Positionsreferenzierung : Die eigentlichen Argumente werden basierend auf der Position in den Argumentlisten zugeordnet. Hier ist der Dummy a
mit 1
, b
mit 2
und c
(wenn angegeben) mit 3
verknüpft.
Alternativ kann die Schlüsselwortreferenzierung verwendet werden, wenn für die Prozedur eine explizite Schnittstelle verfügbar ist
call sub(a=1, b=2, c=3)
call sub(a=1, b=2)
das ist das gleiche wie oben.
Bei Schlüsselwörtern können die tatsächlichen Argumente jedoch in beliebiger Reihenfolge angeboten werden
call sub(b=2, c=3, a=1)
call sub(b=2, a=1)
Positions- und Schlüsselwortreferenzierung können beide verwendet werden
call sub(1, c=3, b=2)
solange ein Schlüsselwort für jedes Argument angegeben wird, das dem ersten Auftreten eines Schlüsselworts folgt
call sub(b=2, 1, 3) ! Not valid: all keywords must be specified
Der Wert der Schlüsselwortreferenzierung ist besonders ausgeprägt, wenn es mehrere optionale Dummy-Argumente gibt, wie unten gezeigt, wenn in der obigen Subroutinen-Definition auch b
optional war
call sub(1, c=3) ! Optional b is not passed
Die Argumentlisten für typgebundene Prozeduren oder Komponentenprozedurzeiger mit einem übergebenen Argument werden separat betrachtet.