Zoeken…


Impliciete variabeletypen

Toen Fortran oorspronkelijk werd ontwikkeld, was geheugen een premium. Variabelen en procedurenamen konden maximaal 6 tekens bevatten en variabelen werden vaak impliciet getypt . Dit betekent dat de eerste letter van de variabelenaam het type bepaalt.

  • variabelen die beginnen met i, j, ..., n zijn integer
  • al het andere (a, b, ..., h en o, p, ..., z) is real

Programma's zoals de volgende zijn acceptabel Fortran:

program badbadnotgood
  j = 4
  key = 5 ! only the first letter determines the type
  x = 3.142
  print*, "j = ", j, "key = ", key, "x = ", x
end program badbadnotgood

U kunt zelfs uw eigen impliciete regels definiëren met de implicit verklaring:

! all variables are real by default 
implicit real (a-z)

of

! variables starting with x, y, z are complex
! variables starting with c, s are character with length of 4 bytes
! and all other letters have their default implicit type
implicit complex (x,y,z), character*4 (c,s) 

Impliciet typen wordt niet langer als beste praktijk beschouwd. Het is heel gemakkelijk om een fout te maken met impliciet typen, omdat typefouten bijvoorbeeld onopgemerkt kunnen blijven

program oops
  real :: somelongandcomplicatedname

  ...

  call expensive_subroutine(somelongandcomplEcatedname)
end program oops

Dit programma wordt graag uitgevoerd en doet het verkeerde.


Om impliciet typen uit te schakelen, kan de implicit none instructie worden gebruikt.

program much_better
  implicit none
  integer :: j = 4
  real :: x = 3.142
  print*, "j = ", j, "x = ", x
end program much_better

Als we implicit none hadden gebruikt in het programma oops hierboven, zou de compiler het onmiddellijk hebben opgemerkt en een fout produceren.

Rekenkundige als statement

Rekenkundige if instructie maakt het mogelijk om drie takken te gebruiken, afhankelijk van het resultaat van een rekenkundige uitdrukking

if (arith_expr) label1, label2, label3

Dit if statement transfers control flow aan één van de labels in een code. Als het resultaat van arith_expr negatief is, is label1 betrokken, als het resultaat nul is, wordt label2 gebruikt en als het resultaat positief is, wordt het laatste label3 toegepast. Rekenkunde if alle drie labels vereist zijn, maar het hergebruik van labels mogelijk maakt, daarom kan deze verklaring worden vereenvoudigd tot een tak met twee if .

Voorbeelden:

if (N * N - N / 2) 130, 140, 130

if (X) 100, 110, 120

Nu is deze functie verouderd met dezelfde functionaliteit die wordt aangeboden door de if instructie en if-else constructie. Bijvoorbeeld het fragment

    if (X) 100, 110, 120
100 print*, "Negative"
    goto 200
110 print*, "Zero"
    goto 200
120 print*, "Positive"
200 continue

kan worden geschreven als het if-else construct

if (X<0) then
  print*, "Negative"
else if (X==0) then
  print*, "Zero"
else
  print*, "Positive"
end if

Een if statement-vervanging voor

    if (X) 100, 100, 200
100 print *, "Negative or zero"
200 continue

kan zijn

if (X<=0) print*, "Negative or zero"

Niet-blok DO-constructen

Het non-block do construct ziet eruit

    integer i
    do 100, i=1, 5
100 print *, i

Dat wil zeggen, wanneer de gelabelde beëindigingsverklaring geen continue verklaring is. Er zijn verschillende beperkingen op de verklaring die kunnen worden gebruikt als de beëindigingsverklaring en de hele zaak is over het algemeen erg verwarrend.

Een dergelijk niet-blokconstructie kan in blokvorm worden herschreven als

    integer i
    do 100 i=1,5
      print *, i
100 continue

of beter, met behulp van een end do beëindiging statement,

integer i
do i=1,5
  print *, i
end do

Alternatief rendement

Alternatief rendement is een faciliteit om de uitvoeringsstroom bij terugkeer vanuit een subroutine te regelen. Het wordt vaak gebruikt als een vorm van foutafhandeling:

real x

call sub(x, 1, *100, *200)
print*, "Success:", x
stop

