Fortran 95 språkfunksjoner - Fortran 95 language features
Dette er en oversikt over Fortran 95 språkfunksjoner . Inkludert er tilleggsfunksjonene i TR-15581: Enhanced Data Type Facilities, som er implementert universelt. Gamle funksjoner som har blitt erstattet av nye er ikke beskrevet - få av de historiske funksjonene brukes i moderne programmer, selv om de fleste har blitt beholdt på språket for å opprettholde bakoverkompatibilitet . Den nåværende standarden er Fortran 2018; mange av de nye funksjonene blir fremdeles implementert i kompilatorer. Tilleggsfunksjonene i Fortran 2003, Fortran 2008 og Fortran 2018 er beskrevet av Metcalf, Reid og Cohen.
Språkelementer
Fortran er ufølsom for store og små bokstaver . Konvensjonen om å skrive Fortran -søkeord med store bokstaver og alle andre navn med små bokstaver er vedtatt i denne artikkelen; unntatt, i kontrast, i input/output -beskrivelsene ( dataoverføring og operasjoner på eksterne filer ).
Grunnleggende
Den grunnleggende komponenten i Fortran -språket er tegnsettet . Medlemmene er
- bokstavene A ... Z og a ... z (som er ekvivalente utenfor en tegnsammenheng)
- tallene 0 ... 9
- understrekningen _
- spesialtegnene
= : + blank - * / ( ) [ ] , . $ ' ! " % & ; < > ?
Tokens som har en syntaktisk betydning for kompilatoren er bygget fra disse komponentene. Det er seks klasser av tokens:
Merkelapp |
123
|
---|---|
Konstant |
123.456789_long
|
Stikkord |
ALLOCATABLE
|
Operatør |
.add.
|
Navn |
solve_equation (opptil 31 tegn, inkludert _)
|
Separator |
/ ( ) (/ /) [ ] , = => : :: ; %
|
Fra tokens, er uttalelser bygget. Disse kan kodes ved hjelp av den nye gratis kildeformen som ikke krever posisjonering i en stiv kolonnestruktur:
FUNCTION string_concat(s1, s2) ! This is a comment
TYPE (string), INTENT(IN) :: s1, s2
TYPE (string) string_concat
string_concat%string_data = s1%string_data(1:s1%length) // &
s2%string_data(1:s2%length) ! This is a continuation
string_concat%length = s1%length + s2%length
END FUNCTION string_concat
Legg merke til de etterfølgende kommentarene og det etterfølgende fortsettelsesmerket. Det kan være 39 fortsettelseslinjer og 132 tegn per linje. Blanks er betydelige. Hvor et token eller tegn konstant er delt på to linjer:
... start_of&
&_name
... 'a very long &
&string'
en ledende &
på den fortsatte linjen er også nødvendig.
Automatisk konvertering av kildeskjema for eksisterende programmer kan utføres av convert.f90 .
Alternativene er
- betydelig blank håndtering;
- innrykk;
- FORTSETT erstattet av END DO;
- navn lagt til underprogrammet END -setning; og
- INTEGER*2 etc. syntaks konvertert.
Egne datatyper
Fortran har fem iboende datatyper : INTEGER
, REAL
, COMPLEX
, LOGICAL
og CHARACTER
. Hver av disse typene kan i tillegg preges av et slag . Kind definerer i utgangspunktet intern representasjon av typen: For de tre numeriske typene definerer den presisjon og rekkevidde, og for de to andre, detaljene for lagringsrepresentasjon. Dermed er det et abstrakt konsept som modellerer grensene for datatypers representasjon; det uttrykkes som medlem av et sett med heltall (f.eks. kan det være {1, 2, 4, 8} for heltall, som angir lagringsbyte), men disse verdiene er ikke spesifisert av standarden og ikke bærbare. For hver type er det en standard type , som brukes hvis ingen art er eksplisitt spesifisert. For hver egen type er det en tilsvarende form for bokstavelig konstant . De numeriske typene INTEGER
og REAL
kan bare signeres (det er ikke noe begrep om tegn for type COMPLEX
).
Bokstavelige konstanter og slag
INTEGER
Heltall bokstavelige konstanter av standardtypen tar formen
1 0 -999 32767 +10
Kind kan defineres som en navngitt konstant. Dersom det ønskede område er ± 10 slag , den bærbare syntaks for å definere den aktuelle slag, two_bytes
er
INTEGER, PARAMETER :: two_bytes = SELECTED_INT_KIND(4)
som tillater påfølgende definisjon av konstanter i skjemaet
-1234_two_bytes +1_two_bytes
Her two_bytes
er typen type parameter; det kan også være en eksplisitt standard heltall bokstavelig konstant, som
-1234_2
men slik bruk er ikke-bærbar.
KIND -funksjonen leverer verdien av en slags type parameter:
KIND(1) KIND(1_two_bytes)
og RANGE
funksjonen leverer det faktiske desimalområdet (så brukeren må gjøre den faktiske tilordningen til byte):
RANGE(1_two_bytes)
I DATA
(initialiserings) utsagn kan også binære (B), oktale (O) og heksadesimale (Z) konstanter brukes (ofte uformelt referert til som "BOZ -konstanter"):
B'01010101' O'01234567' Z'10fa'
EKTE
Det er minst to virkelige typer - standard og en med større presisjon (dette erstatter DOUBLE PRECISION
). SELECTED_REAL_KIND
funksjoner returnerer artnummeret for ønsket rekkevidde og presisjon; for minst 9 desimal siffer med presisjon og et område på 10 −99 til 10 99 , kan det spesifiseres som:
INTEGER, PARAMETER :: long = SELECTED_REAL_KIND(9, 99)
og bokstavene senere spesifisert som
1.7_long
Det er også de iboende funksjonene
KIND(1.7_long) PRECISION(1.7_long) RANGE(1.7_long)
som igjen gir typen type verdi, den faktiske presisjonen (her minst 9) og det faktiske området (her minst 99).
KOMPLEKS
COMPLEX
datatypen er bygget av to heltall eller virkelige komponenter:
(1, 3.7_long)
LOGISK
Det er bare to grunnleggende verdier for logiske konstanter: .TRUE.
og .FALSE.
. Her kan det også være forskjellige typer. Logiske har ikke sine egne snille henvendelsesfunksjoner, men bruker typen som er spesifisert for INTEGER
s; standard slags LOGICAL
er det samme som for INTEGER.
.FALSE. .true._one_byte
og KIND
funksjonen fungerer som forventet:
KIND(.TRUE.)
KARAKTER
Formene for bokstavelige konstanter for CHARACTER
datatype er
'A string' "Another" 'A "quote"' '''''''
(den siste er en tom streng). Ulike typer er tillatt (for eksempel for å skille mellom ASCII- og UNICODE -strenger), men støttes ikke mye av kompilatorer. Igjen er typen verdi gitt av KIND
funksjonen:
KIND('ASCII')
Tallmodell og iboende funksjoner
De numeriske typene er basert på tallmodeller med tilhørende henvendelsesfunksjoner (hvis verdier er uavhengige av verdiene til argumentene deres; argumenter brukes bare for å angi slag). Disse funksjonene er viktige for bærbar numerisk programvare:
DIGITS(X) |
Antall signifikante sifre |
EPSILON(X) |
Nesten ubetydelig sammenlignet med en (ekte) |
HUGE(X) |
Største antall |
MAXEXPONENT(X) |
Maksimal modelleksponent (ekte) |
MINEXPONENT(X) |
Minimum modelleksponent (ekte) |
PRECISION(X) |
Desimal presisjon (ekte, kompleks) |
RADIX(X) |
Basen på modellen |
RANGE(X) |
Desimal eksponentområde |
TINY(X) |
Minste positive tall (ekte) |
Skalarvariabler
Skalar variablene tilsvarer de fem indre Typen er angitt som følger:
INTEGER(KIND=2) :: i
REAL(KIND=long) :: a
COMPLEX :: current
LOGICAL :: Pravda
CHARACTER(LEN=20) :: word
CHARACTER(LEN=2, KIND=Kanji) :: kanji_word
der den valgfrie KIND
parameteren angir en type som ikke er standard, og ::
notasjonen avgrenser typen og attributtene fra variabelnavn (er) og deres valgfrie initialverdier, slik at full variabel spesifikasjon og initialisering kan skrives inn i en setning (i tidligere standarder, attributter og initialisatorer måtte deklareres i flere uttalelser). Selv om det ikke er nødvendig i eksemplene ovenfor (siden det ikke er flere attributter og initialisering), får de fleste Fortran-90-programmerere en vane å bruke det overalt.
LEN=
spesifiser gjelder bare for CHARACTER
s og angir strenglengden (erstatter det eldre *len
skjemaet). De eksplisitte KIND=
og LEN=
spesifisatorene er valgfrie:
CHARACTER(2, Kanji) :: kanji_word
fungerer like bra.
Det er noen andre interessante karaktertrekk. Akkurat som en delstreng som i
CHARACTER(80) :: line
... = line(i:i) ! substring
var tidligere mulig, så nå er delstrengen
'0123456789'(i:i)
Strenger med null lengde er også tillatt:
line(i:i-1) ! zero-length string
Til slutt er det et sett med iboende karakterfunksjoner, eksempler er
ACHAR |
IACHAR (for ASCII -sett)
|
ADJUSTL |
ADJUSTR
|
LEN_TRIM |
INDEX(s1, s2, BACK=.TRUE.)
|
REPEAT |
SCAN (for ett sett)
|
TRIM |
VERIFY (for alle sett)
|
Avledede datatyper
For avledede datatyper må formen for typen først defineres:
TYPE person
CHARACTER(10) name
REAL age
END TYPE person
og deretter kan variabler av den typen defineres:
TYPE(person) you, me
For å velge komponenter av en avledet type, brukes %
kvalifikator:
you%age
Bokstavelige konstanter av avledede typer har formen TypeName(1stComponentLiteral, 2ndComponentLiteral, ...)
:
you = person('Smith', 23.5)
som er kjent som en strukturkonstruktør . Definisjoner kan referere til en tidligere definert type:
TYPE point
REAL x, y
END TYPE point
TYPE triangle
TYPE(point) a, b, c
END TYPE triangle
og for en variabel av typen trekant, som i
TYPE(triangle) t
hver komponent av typen point
er tilgjengelig som
t%a t%b t%c
som igjen har ultimate komponenter av typen real:
t%a%x t%a%y t%b%x etc.
(Vær oppmerksom på at %
kvalifiseringen ble valgt i stedet for dot ( .
) på grunn av potensiell tvetydighet med operatørnotasjon, som .OR.
).
Implisitt og eksplisitt skriving
Med mindre annet er angitt, er alle variabler som begynner med bokstavene I, J, K, L, M og N standarder INTEGER
, og alle andre er standard REAL
; andre datatyper må eksplisitt deklareres. Dette er kjent som implisitt skriving og er en arv fra tidlige FORTRAN -dager. Disse standardene kan overstyres av IMPLICIT TypeName (CharacterRange)
utsagn, som:
IMPLICIT COMPLEX(Z)
IMPLICIT CHARACTER(A-B)
IMPLICIT REAL(C-H,N-Y)
Imidlertid er det en god praksis å eksplisitt skrive inn alle variabler, og dette kan tvinges fram ved å sette inn setningen IMPLICIT NONE
i begynnelsen av hver programenhet.
Matriser
Arrays anses å være variabler i seg selv. Hver matrise er preget av sin type , rangering og form (som definerer omfanget av hver dimensjon). Grenser for hver dimensjon er som standard 1 og størrelse , men vilkårlige grenser kan eksplisitt spesifiseres. DIMENSION
søkeord er valgfritt og anses som et attributt; Hvis den utelates, må matriseformen spesifiseres etter navnet på matrisevariabelen. For eksempel,
REAL:: a(10)
INTEGER, DIMENSION(0:100, -50:50) :: map
erklærer to matriser, rang-1 og rang-2, hvis elementer er i kolonne-stor rekkefølge . Elementer er for eksempel
a(1) a(i*j)
og er skalarer. Abonnementene kan være et vilkårlig heltalsuttrykk.
Seksjoner er deler av matrisevariablene, og er selv matriser:
a(i:j) ! rank one
map(i:j, k:l:m) ! rank two
a(map(i, k:l)) ! vector subscript
a(3:2) ! zero length
Hele matriser og matriseseksjoner er objekter som er verdsatt av matriser. Array-verdsatte konstanter (konstruktører) er tilgjengelige, vedlagt (/ ... /)
:
(/ 1, 2, 3, 4 /)
(/ ( (/ 1, 2, 3 /), i = 1, 4) /)
(/ (i, i = 1, 9, 2) /)
(/ (0, i = 1, 100) /)
(/ (0.1*i, i = 1, 10) /)
ved å bruke en underforstått-DO-loop-notasjon. Fortran 2003 tillater bruk av parenteser:
[1, 2, 3, 4]
og i [([1,2,3], i=1,4)]
stedet for de to første eksemplene ovenfor, støtter mange kompilatorer dette nå. En avledet datatype kan selvfølgelig inneholde matrisekomponenter:
TYPE triplet
REAL, DIMENSION(3) :: vertex
END TYPE triplet
TYPE(triplet), DIMENSION(4) :: t
så det
-
t(2)
er en skalar (en struktur) -
t(2)%vertex
er en matrisekomponent i en skalar
Datainitialisering
Variabler kan gis startverdier som spesifisert i en spesifikasjonserklæring:
REAL, DIMENSION(3) :: a = (/ 0.1, 0.2, 0.3 /)
og en standard initialverdi kan gis til komponenten i en avledet datatype:
TYPE triplet
REAL, DIMENSION(3) :: vertex = 0.0
END TYPE triplet
Når lokale variabler initialiseres innenfor en prosedyre, får de implisitt SAVE -attributtet:
REAL, DIMENSION(3) :: point = (/ 0.0, 1.0, -1.0 /)
Denne erklæringen tilsvarer
REAL, DIMENSION(3), SAVE :: point = (/ 0.0, 1.0, -1.0 /)
for lokale variabler innenfor en underrutine eller funksjon. SAVE -attributtet får lokale variabler til å beholde verdien etter en prosedyresamtale og deretter initialisere variabelen til den lagrede verdien når den returnerer til prosedyren.
PARAMETER -attributt
En navngitt konstant kan spesifiseres direkte ved å legge til PARAMETER
attributtet og de konstante verdiene til en typesetning:
REAL, DIMENSION(3), PARAMETER :: field = (/ 0., 1., 2. /)
TYPE(triplet), PARAMETER :: t = triplet( (/ 0., 0., 0. /) )
DATA -erklæring
Den DATA
setningen kan brukes for skalarene og også for matriser og variablene i avledet type. Det er også den eneste måten å initialisere bare deler av slike objekter, samt å initialisere til binære, oktale eller heksadesimale verdier:
TYPE(triplet) :: t1, t2
DATA t1/triplet( (/ 0., 1., 2. /) )/, t2%vertex(1)/123./
DATA array(1:64) / 64*0/
DATA i, j, k/ B'01010101', O'77', Z'ff'/
Initialiseringsuttrykk
Verdiene som brukes i DATA
og PARAMETER
setninger, eller med disse attributtene, er konstante uttrykk som kan inneholde referanser til: array- og strukturkonstruktorer, elementære iboende funksjoner med heltall eller tegnargumenter og resultater, og de seks transformasjonsfunksjonene REPEAT, SELECTED_INT_KIND, TRIM, SELECTED_REAL_KIND, RESHAPE
og TRANSFER
(se Intrinsic procedures ):
INTEGER, PARAMETER :: long = SELECTED_REAL_KIND(12), &
array(3) = (/ 1, 2, 3 /)
Spesifikasjonsuttrykk
Det er mulig å spesifisere detaljer om variabler ved hjelp av et ikke-konstant, skalært heltallsuttrykk som også kan inkludere henvendelsesfunksjonsreferanser:
SUBROUTINE s(b, m, c)
USE mod ! contains a
REAL, DIMENSION(:, :) :: b
REAL, DIMENSION(UBOUND(b, 1) + 5) :: x
INTEGER :: m
CHARACTER(LEN=*) :: c
CHARACTER(LEN= m + LEN(c)) :: cc
REAL (SELECTED_REAL_KIND(2*PRECISION(a))) :: z
Uttrykk og oppgaver
Skalar numerisk
De vanlige regneoperatørene er tilgjengelige - +, -, *, /, **
(gitt her i økende rekkefølge).
Parenteser brukes til å indikere evalueringsrekkefølgen der det er nødvendig:
a*b + c ! * first
a*(b + c) ! + first
Reglene for skalære numeriske uttrykk og oppgaver tilpasser ikke-standardtypene. Dermed inkorporerer numeriske uttrykks- og oppdragsregler i blandet modus forskjellige parametere av typen type på en forventet måte:
real2 = integer0 + real1
konverterer integer0
til en reell verdi av samme slag som real1
; resultatet er av samme slag, og konverteres til typen real2
for tildeling.
Disse funksjonene er tilgjengelige for kontrollert avrunding av reelle tall til heltall:
-
NINT
: runde til nærmeste heltall, returner heltallsresultat -
ANINT
: runde til nærmeste heltall, returner reelt resultat -
INT
: avkort (runde mot null), returner heltallsresultat -
AINT
: avkort (rund mot null), returner reelt resultat -
CEILING
: minste integrale verdi ikke mindre enn argument (rund opp) (Fortran-90) -
FLOOR
: største integrale verdi ikke større enn argument (rund ned) (Fortran-90)
Skalær relasjonsoperasjon
For skalære relasjonsoperasjoner av numeriske typer er det et sett med innebygde operatører:
< <= == /= > >= .LT. .LE. .EQ. .NE. .GT. .GE.
(skjemaene ovenfor er nye for Fortran-90, og eldre tilsvarende skjemaer er gitt under dem). Eksempeluttrykk:
a < b .AND. i /= j ! for numeric variables
flag = a == b ! for logical variable flags
Skalære tegn
I tilfelle skalare tegn og gittCHARACTER(8) result
det er lovlig å skrive
result(3:5) = result(1:3) ! overlap allowed
result(3:3) = result(3:2) ! no assignment of null string
Sammenkopling utføres av operatøren '//'.
result = 'abcde'//'123'
filename = result//'.dat'
Avledede datatyper
Ingen innebygde operasjoner (unntatt tildeling, definert på komponent-for-komponent-basis) eksisterer mellom avledede datatyper gjensidig eller med iboende typer. Betydningen av eksisterende eller brukerspesifiserte operatører kan (re) defineres skjønt:
TYPE string80
INTEGER length
CHARACTER(80) value
END TYPE string80
CHARACTER:: char1, char2, char3
TYPE(string80):: str1, str2, str3
vi kan skrive
str3 = str1//str2 ! must define operation
str3 = str1.concat.str2 ! must define operation
char3 = char2//char3 ! intrinsic operator only
str3 = char1 ! must define assignment
Legg merke til " overbelastet " bruk av den iboende symbol //
og navngitt operatør .concat.
. En forskjell mellom de to tilfellene er at for et inneboende operatortoken gjelder de vanlige fortrinnsreglene, mens for navngitte operatører er forrang den høyeste som en unary operatør eller den laveste som en binær. I
vector3 = matrix * vector1 + vector2
vector3 =(matrix .times. vector1) + vector2
de to uttrykkene er bare likeverdige hvis passende parenteser legges til som vist. I hvert tilfelle må det i en modul defineres prosedyrer som definerer operatøren og oppdraget, og tilsvarende operatør-prosedyre-tilknytning, som følger:
INTERFACE OPERATOR(//) !Overloads the // operator as invoking string_concat procedure
MODULE PROCEDURE string_concat
END INTERFACE
Strengen sammenkoplingsfunksjonen er en mer utførlig versjon av den som allerede er vist i Grunnleggende . Vær oppmerksom på at for å håndtere feiltilstanden som oppstår når de to strengene tilsammen overskrider den forhåndsinnstilte grensen på 80 tegn, ville det være tryggere å bruke en subrutine for å utføre sammenkoblingen (i dette tilfellet vil overbelastning av operatører ikke være aktuelt.)
MODULE string_type
IMPLICIT NONE
TYPE string80
INTEGER length
CHARACTER(LEN=80) :: string_data
END TYPE string80
INTERFACE ASSIGNMENT(=)
MODULE PROCEDURE c_to_s_assign, s_to_c_assign
END INTERFACE
INTERFACE OPERATOR(//)
MODULE PROCEDURE string_concat
END INTERFACE
CONTAINS
SUBROUTINE c_to_s_assign(s, c)
TYPE (string80), INTENT(OUT) :: s
CHARACTER(LEN=*), INTENT(IN) :: c
s%string_data = c
s%length = LEN(c)
END SUBROUTINE c_to_s_assign
SUBROUTINE s_to_c_assign(c, s)
TYPE (string80), INTENT(IN) :: s
CHARACTER(LEN=*), INTENT(OUT) :: c
c = s%string_data(1:s%length)
END SUBROUTINE s_to_c_assign
TYPE(string80) FUNCTION string_concat(s1, s2)
TYPE(string80), INTENT(IN) :: s1, s2
TYPE(string80) :: s
INTEGER :: n1, n2
CHARACTER(160) :: ctot
n1 = LEN_TRIM(s1%string_data)
n2 = LEN_TRIM(s2%string_data)
IF (n1+n2 <= 80) then
s%string_data = s1%string_data(1:n1)//s2%string_data(1:n2)
ELSE ! This is an error condition which should be handled - for now just truncate
ctot = s1%string_data(1:n1)//s2%string_data(1:n2)
s%string_data = ctot(1:80)
END IF
s%length = LEN_TRIM(s%string_data)
string_concat = s
END FUNCTION string_concat
END MODULE string_type
PROGRAM main
USE string_type
TYPE(string80) :: s1, s2, s3
CALL c_to_s_assign(s1,'My name is')
CALL c_to_s_assign(s2,' Linus Torvalds')
s3 = s1//s2
WRITE(*,*) 'Result: ',s3%string_data
WRITE(*,*) 'Length: ',s3%length
END PROGRAM
Definerte operatører som disse kreves for uttrykkene som også er tillatt i strukturkonstruktører (se Avledede datatyper ):
str1 = string(2, char1//char2) ! structure constructor
Matriser
Når det gjelder matriser, utvides operasjoner og oppgaver på en åpenbar måte, element-for-element-basis, så lenge de er av samme form (formbar). For eksempel gitt erklæringer av
REAL, DIMENSION(10, 20) :: a, b, c
REAL, DIMENSION(5) :: v, w
LOGICAL flag(10, 20)
det kan skrives:
a = b ! whole array assignment
c = a/b ! whole array division and assignment
c = 0. ! whole array assignment of scalar value
w = v + 1. ! whole array addition to scalar value
w = 5/v + a(1:5, 5) ! array division, and addition to section
flag = a==b ! whole array relational test and assignment
c(1:8, 5:10) = a(2:9, 5:10) + b(1:8, 15:20) ! array section addition and assignment
v(2:5) = v(1:4) ! overlapping section assignment
Evalueringsrekkefølgen er ikke spesifisert for å muliggjøre optimalisering på parallelle og vektormaskiner. Selvfølgelig må alle operatorer for matriser av avledet type defineres.
Noen virkelige iboende funksjoner som er nyttige for numeriske beregninger er
CEILING FLOOR MODULO (also integer)
EXPONENT FRACTION
NEAREST RRSPACING SPACING
SCALE SET_EXPONENT
Disse er array verdsatt for array -argumenter (elementære), som alle FORTRAN 77 -funksjoner (unntatt LEN):
INT REAL CMPLX
AINT ANINT NINT
ABS MOD SIGN
DIM MAX MIN
SQRT EXP LOG
LOG10 SIN COS
TAN ASIN ACOS
ATAN ATAN2
SINH COSH TANH
AIMAG CONJG
LGE LGT LLE
LLT ICHAR CHAR
INDEX
(de syv siste er for tegn).
Kontrollerklæringer
Forgrening og vilkår
Den enkle GO TO
etiketten eksisterer, men unngås vanligvis - i de fleste tilfeller vil en mer spesifikk forgreningskonstruksjon oppnå den samme logikken med mer klarhet.
Den enkle betingede testen er IF
utsagnet:IF (a > b) x = y
En fullstendig IF
konstruksjon er illustrert av
IF (i < 0) THEN
IF (j < 0) THEN
x = 0.
ELSE
z = 0.
END IF
ELSE IF (k < 0) THEN
z = 1.
ELSE
x = 1.
END IF
CASE -konstruksjon
Den CASE
konstruere er en erstatning for den beregnede GOTO
, men er bedre strukturert og krever ikke bruk av setningen etiketter:
SELECT CASE (number) ! number of type integer
CASE (:-1) ! all values below 0
n_sign = -1
CASE (0) ! only 0
n_sign = 0
CASE (1:) ! all values above 0
n_sign = 1
END SELECT
Hver CASE
velgerliste kan inneholde en liste og/eller et område med heltall, tegn eller logiske konstanter, hvis verdier ikke overlapper mellom eller mellom velgere:
CASE (1, 2, 7, 10:17, 23)
En standard er tilgjengelig:
CASE DEFAULT
Det er bare en evaluering, og bare en kamp.
GJØ konstruer
En forenklet, men tilstrekkelig form av DO
konstruksjonen er illustrert av
outer: DO
inner: DO i = j, k, l ! from j to k in steps of l (l is optional)
:
IF (...) CYCLE
:
IF (...) EXIT outer
:
END DO inner
END DO outer
der vi merker at looper eventuelt kan navngis slik at enhver EXIT- eller CYCLE -setning kan spesifisere hvilken loop som er ment.
Mange, men ikke alle, enkle sløyfer kan erstattes av matriseuttrykk og tildelinger, eller med nye iboende funksjoner. For eksempel
tot = 0.
DO i = m, n
tot = tot + a(i)
END DO
blir rett og slett tot = SUM( a(m:n) )
Programenheter og prosedyrer
Definisjoner
For å diskutere dette emnet trenger vi noen definisjoner. I logiske termer består et kjørbart program av ett hovedprogram og null eller flere delprogrammer (eller prosedyrer ) - disse gjør noe. Delprogrammer er enten funksjoner eller underrutiner , som enten er eksterne, interne eller modulprogrammer . (Eksterne subrutiner er det vi kjente fra FORTRAN 77.)
Fra et organisatorisk synspunkt består imidlertid et komplett program av programenheter . Dette er enten hovedprogrammer, eksterne delprogrammer eller moduler og kan kompileres separat.
Et eksempel på et hovedprogram (og komplett) er
PROGRAM test
PRINT *, 'Hello world!'
END PROGRAM test
Et eksempel på et hovedprogram og et eksternt delprogram, som danner et kjørbart program, er
PROGRAM test
CALL print_message
END PROGRAM test
SUBROUTINE print_message
PRINT *, 'Hello world!'
END SUBROUTINE print_message
Formen på en funksjon er
FUNCTION name(arg1, arg2) ! zero or more arguments
:
name = ...
:
END FUNCTION name
Referanseformen til en funksjon er x = name(a, b)
Interne prosedyrer
En intern underprogram er ett som inneholdes i en annen (ved maksimalt ett nivå av nesting) og tilveiebringer en erstatning for sammensatt funksjon:
SUBROUTINE outer
REAL x, y
:
CONTAINS
SUBROUTINE inner
REAL y
y = x + 1.
:
END SUBROUTINE inner ! SUBROUTINE mandatory
END SUBROUTINE outer
Vi sier at det outer
er verten for inner
, og som inner
får tilgang til enheter i outer
av vertsforeningen (f.eks. Til x
), mens det
y
er en lokal variabel til inner
.
Den omfanget av en navngitt enhet er en scoping enhet , her
outer
mindre inner
, og inner
.
Navnene på programenheter og eksterne prosedyrer er globale , og navnene på implisitte DO-variabler har et omfang av setningen som inneholder dem.
Moduler
Moduler brukes til å pakke
- globale data (erstatter FELLES og BLOCKDATA fra Fortran 77);
- type definisjoner (seg selv en omfangende enhet);
- delprogrammer (som blant annet erstatter bruk av ENTRY fra Fortran 77);
- grensesnittblokker (en annen omfangsenhet, se grensesnittblokker );
- navnelistgrupper (se hvilken som helst lærebok).
Et eksempel på en modul som inneholder en type definisjon, grensesnittblokk og funksjonsdelprogram
MODULE interval_arithmetic
TYPE interval
REAL lower, upper
END TYPE interval
INTERFACE OPERATOR(+)
MODULE PROCEDURE add_intervals
END INTERFACE
:
CONTAINS
FUNCTION add_intervals(a,b)
TYPE(interval), INTENT(IN) :: a, b
TYPE(interval) add_intervals
add_intervals%lower = a%lower + b%lower
add_intervals%upper = a%upper + b%upper
END FUNCTION add_intervals ! FUNCTION mandatory
:
END MODULE interval_arithmetic
og den enkle uttalelsen
USE interval_arithmetic
gir brukstilknytning til alle modulens enheter. Modulens delprogrammer kan igjen inneholde interne delprogrammer.
Kontrollerer tilgjengeligheten
Den PUBLIC
og PRIVATE
attributter brukes i spesifikasjonene i moduler for å begrense omfanget av enheter. Attributtformen er
REAL, PUBLIC :: x, y, z ! default
INTEGER, PRIVATE :: u, v, w
og erklæringsskjemaet er
PUBLIC :: x, y, z, OPERATOR(.add.)
PRIVATE :: u, v, w, ASSIGNMENT(=), OPERATOR(*)
Erklæringsskjemaet må brukes for å begrense tilgangen til operatører, og kan også brukes til å endre den generelle standarden:
PRIVATE ! sets default for module
PUBLIC :: only_this
For avledede typer er det tre muligheter: typen og komponentene er alle PUBLIC, typen er PUBLIC og komponentene PRIVATE (typen er bare synlig og man kan enkelt endre detaljene), eller alle er PRIVATE (for intern bruk bare i modulen):
MODULE mine
PRIVATE
TYPE, PUBLIC :: list
REAL x, y
TYPE(list), POINTER :: next
END TYPE list
TYPE(list) :: tree
:
END MODULE mine
Den USE
uttalelsen formål er å få tilgang til enheter i en modul. Den har alternativer for å løse navnekollisjoner hvis et importert navn er det samme som et lokalt:
USE mine, local_list => list
eller for å begrense de brukte enhetene til et bestemt sett:
USE mine, ONLY : list
Disse kan kombineres:
USE mine, ONLY : local_list => list
Argumenter
Vi kan spesifisere hensikten med dummy -argumenter:
SUBROUTINE shuffle (ncards, cards)
INTEGER, INTENT(IN) :: ncards
INTEGER, INTENT(OUT), DIMENSION(ncards) :: cards
INOUT er også mulig: her må det faktiske argumentet være en variabel (i motsetning til standardtilfellet der det kan være en konstant).
Argumenter kan være valgfrie:
SUBROUTINE mincon(n, f, x, upper, lower, equalities, inequalities, convex, xstart)
REAL, OPTIONAL, DIMENSION :: upper, lower
:
IF (PRESENT(lower)) THEN ! test for presence of actual argument
:
tillater oss å samtale mincon
med
CALL mincon (n, f, x, upper)
Argumenter kan være nøkkelord i stedet for posisjonelle (som kommer først):
CALL mincon(n, f, x, equalities=0, xstart=x0)
Valgfrie argumenter og søkeord håndteres av eksplisitte grensesnitt, det vil si med interne eller modulprosedyrer eller med grensesnittblokker.
Grensesnittblokker
Enhver referanse til et internt eller modul -delprogram er gjennom et grensesnitt som er 'eksplisitt' (det vil si at kompilatoren kan se alle detaljene). En referanse til en ekstern (eller dummy) prosedyre er vanligvis 'implisitt' (kompilatoren antar detaljene). Imidlertid kan vi også tilby et eksplisitt grensesnitt i dette tilfellet. Det er en kopi av overskriften, spesifikasjonene og END -erklæringen for den aktuelle prosedyren, enten plassert i en modul eller satt inn direkte:
REAL FUNCTION minimum(a, b, func)
! returns the minimum value of the function func(x)
! in the interval (a,b)
REAL, INTENT(in) :: a, b
INTERFACE
REAL FUNCTION func(x)
REAL, INTENT(IN) :: x
END FUNCTION func
END INTERFACE
REAL f,x
:
f = func(x) ! invocation of the user function.
:
END FUNCTION minimum
Et eksplisitt grensesnitt er obligatorisk for
- valgfrie argumenter og søkeord;
- PEKER- og MÅL -argumenter (se Pekere );
- POINTER funksjon resultat;
- nye matriseargumenter og matrisefunksjoner ( Array-håndtering ).
Det tillater full kontroll ved kompileringstid mellom faktiske og dummy -argumenter.
Generelt er den beste måten å sikre at et prosedyregrensesnitt er eksplisitt, enten å plassere den aktuelle prosedyren i en modul eller å bruke den som en intern prosedyre.
Overbelastning og generiske grensesnitt
Grensesnittblokker gir mekanismen for hvordan vi kan definere generiske navn for spesifikke prosedyrer:
INTERFACE gamma ! generic name
FUNCTION sgamma(X) ! specific name
REAL (SELECTED_REAL_KIND( 6)) sgamma, x
END
FUNCTION dgamma(X) ! specific name
REAL (SELECTED_REAL_KIND(12)) dgamma, x
END
END INTERFACE
der et gitt sett med spesifikke navn som tilsvarer et generisk navn alle må ha funksjoner eller alle underrutiner. Hvis dette grensesnittet er i en modul, er det ganske enkelt
INTERFACE gamma
MODULE PROCEDURE sgamma, dgamma
END INTERFACE
Vi kan bruke eksisterende navn, f.eks. SIN, og kompilatoren sorterer ut riktig tilknytning.
Vi har allerede sett bruken av grensesnittblokker for definerte operatører og tildeling (se moduler ).
Rekursjon
Indirekte rekursjon er nyttig for flerdimensjonal integrasjon. Til
volume = integrate(fy, ybounds)
Vi kan ha
RECURSIVE FUNCTION integrate(f, bounds)
! Integrate f(x) from bounds(1) to bounds(2)
REAL integrate
INTERFACE
FUNCTION f(x)
REAL f, x
END FUNCTION f
END INTERFACE
REAL, DIMENSION(2), INTENT(IN) :: bounds
:
END FUNCTION integrate
og for å integrere f (x, y) over et rektangel:
FUNCTION fy(y)
USE func ! module func contains function f
REAL fy, y
yval = y
fy = integrate(f, xbounds)
END
Direkte rekursjon er når en prosedyre kaller seg selv, som i
RECURSIVE FUNCTION factorial(n) RESULT(res)
INTEGER res, n
IF(n.EQ.0) THEN
res = 1
ELSE
res = n*factorial(n-1)
END IF
END
Her noterer vi RESULT
klausulen og avslutningstesten.
Rene prosedyrer
Dette er en funksjon for parallell databehandling.
I FORALL -setningen og konstruksjonen kan eventuelle bivirkninger i en funksjon hindre optimalisering på en parallell prosessor - rekkefølgen på utførelsen av oppgavene kan påvirke resultatene. For å kontrollere denne situasjonen, legger vi til PURE
søkeordet i SUBROUTINE
eller FUNCTION
setningen - en påstand om at prosedyren (uttrykt enkelt):
- endrer ingen global variabel,
- utfører ingen I/O,
- har ingen lagrede variabler (variabler med
SAVE
attributtet som beholder verdier mellom påkallelser), og - for funksjoner, endrer ikke noen av argumentene.
En kompilator kan kontrollere at dette er tilfellet, som i
PURE FUNCTION calculate (x)
Alle iboende funksjoner er rene.
Arrayhåndtering
Arrayhåndtering er inkludert i Fortran av to hovedårsaker:
- den notasjonelle bekvemmeligheten den gir, og bringer koden nærmere den underliggende matematiske formen;
- for de ekstra optimaliseringsmulighetene gir det kompilatorer (selv om det er mange muligheter for nedverdigende optimalisering også!).
Samtidig har store utvidelser av funksjonaliteten i dette området blitt lagt til. Vi har allerede møtt hele matriser over #Arrays 1 og her #Arrays 2 - nå utvikler vi temaet.
Nullstørrelser
En nullstørrelse håndteres av Fortran som et legitimt objekt, uten spesiell koding av programmereren. Således i
DO i = 1,n
x(i) = b(i) / a(i, i)
b(i+1:n) = b(i+1:n) - a(i+1:n, i) * x(i)
END DO
ingen spesiell kode er nødvendig for den endelige iterasjonen hvor i = n
. Vi bemerker at en matrise med null størrelse anses å være definert; Imidlertid er en matrise av form (0,2) ikke forenlig med formen (0,3), mens det er en gyldig "gjør ingenting" -uttalelse.
x(1:0) = 3
Antatt formede matriser
Dette er en utvidelse og erstatning for antatte størrelser. Gitt et faktisk argument som:
REAL, DIMENSION(0:10, 0:20) :: a
:
CALL sub(a)
den tilsvarende dummy -argumentspesifikasjonen definerer bare typen og rangen til matrisen, ikke dens form. Denne informasjonen må gjøres tilgjengelig av et eksplisitt grensesnitt, ofte ved hjelp av en grensesnittblokk (se grensesnittblokker ). Dermed skriver vi bare
SUBROUTINE sub(da)
REAL, DIMENSION(:, :) :: da
og dette er som om det da
var dimensjonert (11,21). Imidlertid kan vi spesifisere en nedre grense og matrisekartene deretter.
REAL, DIMENSION(0:, 0:) :: da
Formen, ikke grenser, passeres, der standard nedre grense er 1 og standard øvre grense er tilsvarende omfang.
Automatiske matriser
EQUIVALENCE
Denne anlegget gir en delvis erstatning for bruksområdene som er nyttig for lokale, midlertidige matriser, som i
SUBROUTINE swap(a, b)
REAL, DIMENSION(:) :: a, b
REAL, DIMENSION(SIZE(a)) :: work
work = a
a = b
b = work
END SUBROUTINE swap
Selve lagringen opprettholdes vanligvis på en bunke.
TILDELELIG og TILDEL
Fortran gir dynamisk fordeling av lagring; den er avhengig av en haugelagringsmekanisme (og erstatter en annen bruk av
EQUIVALENCE
). Et eksempel for å etablere et arbeidsarray for et helt program er
MODULE work_array
INTEGER n
REAL, DIMENSION(:,:,:), ALLOCATABLE :: work
END MODULE
PROGRAM main
USE work_array
READ (input, *) n
ALLOCATE(work(n, 2*n, 3*n), STAT=status)
:
DEALLOCATE (work)
Arbeidsoppsettet kan formidles gjennom hele programmet via en USE
uttalelse i hver programenhet. Vi kan spesifisere en eksplisitt nedre grense og tildele flere enheter i en uttalelse. For å frigjøre død lagring skriver vi for eksempel
DEALLOCATE(a, b)
Deallocation av matriser er automatisk når de går utenfor omfanget.
Elementære operasjoner, oppdrag og prosedyrer
Vi har allerede møtt oppgaver og operasjoner for hele matrisen:
REAL, DIMENSION(10) :: a, b
a = 0. ! scalar broadcast; elemental assignment
b = SQRT(a) ! intrinsic function result as array object
I den andre oppgaven returnerer en inneboende funksjon et matrisevurdert resultat for et matrise-verdsatt argument. Vi kan skrive funksjoner som er verdsatt selv (de krever et eksplisitt grensesnitt):
PROGRAM test
REAL, DIMENSION(3) :: a = (/ 1., 2., 3./), &
b = (/ 2., 2., 2. /), r
r = f(a, b)
PRINT *, r
CONTAINS
FUNCTION f(c, d)
REAL, DIMENSION(:) :: c, d
REAL, DIMENSION(SIZE(c)) :: f
f = c*d ! (or some more useful function of c and d)
END FUNCTION f
END PROGRAM test
Elementære prosedyrer er spesifisert med skalar -dummy -argumenter som kan kalles med array -faktiske argumenter. Når det gjelder en funksjon, er formen på resultatet formen på arrayargumentene.
De fleste iboende funksjoner er elementære, og Fortran 95 utvider denne funksjonen til ikke-inneboende prosedyrer, og gir dermed effekten av å skrive, i Fortran 90, 22 forskjellige versjoner, for rangene 0-0, 0-1, 1-0, 1-1, 0-2, 2-0, 2-2, ... 7-7, og er videre et hjelpemiddel for optimalisering på parallelle prosessorer. En elementær prosedyre må være ren.
ELEMENTAL SUBROUTINE swap(a, b)
REAL, INTENT(INOUT) :: a, b
REAL :: work
work = a
a = b
b = work
END SUBROUTINE swap
Blind argumentene kan ikke brukes i spesifikasjons uttrykk (se ovenfor ), unntatt som argumenter til visse iboende funksjoner ( BIT_SIZE
, KIND
, LEN
, og de numeriske forespørsel seg, (se nedenfor ).
HVOR
Ofte må vi maskere en oppgave. Dette kan vi gjøre ved å bruke WHERE
, enten som en setning:
WHERE (a /= 0.0) a = 1.0/a ! avoid division by 0
(merk: testen er element-for-element, ikke på hele arrayet), eller som en konstruksjon:
WHERE (a /= 0.0)
a = 1.0/a
b = a ! all arrays same shape
END WHERE
eller
WHERE (a /= 0.0)
a = 1.0/a
ELSEWHERE
a = HUGE(a)
END WHERE
Lengre:
- det er tillatt å maskere ikke bare
WHERE
uttalelsen tilWHERE
konstruksjonen, men også enhverELSEWHERE
uttalelse som den inneholder; - en
WHERE
konstruksjon kan inneholde et hvilket som helst antall maskerteELSEWHERE
utsagn, men høyst enELSEWHERE
setning uten maske, og den må være den siste; -
WHERE
konstruksjoner kan være nestet i hverandre, bareFORALL
konstruksjoner; - en
WHERE
oppdragserklæring er tillatt å være en definert oppgave, forutsatt at den er elementær; - en
WHERE
konstruksjon kan navngis på samme måte som andre konstruksjoner.
FORALL -setningen og konstruksjonen
Når en DO
konstruksjon er utført, utføres hver påfølgende iterasjon i rekkefølge og den ene etter den andre - et hinder for optimalisering på en parallell prosessor.
FORALL(i = 1:n) a(i, i) = x(i)
hvor de enkelte oppdragene kan utføres i hvilken som helst rekkefølge, og til og med samtidig. Dette FORALL
kan betraktes som en matriseoppgave uttrykt ved hjelp av indekser.
FORALL(i=1:n, j=1:n, y(i,j)/=0.) x(j,i) = 1.0/y(i,j)
med maskeringstilstand.
Den FORALL
konstruksjonen gjør at flere oppdrag uttalelser for å bli henrettet i orden.
a(2:n-1,2:n-1) = a(2:n-1,1:n-2) + a(2:n-1,3:n) + a(1:n-2,2:n-1) + a(3:n,2:n-1)
b(2:n-1,2:n-1) = a(2:n-1,2:n-1)
tilsvarer matriseoppgavene
FORALL(i = 2:n-1, j = 2:n-1)
a(i,j) = a(i,j-1) + a(i,j+1) + a(i-1,j) + a(i+1,j)
b(i,j) = a(i,j)
END FORALL
Den FORALL
versjonen er mer lesbar.
Tildeling i a FORALL
er som en matriseoppgave: som om alle uttrykkene ble evaluert i en hvilken som helst rekkefølge, holdt i midlertidig lagring, deretter ble alle oppgavene utført i en hvilken som helst rekkefølge. Den første uttalelsen må være fullstendig før den andre kan begynne.
A FORALL
kan være reir, og kan inneholde a WHERE
. Prosedyrer referert til i en FORALL
må være rene.
Arrayelementer
For en enkel sak, gitt
REAL, DIMENSION(100, 100) :: a
vi kan referere til et enkelt element som f.eks a(1, 1)
. For en avledet datatype som
TYPE fun_del
REAL u
REAL, DIMENSION(3) :: du
END TYPE fun_del
vi kan erklære en rekke av den typen:
TYPE(fun_del), DIMENSION(10, 20) :: tar
og en referanse som er et element (en skalar!) av typen fun_del, men er en matrise av typen reell, og er et element i den. Den grunnleggende regelen å huske er at et array -element alltid har et eller flere abonnementer som kvalifiserer minst etternavnet.
tar(n, 2)
tar(n, 2)%du
tar(n, 2)%du(2)
Array -subobjekter (seksjoner)
Den generelle formen for abonnement for en array -seksjon er
[lower] : [upper] [:stride]
(der [] angir et valgfritt element) som i
REAL a(10, 10)
a(i, 1:n) ! part of one row
a(1:m, j) ! part of one column
a(i, : ) ! whole row
a(i, 1:n:3) ! every third element of row
a(i, 10:1:-1) ! row in reverse order
a( (/ 1, 7, 3, 2 /), 1) ! vector subscript
a(1, 2:11:2) ! 11 is legal as not referenced
a(:, 1:7) ! rank two section
Vær oppmerksom på at et vektorabonnement med dupliserte verdier ikke kan vises på venstre side av en oppgave, da det ville være tvetydig. Og dermed,
b( (/ 1, 7, 3, 7 /) ) = (/ 1, 2, 3, 4 /)
er ulovlig. Dessuten må en seksjon med en vektorabonnement ikke leveres som et faktisk argument til et OUT
eller INOUT
dummy -argument. Arrays av arrays er ikke tillatt:
tar%du ! illegal
Vi merker oss at en gitt verdi i en matrise kan refereres både som et element og som en seksjon:
a(1, 1) ! scalar (rank zero)
a(1:1, 1) ! array section (rank one)
avhengig av omstendighetene eller kravene. Ved å kvalifisere objekter av avledet type, får vi elementer eller seksjoner avhengig av regelen som er nevnt tidligere:
tar%u ! array section (structure component)
tar(1, 1)%u ! component of an array element
Arrangerer inneboende funksjoner
Vector og matrise multipliserer
DOT_PRODUCT Dot product of 2 rank-one arrays MATMUL Matrix multiplication
Array reduksjon
ALL True if all values are true ANY True if any value is true. Example: IF (ANY( a > b)) THEN COUNT Number of true elements in array MAXVAL Maximum value in an array MINVAL Minimum value in an array PRODUCT Product of array elements SUM Sum of array elements
Array forespørsel
ALLOCATED Array allocation status LBOUND Lower dimension bounds of an array SHAPE Shape of an array (or scalar) SIZE Total number of elements in an array UBOUND Upper dimension bounds of an array
Array konstruksjon
MERGE Merge under mask PACK Pack an array into an array of rank one under a mask SPREAD Replicate array by adding a dimension UNPACK Unpack an array of rank one into an array under mask
Array omforme
RESHAPE Reshape an array
Array manipulasjon
CSHIFT Circular shift EOSHIFT End-off shift TRANSPOSE Transpose of an array of rank two
Array plassering
MAXLOC Location of first maximum value in an array MINLOC Location of first minimum value in an array
Pekere
Grunnleggende
Pekere er variabler med POINTER
attributtet; de er ikke en distinkt datatype (og derfor er ingen "peker -aritmetikk" mulig).
REAL, POINTER :: var
De er konseptuelt en beskrivelse som viser attributtene til objektene (målene) som pekeren kan peke på, og adressen, hvis noen, til et mål. De har ingen tilknyttet lagring før den er tildelt eller på annen måte assosiert (etter pekeroppgave, se nedenfor ):
ALLOCATE (var)
og de blir automatisk referert, så det kreves ikke noe spesielt symbol. I
var = var + 2.3
verdien av målet for var brukes og modifiseres. Pekere kan ikke overføres via I/O. Uttalelsen
WRITE *, var
skriver verdien av målet for var og ikke pekerbeskrivelsen selv.
En peker kan peke på en annen peker, og dermed til målet, eller til et statisk objekt som har TARGET
attributtet:
REAL, POINTER :: object
REAL, TARGET :: target_obj
var => object ! pointer assignment
var => target_obj
men de er sterkt skrevet:
INTEGER, POINTER :: int_var
var => int_var ! illegal - types must match
og på samme måte for matriser må både rangene og typen være enige.
En peker kan være en komponent av en avledet type:
TYPE entry ! type for sparse matrix
REAL value
INTEGER index
TYPE(entry), POINTER :: next ! note recursion
END TYPE entry
og vi kan definere begynnelsen på en koblet kjede med slike oppføringer:
TYPE(entry), POINTER :: chain
Etter passende tildelinger og definisjoner, kan de to første oppføringene adresseres som
chain%value chain%next%value
chain%index chain%next%index
chain%next chain%next%next
men vi vil normalt definere flere pekere for å peke på for eksempel de første og nåværende oppføringene i listen.
assosiasjon
En pekers foreningsstatus er en av
- udefinert (utgangstilstand);
- tilknyttet (etter tildeling eller pekeroppgave);
- frakoblet:
DEALLOCATE (p, q) ! for returning storage NULLIFY (p, q) ! for setting to 'null'
Det må utvises en viss forsiktighet for ikke å la en peker "dingle" ved bruk av DEALLOCATE
på målet uten å oppheve noen annen peker som refererer til den.
Den iboende funksjonen ASSOCIATED
kan teste assosiasjonsstatusen til en definert peker:
IF (ASSOCIATED(pointer)) THEN
eller mellom en definert peker og et definert mål (som i seg selv kan være en peker):
IF (ASSOCIATED(pointer, target)) THEN
En alternativ måte å initialisere en peker, også i en spesifikasjonserklæring, er å bruke NULL
funksjonen:
REAL, POINTER, DIMENSION(:) :: vector => NULL() ! compile time
vector => NULL() ! run time
Pekere i uttrykk og oppgaver
For inneboende typer kan vi "feie" pekepinner over forskjellige sett med måldata ved å bruke den samme koden uten databevegelse. Gitt matrisemanipulasjonen y = BC z , kan vi skrive følgende kode (selv om det samme resultatet i dette tilfellet kan oppnås enklere på andre måter):
REAL, TARGET :: b(10,10), c(10,10), r(10), s(10), z(10)
REAL, POINTER :: a(:,:), x(:), y(:)
INTEGER mult
:
DO mult = 1, 2
IF (mult == 1) THEN
y => r ! no data movement
a => c
x => z
ELSE
y => s ! no data movement
a => b
x => r
END IF
y = MATMUL(a, x) ! common calculation
END DO
For objekter av avledet type må vi skille mellom peker og normal tildeling. I
TYPE(entry), POINTER :: first, current
:
first => current
oppdraget får først til å peke på gjeldende, mens
first = current
får strøm til å overskrive først og tilsvarer
first%value = current%value
first%index = current%index
first%next => current%next
Pekerargumenter
Hvis et faktisk argument er en peker, hvis dummy -argumentet også er en peker,
- den må ha samme rang,
- den mottar sin assosiasjonsstatus fra det faktiske argumentet,
- den returnerer sin endelige tilknytningsstatus til det faktiske argumentet (merk: målet kan være udefinert!),
- det har kanskje ikke
INTENT
attributtet (det ville være tvetydig), - det krever en grensesnittblokk.
Hvis dummy -argumentet ikke er en peker, blir det assosiert med målet for det faktiske argumentet:
REAL, POINTER :: a (:,:)
:
ALLOCATE (a(80, 80))
:
CALL sub(a)
:
SUBROUTINE sub(c)
REAL c(:, :)
Pekerfunksjoner
Funksjonsresultater kan også ha POINTER
attributtet; dette er nyttig hvis resultatstørrelsen er avhengig av beregninger utført i funksjonen, som i
USE data_handler
REAL x(100)
REAL, POINTER :: y(:)
:
y => compact(x)
der modulen data_handler inneholder
FUNCTION compact(x)
REAL, POINTER :: compact(:)
REAL x(:)
! A procedure to remove duplicates from the array x
INTEGER n
: ! Find the number of distinct values, n
ALLOCATE(compact(n))
: ! Copy the distinct values into compact
END FUNCTION compact
Resultatet kan brukes i et uttrykk (men må være knyttet til et definert mål).
Matriser med tips
Disse eksisterer ikke som sådan: gitt
TYPE(entry) :: rows(n)
deretter
rows%next ! illegal
ville være et slikt objekt, men med et uregelmessig lagringsmønster. Av denne grunn er de ikke tillatt. Imidlertid kan vi oppnå samme effekt ved å definere en avledet datatype med en peker som eneste komponent:
TYPE row
REAL, POINTER :: r(:)
END TYPE
og deretter definere matriser av denne datatypen
TYPE(row) :: s(n), t(n)
hvor lagringen for radene kan tildeles av f.eks.
DO i = 1, n
ALLOCATE (t(i)%r(1:i)) ! Allocate row i of length i
END DO
Arrayoppgaven tilsvarer deretter pekeroppgavene for alle komponentene.
s = t
s(i)%r => t(i)%r
Pekere som dynamiske aliaser
Gitt et utvalg
REAL, TARGET :: table(100,100)
som det ofte refereres til med de faste abonnementene
table(m:n, p:q)
disse referansene kan erstattes av
REAL, DIMENSION(:, :), POINTER :: window
:
window => table(m:n, p:q)
Abonnementene på vinduet er . Tilsvarende, for
(som definert i allerede ), kan vi si for eksempel å peke på alle u -komponentene i tjære, og abonnere det som1:n-m+1, 1:q-p+1
tar%u
taru => tar%u
taru(1, 2)
Abonnementene er som de av tjære selv. (Dette erstatter enda flere av EQUIVALENCE
.)
I pekerforeningen
pointer => array_expression
de nedre grensene for pointer
bestemmes som om de lbound
ble brukt på array_expression
. Når en peker er tilordnet en hel matrisvariabel, arver den altså de nedre grensene for variabelen, ellers er de nedre grensene standard til 1.
Fortran 2003 tillater spesifisering av vilkårlige lavere grenser for pekerforening, som
window(r:,s:) => table(m:n,p:q)
slik at grensene for window
blir r:r+n-m,s:s+q-p
.
Fortran 95 har ikke denne funksjonen; Imidlertid kan den simuleres ved å bruke følgende triks (basert på pekerassosiasjonens regler for antatte formmatrix -dummy -argumenter):
FUNCTION remap_bounds2(lb1,lb2,array) RESULT(ptr)
INTEGER, INTENT(IN) :: lb1,lb2
REAL, DIMENSION(lb1:,lb2:), INTENT(IN), TARGET :: array
REAL, DIMENSION(:,:), POINTER :: ptr
ptr => array
END FUNCTION
:
window => remap_bounds2(r,s,table(m:n,p:q))
Kildekoden til et utvidet eksempel på bruk av pekere for å støtte en datastruktur er i pointer.f90 .
Egne prosedyrer
De fleste av de innebygde funksjonene er allerede nevnt. Her behandler vi bare deres generelle klassifisering og de som hittil har blitt utelatt. Alle egenprosedyrer kan brukes med søkeordargumenter:
CALL DATE_AND_TIME (TIME=t)
og mange har valgfrie argumenter.
De egentlige prosedyrene er gruppert i fire kategorier:
- elementær - arbeid med skalarer eller matriser, f.eks
ABS(a)
. - forespørsel - uavhengig av argumentets verdi (som kan være udefinert), f.eks
PRECISION(a)
. - transformational - array argument med array resultat av forskjellig form, f.eks
RESHAPE(a, b)
. - underrutiner, f.eks
SYSTEM_CLOCK
.
Prosedyrene som ikke allerede er innført er
Litt forespørsel
BIT_SIZE Number of bits in the model
Litt manipulasjon
BTEST Bit testing IAND Logical AND IBCLR Clear bit IBITS Bit extraction IBSET Set bit IEOR Exclusive OR IOR Inclusive OR ISHFT Logical shift ISHFTC Circular shift NOT Logical complement
Overføringsfunksjon, som i
INTEGER :: i = TRANSFER('abcd', 0)
(erstatter en del av EQUIVALENCE)
Subrutiner
DATE_AND_TIME Obtain date and/or time MVBITS Copies bits RANDOM_NUMBER Returns pseudorandom numbers RANDOM_SEED Access to seed SYSTEM_CLOCK Access to system clock CPU_TIME Returns processor time in seconds
Data overføring
(Dette er bare et delsett av de faktiske funksjonene, og unntaksvis brukes små bokstaver i kodeeksemplene.)
Formaterte input/output
Disse eksemplene illustrerer ulike former for I/O -lister med noen enkle formater (se nedenfor ):
integer :: i
real, dimension(10) :: a
character(len=20) :: word
print "(i10)", i
print "(10f10.3)", a
print "(3f10.3)", a(1),a(2),a(3)
print "(a10)", word(5:14)
print "(3f10.3)", a(1)*a(2)+i, sqrt(a(3:4))
Variabler, men ikke uttrykk, er like gyldige i input -setninger som bruker read
setningen:
read "(i10)", i
Hvis en matrise vises som et element, blir det behandlet som om elementene ble spesifisert i rekkefølgeelementrekkefølge.
Eventuelle tips i en I/O -liste må være knyttet til et mål, og overføringen finner sted mellom filen og målene.
Et element av avledet type behandles som om komponentene ble spesifisert i samme rekkefølge som i typedeklarasjonen, så
read "(8f10.5)", p, t ! types point and triangle
har samme effekt som utsagnet
read "(8f10.5)", p%x, p%y, t%a%x, t%a%y, t%b%x, &
t%b%y, t%c%x, t%c%y
Et objekt i en I/O -liste er ikke tillatt å være av en avledet type som har en pekerkomponent på noe nivå av komponentvalg.
Vær oppmerksom på at en matrise med null størrelse kan forekomme som et element i en I/O-liste. Et slikt element tilsvarer ingen faktisk dataoverføring.
Formatspesifikasjonen kan også gis i form av et tegnuttrykk:
character(len=*), parameter :: form="(f10.3)"
:
print form, q
eller som en stjerne-dette er en type I/O kjent som listerettet I/O (se nedenfor ), der formatet er definert av datasystemet:
print *, "Square-root of q = ", sqrt(q)
Inndata/utdata operasjoner brukes til å overføre data mellom lagringen av et utførende program og et eksternt medium, spesifisert av et enhetsnummer . To I/O -setninger print
og en variant av
read
refererer imidlertid ikke til noe enhetsnummer: dette kalles terminal I/O. Ellers er skjemaet:
read (unit=4, fmt="(f10.3)") q
read (unit=nunit, fmt="(f10.3)") q
read (unit=4*i+j, fmt="(f10.3)") a
hvor unit=
er valgfritt. Verdien kan være et hvilket som helst ikke -negativt heltall som systemet tillater for dette formålet (men 0, 5 og 6 angir ofte feilen, tastaturet og terminalen).
En stjerne er en variant - igjen fra tastaturet:
read (unit=*, fmt="(f10.3)") q
En lesing med en enhetsspesifiser tillater håndtering av unntak :
read (unit=nunit, fmt="(3f10.3)", iostat=ios) a,b,c
if (ios == 0) then
! Successful read - continue execution.
:
else
! Error condition - take appropriate action.
call error (ios)
end if
Det er en annen type formatert utdata,
write
setningen:
write (unit=nout, fmt="(10f10.3)", iostat=ios) a
Interne filer
Disse lar formatkonvertering mellom ulike representasjoner utføres av programmet i et lagringsområde definert i selve programmet.
integer, dimension(30) :: ival
integer :: key
character(len=30) :: buffer
character(len=6), dimension(3), parameter :: form=(/ "(30i1)", "(15i2)","(10i3)" /)
read (unit=*, fmt="(a30,i1)") buffer, key
read (unit=buffer, fmt=form (key)) ival(1:30/key)
Hvis en intern fil er en skalar, har den en enkelt post hvis lengde er den på skalaren.
Hvis det er en matrise, blir elementene i rekkefølgeelementsrekkefølge behandlet som påfølgende poster av filen, og hver har lengden som et arrayelement.
Et eksempel på bruk av en write
setning er
integer :: day
real :: cash
character(len=50) :: line
:
! write into line
write (unit=line, fmt="(a, i2, a, f8.2, a)") "Takings for day ", day, " are ", cash, " dollars"
som kan skrive
Takings for day 3 are 4329.15 dollars
Listerettet I/O
Et eksempel på en lese uten et spesifisert format for inndata er
integer :: i
real :: a
complex, dimension(2) :: field
logical :: flag
character(len=12) :: title
character(len=4) :: word
:
read *, i, a, field, flag, title, word
Hvis dette leser inndataposten
10 6.4 (1.0,0.0) (2.0,0.0) t test/
(i hvilken emnene benyttes som skilletegn), da i
, a
,
field
, flag
, og title
vil få verdiene 10, 6,4, (1.0,0.0) og (2.0,0.0), .true.
og test
henholdsvis, samtidig som word
forblir uendret.
Anførselstegn eller apostrofer kreves som avgrensere for en streng som inneholder et tomt.
I/O som ikke går videre
Dette er en form for lesing og skriving uten alltid å gå filposisjonen til neste rekord. Mens en fremrykkende I/O-setning alltid plasserer filen på nytt etter at den siste posten ble åpnet, utfører en I/O-setning som ikke går videre, ingen slik posisjonering og kan derfor la filen stå i en post.
character(len=3) :: key
integer :: u, s, ios
:
read(unit=u, fmt="(a3)", advance="no", size=s, iostat=ios) key
if (ios == 0) then
:
else
! key is not in one record
key(s+1:) = ""
:
end if
En ikke-avansert lesning kan lese de første tegnene i en plate og en normal lese resten.
For å skrive en melding til en terminalskjerm og for å lese fra neste tegnposisjon på skjermen uten mellomliggende linjefeed, kan vi skrive
write (unit=*, fmt="(a)", advance="no") "enter next prime number:"
read (unit=*, fmt="(i10)") prime_number
Ikke-fremskritt I/O er for eksterne filer, og er ikke tilgjengelig for listestyrte I/O.
Rediger beskrivelser
Det er mulig å angi at en redigeringsbeskrivelse skal gjentas et bestemt antall ganger, ved bruk av en gjentakelse :10f12.3
Slash -redigeringsbeskrivelsen (se nedenfor ) kan ha en gjentakelse, og en gjentakelse kan også gjelde for en gruppe med redigeringsbeskrivelser, innesluttet i parentes, med hekkende:
print "(2(2i5,2f8.2))", i(1),i(2),a(1),a(2), i(3),i(4),a(3),a(4)
Hele formatspesifikasjonene kan gjentas:
print "(10i8)", (/ (i(j), j=1,200) /)
skriver 10 heltall, hver opptar 8 tegnposisjoner, på hver av 20 linjer (gjentar formatspesifikasjonen går videre til neste linje).
Dataredigeringsbeskrivelser
- Heltall:
iW iW.M
- Ekte:
fW.D esW.D esW.DeE
- Kompleks: par med
f
elleres
rediger beskrivelser - Logisk:
lW
- Karakter:
a aW
- Avledede typer: redigeres av en passende sekvens av redigeringsbeskrivelser som tilsvarer de iboende typene til de endelige komponentene i den avledede typen.
type, public :: string integer :: length character(len=20) :: word end type string type(string) :: text read(unit=*, fmt="(i2, a)") text
Kontroller redigeringsbeskrivere
Innstillinger for kontrollredigeringsbeskrivelser :
- Den
ss
(sign undertrykke) redigere descriptor undertrykker ledende plusstegn. For å slå på plussskiltutskrift, brukessp
(tegnutskrift) -beskrivelsen. Dens
redigere descriptor gjenoppretter muligheten til prosessoren. - Denne beskrivelsen forblir i kraft resten av formatspesifikasjonen, med mindre en annen av dem er oppfylt.
Kontroller redigeringsbeskrivere for umiddelbar behandling :
- Tabulering:
tN trN tlN
read (unit=*, fmt="(t3,i4, tl4,i1, i2)") i,j,k
- Nye rekorder:
/ N/
read "(i5,i3,/,i5,i3,i2)", i, j, k, l, m
Noter det
skiller de to verdiene med tre tomme poster.print "(i5,4/,i5)", i, j
- Kolonredigering:
:
avslutter formatkontrollen hvis det ikke er flere elementer i en I/O -liste.stopper nye poster hvis det erprint "( i5, :, /, i5, :, /, i5)", (/(l(i), i=1,n)/)
n
lik 1 eller 2.
Uformatert I/O.
Denne typen I/O skal bare brukes i tilfeller der postene genereres av et program på en datamaskin, for å kunne leses tilbake på samme datamaskin eller en annen datamaskin ved hjelp av de samme interne tallrepresentasjonene:
open(unit=4, file='test', form='unformatted')
read(unit=4) q
write(unit=nout, iostat=ios) a ! no fmt=
Filer med direkte tilgang
Denne formen for I/O er også kjent som tilfeldig tilgang eller indeksert I/O. Her har alle postene samme lengde, og hver post er identifisert med et indeksnummer. Det er mulig å skrive, lese eller skrive om en spesifisert post uten hensyn til posisjon.
integer, parameter :: nunit=2, length=100
real, dimension(length) :: a
real, dimension(length+1:2*length) :: b
integer :: i, rec_length
:
inquire (iolength=rec_length) a
open (unit=nunit, access="direct", recl=rec_length, status="scratch", action="readwrite")
:
! Write array b to direct-access file in record 14
write (unit=nunit, rec=14) b
:
!
! Read the array back into array a
read (unit=nunit, rec=14) a
:
do i = 1, length/2
a(i) = i
end do
!
! Replace modified record
write (unit=nunit, rec=14) a
Filen må være en ekstern fil og listestyrt formatering og ikke-fremskritt I/O er utilgjengelig.
Operasjoner på eksterne filer
Nok en gang er dette bare en oversikt.
Uttalelser om posisjonering av filer
- Den
backspace
uttalelsen:backspace (unit=u [,iostat=ios]) ! where [ ] means optional
- Den
rewind
uttalelsen:rewind (unit=u [,iostat=ios])
- Den
endfile
uttalelsen:endfile (unit=u [,iostat=ios])
den open
uttalelsen
Uttalelsen brukes til å koble en ekstern fil til en enhet, lage en fil som er forhåndskoblet, eller opprette en fil og koble den til en enhet. Syntaksen er
open (unit=u, status=st, action=act [,olist])
hvor olist
er en liste over valgfrie spesifikatorer. Spesifikatorene kan vises i hvilken som helst rekkefølge.
open (unit=2, iostat=ios, file="cities", status="new", access="direct", &
action="readwrite", recl=100)
Andre spesifiserere er form
og position
.
den close
uttalelsen
Dette brukes til å koble en fil fra en enhet.
close (unit=u [,iostat=ios] [,status=st])
som i
close (unit=2, iostat=ios, status="delete")
den inquire
uttalelsen
Når som helst under utførelsen av et program er det mulig å spørre om status og attributter til en fil ved å bruke denne uttalelsen.
Ved å bruke en variant av denne setningen, er det på samme måte mulig å bestemme statusen til en enhet, for eksempel om enhetsnummeret eksisterer for det systemet.
En annen variant tillater en forespørsel om lengden på en utgangsliste når den brukes til å skrive en uformatert post.
For forespørsel etter enhet
inquire (unit=u, ilist)
eller for å spørre etter fil
inquire (file=fln, ilist)
eller for forespørsel etter I/O -liste
inquire (iolength=length) olist
Som et eksempel
logical :: ex, op
character (len=11) :: nam, acc, seq, frm
integer :: irec, nr
inquire (unit=2, exist=ex, opened=op, name=nam, access=acc, sequential=seq, form=frm, &
recl=irec, nextrec=nr)
gir
ex .true.
op .true.
nam cities
acc DIRECT
seq NO
frm UNFORMATTED
irec 100
nr 1
(forutsatt ingen mellomliggende lese- eller skriveoperasjoner).
Andre spesifiserere er iostat, opened, number,
named, formatted, position, action, read, write, readwrite
.