100 print*, "Negative input value"
stop

200 print*, "Input value too large"
stop

end

subroutine sub(x, i, *, *)
  real, intent(out) :: x
  integer, intent(in) :: i
  if (i<0) return 1
  if (i>10) return 2
  x = i
end subroutine

De alternatieve return wordt gemarkeerd door de argumenten * in de subroutine dummy argumentlijst.

In de call hierboven verwijzen *100 en *200 naar de verklaringen met het label respectievelijk 100 en 200 .

In de subroutine zelf hebben de return die overeenkomen met alternatieve retouren een nummer. Dit nummer is geen retourwaarde, maar geeft het opgegeven label aan waarnaar uitvoering wordt teruggestuurd. In dit geval geeft return 1 uitvoering door aan de instructie met het label 100 en return 2 uitvoering door aan de instructie met het label 200 . Een onopgesmelde return , of voltooiing van subroutine-uitvoering zonder een return , passess-uitvoering tot onmiddellijk na de oproepverklaring.

De alternatieve syntaxis van het rendement is heel anders dan andere vormen van argumentassociatie en de faciliteit introduceert flow control in tegenstelling tot moderne smaken. Meer aangename flow control kan worden beheerd met de terugkeer van een geheel "status" code.

real x
integer status

call sub(x, 1, status)
select case (status)
case (0)
  print*, "Success:", x
case (1)
  print*, "Negative input value"
case (2)
  print*, "Input value too large"
end select

end

subroutine sub(x, i, status)
  real, intent(out) :: x
  integer, intent(in) :: i
  integer, intent(out) :: status

  status = 0

  if (i<0) then
    status = 1
  else if (i>10)
    status = 2
  else
    x = i
  end if

end subroutine

Formulier vaste bron

Fortran is oorspronkelijk ontworpen voor een vast formaat op basis van een ponskaart met 80 kolommen:

voer hier de afbeeldingsbeschrijving in

Ja: dit is een regel van de eigen code van de auteur

Deze zijn gemaakt op een kaartponsmachine, ongeveer zoals dit:

voer hier de afbeeldingsbeschrijving in

Afbeeldingen zijn originele fotografie door de auteur

Het formaat, zoals weergegeven op de geïllustreerde voorbeeldkaart, had de eerste vijf kolommen gereserveerd voor statementlabels. De eerste kolom werd gebruikt om opmerkingen aan te duiden met een letter C. De zesde kolom werd gebruikt om een voortzetting van de instructie aan te geven (door een ander teken dan een nul '0' in te voegen). De laatste 8 kolommen werden gebruikt voor kaartidentificatie en sequencing, wat behoorlijk waardevol was als je je stapel kaarten op de grond liet vallen! De karaktercodering voor ponskaarten had slechts een beperkt aantal karakters en was alleen hoofdletters. Daarom zagen Fortran-programma's er als volgt uit:

       DIMENSION A(10)                                                    00000001
C THIS IS A COMMENT STATEMENT TO EXPLAIN THIS EXAMPLE PROGRAM             00000002
       WRITE (6,100)                                                      00000003
 100   FORMAT(169HTHIS IS A RATHER LONG STRING BEING OUTPUT WHICH GOES OVE00000004
      1R MORE THAN ONE LINE, AND USES THE STATEMENT CONTINUATION MARKER IN00000005
      2COLUMN 6, AND ALSO USES HOLLERITH STRING FORMAT)                   00000006
       STOP                                                               00000007
       END                                                                00000008

Het ruimtekarakter werd ook overal genegeerd, behalve in een Hollerith- karakterconstante (zoals hierboven weergegeven). Dit betekende dat spaties konden voorkomen in gereserveerde woorden en constanten, of volledig konden worden gemist. Dit had het neveneffect van enkele nogal misleidende uitspraken zoals:

       DO 1 I = 1.0

is een toewijzing aan de variabele DO1I terwijl:

       DO1I = 1,0 

is eigenlijk een DO lus op de variabele I


Modern Fortran heeft nu deze vaste vorm van invoer niet nodig en staat vrije vorm toe met behulp van kolommen. Reacties worden nu aangegeven met een ! die ook aan een afschriftregel kan worden toegevoegd. Spaties zijn nu nergens toegestaan en moeten worden gebruikt als scheidingstekens, net als in de meeste andere talen. Het bovenstaande programma kan in het moderne Fortran worden geschreven als:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH no longer GOES OVER MORE THAN ONE LINE, AND does not need to USE THE STATEMENT CONTINUATION MARKER IN COLUMN 6, or the HOLLERITH STRING FORMAT"

Hoewel de oude stijl niet langer wordt gebruikt, illustreert het bovenstaande voorbeeld dat er nog steeds zeer lange uitspraken zullen voorkomen. Modern Fortran gebruikt een & -symbool aan het einde en begin van de voortzetting. We zouden het bovenstaande bijvoorbeeld in een beter leesbare vorm kunnen schrijven:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH still &
         &GOES OVER MORE THAN ONE LINE, AND does need to USE THE STATEMENT &
         &CONTINUATION notation"

Gemeenschappelijke blokken

In de vroege vormen van Fortran is het enige mechanisme voor het creëren van een globale variabele store zichtbaar vanuit subroutines en functies het gebruik van het COMMON -blokmechanisme. Hierdoor konden sequenties van variabelen namen zijn en gemeenschappelijk worden gebruikt.

Naast benoemde gemeenschappelijke blokken kan er ook een blanco (naamloos) gemeenschappelijk blok zijn.

Een leeg gemeenschappelijk blok kan worden gedeclareerd als

common i, j

terwijl de genoemde variables zouden kunnen worden verklaard

common /variables/ i, j

Als een volledig voorbeeld kunnen we ons een heap-winkel voorstellen die wordt gebruikt door routines die waarden kunnen toevoegen en verwijderen:

       PROGRAM STACKING
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = 0
       READ *, IVAL
       CALL PUSH(IVAL)
       CALL POP(IVAL)
       END

       SUBROUTINE PUSH(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = ICOUNT + 1
       ISTACK(ICOUNT) = IVAL
       RETURN
       END

       SUBROUTINE POP(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       IVAL = ISTACK(ICOUNT)
       ICOUNT = ICOUNT - 1
       RETURN
       END

Algemene instructies kunnen worden gebruikt om impliciet het type van een variabele aan te geven en het dimension kenmerk op te geven. Alleen al dit gedrag is vaak een voldoende bron van verwarring. Verder maakt de impliciete opslagassociatie en vereisten voor herhaalde definities tussen programma-eenheden het gebruik van gemeenschappelijke blokken vatbaar voor fouten.

Tot slot zijn gemeenschappelijke blokken erg beperkt in de objecten die ze bevatten. Een array in een gemeenschappelijk blok moet bijvoorbeeld een expliciete grootte hebben; toewijsbare objecten mogen niet voorkomen; afgeleide typen mogen geen standaardinitialisatie hebben.

In het moderne Fortran kan dit delen van variabelen worden afgehandeld door het gebruik van modules . Het bovenstaande voorbeeld kan worden geschreven als:

module heap
  implicit none
  ! In Fortran 2008 all module variables are implicitly saved
  integer, save :: count = 0
  integer, save :: stack(1023)
end module heap

program stacking
  implicit none
  integer val
  read *, val
  call push(val)
  call pop(val)

contains
  subroutine push(val)
    use heap, only : count, stack
    integer val
    count = count + 1
    stack(count) = val
  end subroutine push

  subroutine pop(val)
    use heap, only : count, stack
    integer val
    val = stack(count)
    count = count - 1
  end subroutine pop
end program stacking

Benoemde en lege gemeenschappelijke blokken hebben een enigszins ander gedrag. Van belang:

  • objecten in benoemde gemeenschappelijke blokken kunnen aanvankelijk worden gedefinieerd; objecten in blanco zijn dat niet
  • objecten in lege gemeenschappelijke blokken gedragen zich alsof het gemeenschappelijke blok het kenmerk save heeft; objecten in benoemde gemeenschappelijke blokken zonder het kenmerk save kunnen ongedefinieerd worden wanneer het blok niet binnen het bereik van een actieve programma-eenheid valt

Dit laatste punt kan worden afgezet tegen het gedrag van modulevariabelen in moderne code. Alle modulevariabelen in Fortran 2008 worden impliciet opgeslagen en worden niet ongedefinieerd wanneer de module buiten bereik valt. Vóór Fortran 2008 zouden modulevariabelen, zoals variabelen in benoemde gemeenschappelijke blokken, ook ongedefinieerd worden wanneer de module buiten bereik zou vallen.

Toegewezen GOTO

Toegewezen GOTO gebruikt de variabele integer waaraan een instructie-label wordt toegewezen met behulp van de ASSIGN-instructie.

100 CONTINUE

...

ASSIGN 100 TO ILABEL

...


GOTO ILABEL

Toegewezen GOTO is verouderd in Fortran 90 en verwijderd in Fortran 95 en later. Het kan in moderne code worden vermeden door procedures, interne procedures, procedurepunten en andere functies te gebruiken.

GOTO berekend

Berekende GOTO maakt vertakking van het programma mogelijk volgens de waarde van een geheel getal-uitdrukking.

GOTO (label_1, label_2,... label_n) scalar-integer-expression

Als scalar-integer-expression gelijk is aan 1, gaat het programma verder met statement label label_1 , als het gelijk is aan 2 gaat het naar label_2 enzovoort. Als het minder dan 1 of groter dan n programma wordt voortgezet op de volgende regel.

Voorbeeld:

ivar = 2

...

GOTO (10, 20, 30, 40) ivar

springt naar statement label 20.

Deze vorm van goto is verouderd in Fortran 95 en later en wordt vervangen door het select case construct.

Toegewezen opmaakspecificaties

Vóór Fortran 95 was het mogelijk om toegewezen formaten te gebruiken voor invoer of uitvoer. Overwegen

integer i, fmt
read *, i

assign 100 to fmt
if (i<100000) assign 200 to fmt

print fmt, i

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

Met de assign statement wordt een instructielabel assign aan een variabele met een geheel getal. Deze variabele met geheel getal wordt later gebruikt als de opmaakaanduiding in de print .

Een dergelijke indelingstoewijzingstoewijzing is verwijderd in Fortran 95. In plaats daarvan kan modernere code een andere vorm van uitvoering van stroombeheer gebruiken

integer i
read *, i

if (i<100000) then
  print 100, i
else
  print 200, i
end if

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

of een tekenvariabele kan worden gebruikt als de opmaakspecificatie

character(29), target :: big_fmt='("This is a big number", I10)'
character(30), target :: small_fmt='("This is a small number", I6)'
character(:), pointer :: fmt

integer i
read *, i

fmt=>big_fmt
if (i<100000) fmt=>small_fmt

print fmt, i

end

Statement-functies

Overweeg het programma

implicit none
integer f, i
f(i)=i

print *, f(1)
end

Hier is f een statement-functie. Het heeft een integer resultaattype, waarbij één integer dummy-argument wordt gebruikt. 1

Een dergelijke statement-functie bestaat binnen het bereik waarin deze is gedefinieerd. In het bijzonder heeft het toegang tot variabelen en benoemde constanten die binnen dat bereik toegankelijk zijn.

Statement-functies zijn echter onderhevig aan vele beperkingen en kunnen potentieel verwarrend zijn (kijkend naar een casual blik zoals een toewijzingsstatement van een array-element). Belangrijke beperkingen zijn:

  • het functieresultaat en dummyargumenten moeten scalair zijn
  • de dummy-argumenten vallen binnen hetzelfde bereik als de functie
  • instructiefuncties hebben geen lokale variabelen
  • instructiefuncties kunnen niet worden doorgegeven als feitelijke argumenten

De belangrijkste voordelen van statement-functies worden herhaald door interne functies

implicit none

print *, f(1)

contains

  integer function f(i)
    integer i
    f = i
  end function

end

Interne functies zijn niet onderworpen aan de hierboven genoemde beperkingen, hoewel het misschien vermeldenswaard is dat een intern subprogramma mogelijk geen verder intern subprogramma bevat (maar het kan een statementfunctie bevatten).

Interne functies hebben hun eigen toepassingsgebied, maar hebben ook beschikbare host-associatie.


1 In echte oude codevoorbeelden zou het niet ongebruikelijk zijn om te zien dat de dummy-argumenten van een statement-functie impliciet worden getypt, zelfs als het resultaat een expliciet type heeft.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow