Ulkoasu
Jos sarakkeella 1 on
Sarakkeet 1--5: osoitekenttä
Sarake 6: jos jotakin muuta kuin välilyönti, kyseessä on jatkorivi
Sarakkeet 7--72: ohjelman lauseet
Sarakkeet 73--: kommentti (käytettiin joskus muinoin esim. reikäkorttien numerointiin). Uudemmat kääntäjät hyväksyvät pitemmät rivit; mahdollisesti ilmoitettava sopivalla kääntäjän optiolla.
Välilyönneillä ei ole mitään merkitystä missään kohdassa; niitä voi olla jopa tunnusten keskellä (!!)
REAL X1 Y(10) DIMENSIONU(100) DO100I=1,10 Z=X1 1Y(I) IF(Z.GT.0.0.AND.Z.LT.1.0)T H E N U(I)=S SQRT(Z)+1 . 23 11E-1-Z EN +DIF 100 CONTINUE
Muuttujan nimi saa olla korkeintaan kuuden merkin mittainen. Jotkin kääntäjät sallivat pitemmät nimet, mutta ne eivät kuulu standardiin.
Standardin mukaiset tyypit:
integer real double precision complex logical character
Useimmissa toteutuksissa laajennuksia, kuten
integer*4 real*8 logical*1Numero kertoo, kuinka monta tavua muuttujalle varataan. Tämä ei ole standardin mukainen määrittely!
Vanhoissa ohjelmissa luotetaan usein implisiittiseen
määrittelyyn. Tästä johtuvat joskus omituiset
muuttujien nimet, kuten
Muuttujat voidaan alustaa
real x(3) data x /1.0, 2*0.5/
Useat muuttujat (jopa eri tyyppiset) voivat viitata samaan muistipaikkaan:
real z(100),x(3),y integer nn equivalence (x,z(10)) equivalence (y,z(100)) equivalence (nn,z)
Käyttökohteita:
do 100 i=1,10 100 x(i)=0.0tai mieluummin:
do 100 i=1,10 x(i)=0.0 100 continueVanhimmissa versioissa ei
Aritmeettinen if:
if (i-j) 100,200,300 100 k=i-j goto 400 200 k=0 goto 400 300 k=j 400 ...Taulukkosyntaksi on F90:n laajennus, vaikkakin mukana monissa vektorikoneiden (kuten Cray) Fortraneissa.
Matemaattiset varusfunktiot käytettävissä. Muista varusfunktioista suurin osa vasta F90:ssä.
Lausefunktio:
f(x)=sqrt(1-x**2) ... z=f(0.1)Notaation ongelma (myös F90:ssä):
real f ... y=f(x)Tämä voi tarkoittaa:
Aliohjelmat käännetään erikseen. Kääntäjä ei voi varmistaa, että parametrien tyypit ovat oikein, tai että niitä on oikea määrä. Virhe johtaa virheellisiin tuloksiin tai parhaassa tapauksessa ajon kaatumiseen.
Käytetystä tekniikasta riippumatta strukturoitu ohjelmointi pyrkii ohjelman pilkkomiseen pieniin, helposti hallittaviin ja riittävän yksinkertaisiin moduuleihin.
Aliohjelman pitäisi olla aina ymmärrettävissä kerralla yhtenä kokonaisuutena. Mitä monimutkaisempia kontrollirakenteita aliohjelma sisältää, sitä lyhyempi sen on oltava.
Kukin aliohjelma tekee yhden täsmällisesti määritellyn toimenpiteen. Tämä ei tarkoita, että toiminnon pitäisi olla yksinkertainen, pääasia on että se voidaan määritellä yksinkertaisesti, esim. "lajittele tiedosto", "etsi osittaisdifferentiaaliyhtälön ratkaisu, joka toteuttaa annetut reunaehdot", "todista Goldbachin konjektuuri". Samaan aliohjelmaan ei pidä kasata sekalaisia toimenpiteitä, jotka eivät kuulu loogisesti yhteen.
Aliohjelmien tulee olla toisistaan mahdollisimman riippumattomia. Globaalien muuttujien avulla tulisi välittää mahdollisimman vähän tietoa. Jos aliohjelmalla on hyvin paljon parametreja, jotakin voi olla vialla.
Kolme tarkastelukulmaa:
DO100I=1,10 IF(X(I).GT.0.0.AND.X(I).LT.1.0)THEN Y(I)=SQRT(X(I))+123.4*SIN(X(I))+(A-1.0)*SQRT( 11.0-X(I)) ELSE Y(I)=0.0 ENDIF 100 CONTINUELuettavampi versio:
do 100 i=1,10 if(x(i) .gt. 0.0 .and. x(i) .lt. 1.0) then y(i)=sqrt(x(i))+123.4*sin(x(i))+ . (a-1.0)*sqrt(1.0-x(i)) else y(i)=0.0 end if 100 continueF90-ratkaisu voisi olla
y(1:10)=0 do i=1,10 if(x(i) > 0.0 .and. x(i) < 1.0) then y(i)=sqrt(x(i))+123.4*sin(x(i))+ \& (a-1.0)*sqrt(1.0-x(i)) end dotai jopa
y=0 where (x > 0.0 .and. x < 1.0) \& y=sqrt(x)+123.4*sin(x)+(a-1.0)*sqrt(1.0-x)Jo pelkästään typografiset muutokset parantavat ohjelmaa:
Jokaisen ohjelmatiedoston alussa pitäisi olla
selostus siitä, mihin ohjelmaa tai tässä
tiedostossa olevaa ohjelmanosaa käytetään.
Ohjelmaa kehitellessään tulee helposti tehneeksi
tiedostoja, joilla on sellaisia havainnollisia
nimiä kuin
Mikäli ohjelmaan on linkitettävä muissakin tiedostoissa olevia moduleita, alkukommenteissa olisi hyvä kertoa myös käännös- ja linkitysohjeet. Hyödyksi on myös tieto, mitä syöttö- ja tulostustiedostoja ohjelma mahdollisesti tarvitsee.
Älä selittele sotkuista ohjelmaa, vaan kirjoita uusiksi.
Kommenttien on vastattava ohjelman toimintaa:
if (x*y .le. 0.0) ... ! tulo negatiivinenTällaisia virheitä syntyy, kun muutetaan ohjelmakoodia, mutta unohdetaan korjata kommentit.
Kommenttien kirjoittamisessa kannattaa keskittyä oleelliseen:
i=i+1 ! lisataan i:ta yhdellaTämä ei lisää ohjelman ymmärrettävyyttä. Seuraavassa muodossa kommentti sen sijaan antaa tietoa, josta saattaa olla hyötyä:
i=i+1 ! siirrytaan matriisin seuraavalle ! vaakarivilleYleensä ei ole tarpeen selitellä yksittäisiä lauseita. Parempi on keskittyä laajempiin kokonaisuuksiin, kuten aliohjelmiin ja kokonaisiin kontrollirakenteisiin.
Aliohjelman alussa tulisi olla lyhyt selostus aliohjelman toiminnasta, sen parametreista, mahdollisista globaaleista muuttujista, sivuvaikutuksista ja funktion tapauksessa sen palauttamasta arvosta.
Hyvä tapa on kommentoida muuttujien määrittelyt. Tärkeintä on keskittyä oleellisimpiin muuttujiin; silmukan toistomuuttujia ja lausekkeissa esiintyviä tilapäisiä apumuuttujia ei kannata selittää.
c------------------------------------------------- c ratkaistaan n. asteen yhtalo x**n-1=0 c juuret palautetaan vektorissa z(1), ..., z(n) c------------------------------------------------- subroutine solven(n,z) implicit none integer, intent(in):: n ! yhtalon asteluku complex, intent(out):: z(:) ! ratkaisuvektori real, parameter:: pi=3.141592654 real phi integer k phi=2*pi/n do k=0,n-1 z(k+1)=cmplx(cos(k*phi),sin(k*phi)) enddo return end
Mitä seuraava ohjelma tekee?
NZERO=0 DO 10 I=1.5 IF (NUM(I).EQ.0) NZERO=NZER0+1 10 CONTINUEOhjelmassa on kaksi virhettä, joilta välttyy, jos kieltää implisiittiset määrittelyt.
Muuttujille on syytä käyttää selkeitä ja
merkitystä kuvaavia nimiä. Joissakin
ympäristöissä globaalien tunnusten (aliohjelmien
ja
Fortranin
dimension x(10)kun saman asian voi sanoa lyhyemmin ja selvemmin:
real x(10)Fortran 90:ssä kannattaa johdonmukaisuuden vuoksi käyttää määrittelyä
real, dimension(10) :: x
Toistorakenteet ovat erikoistapauksia n+1/2 kierroksen silmukoista. Hyvin usein vastaan tulee tilanteita, joissa lopetusehtoa ei voi kovin luontevasti testata silmukan alussa tai lopussa.
do i=0,n .. if (x(i) > 0) goto 100 ... end do 100 continue do i=0,n .. if (x(i) > 0) then ... end if end doF90:ssä tämä voidaan kirjoittaa luettavampaan muotoon
do i=0,n .. if (x(i) <= 0) exit ... end do
Jos ohjelmat suunnitellaan alusta alkaen huolella, päädytään yleensä täysin luontevasti ratkaisuihin, joissa hyppykäskyjä ei tarvita.
Jokainen
if (x .gt. 0.0) goto 200 goto 100 200 y=sqrt(x) 100 ...Tämä voidaan toteuttaa yksinkertaisemmin:
if (x .gt. 0.0) y=sqrt(x)Mitä seuraava ohjelma tekee?
if (a .gt. b) then big=a goto 100 end if big=b 100 if (big .gt. c) goto 200 big=c 200 ...Ohjelma voitaisiin kirjoittaa luettavampaan muotoon
big=a if (b .gt. big) big=b if (c .gt. big) big=cmutta itse asiassa samasta asiasta selvitään vielä yksinkertaisemmin
big=max(a,b,c)
Seuraava pätkä on todellisesta ohjelmasta:
681 FORMAT( .. ) DO 7813 LL=1,NTOT IF(LL.LE.N)WRITE(6,781)LL,XLOW(LL),XBE(LL),XUPP(LL) IF(LL.LE.N)WRITE(3,781)LL,XLOW(LL),XBE(LL),XUPP(LL) IF(LL.GT.N)WRITE(6,782)LL,XBE(LL) IF(LL.GT.N)WRITE(3,782)LL,XBE(LL) 781 FORMAT( .. ) 782 FORMAT( .. ) 7813 CONTINUE WRITE(6,7812) WRITE(3,7812) 7812 FORMAT( .. ) 78 CONTINUE 600 CONTINUE 60 CONTINUE 999 KNC=0 ... IF (N.NE.0) GOTO 100 100 CONTINUEOhjelmassa on useita sisäkkäisiä silmukoita, jotka päättyvät
Erityisen hankalia ovat aritmeettiset
Seuraava esimerkki on kirjasta Kernighan, Plaugerin: Elements of programming style:
1 SUBROUTINE MERGE(P,Q,R,S,N) 2 DIMENSION P(N), Q(N), R(N), S(N) 3 LP=1 4 LQ=1 5 LR=1 6 LS=1 7 CALL ORDER(P,Q,R,LP,LQ,LR,N) 8 IF (P(LP)) 10,9,10 9 IF (Q(LQ)) 10,13,10 10 CALL ORDER(P,Q,S,LP,LQ,LS,N) 11 IF (P(LP)) 7,12,7 12 IF (Q(LQ)) 7,13,7 13 RETURN 14 ENDOheismateriaalina on basic-ohjelma kosci.bas, joka on joskus tarttunut mukaan silloisesta Neuvostoliitosta. Yritä keksiä, mitä ohjelma tekee. (En tiedä vastausta, turha kysyä!)
real x(100,100) do i=1,n do j=1,n x(j,i)=(i/j)*(j/i) end do end doTehokas tapa:
real x(100,100), y(10000) equivalence (x(1,1), y(1)) do i=1,10000 y(i)=0.0 end do do i=1,10000,101 y(i)=1.0 end doLuonnollinen tapa:
real x(100,100) do i=1,100 do j=1,100 x(i,j)=0.0 end do x(i,i)=1.0 end doFortran 90:
real, dimension (100,100) :: x integer i x = 0.0 do i=1,100 x(i,i)=1.0 end do
Aliohjelmat perustuvat pelkästään sivuvaikutuksiin. Koska ne eivät palauta mitään arvoa, niiden täytyy tehdä jotakin muuta, jotta niillä ylipäänsä olisi vaikutusta.
Vaarallisia ovat funktiot, joilla on myös sivuvaikutuksia.
real function f(x) x=x+1.0 f=x**2 return endFunktiota voi kutsua esimerkiksi seuraavasti:
x=1.0 z=f(x)+f(x) if (f(x).gt.z .or. f(x).lt.0.0) z=xMikä on muuttujan
Toimiiko seuraava optimoitu versio samalla tavalla?
x=1.0 y=f(x) z=2*y if (y.gt.z .or. y.lt.0.0) z=xMitä tämä ohjelma mahtaa tulostaa?
call s(1) write(*,*) 1 end subroutine s(i) i=i+1 return endMuista, että Fortranissa kaikki parametrit ovat viiteparametreja, eli aliohjelmalle välitetään todellisen parametrin osoite.
Testaa syöttöarvojen järkevyys. Identifioi järjettömät syöttöarvot, ja toivu tilanteesta mikäli mahdollista. Testaa erityisesti (odottamattomat) tiedostojen loput.
Tee syöttö mahdollisimman yksinkertaiseksi ja helpoksi. Vapaamuotoinen syöttö on järkevää pieniä kontrolliarvoja varten, vain suuret data-aineistot kannattaa lukea määrämuotoisena. Tulostus sen sijaan kannattaa useimmiten tehdä määrämuotoisesti.
Sijoita syöttö- ja tulostus selkeisiin aliohjelmiin. Älä sirottele tulostuskomentoja joka paikkaan.
Käytä syöttöarvoille oletuksia, jos mahdollista. Kaiuta syötetyt arvot tulostukseen (lokiin).
Vältä myös
Lopeta aineisto sopivaan syöttötietoon, tiedoston loppuun yms. "Alä käytä lukumäärää:
do i=1,1000 read (1,*,END=100) z x(i)=z end do 100 continueAnna virheellisistä syöttötiedoista selkeä virheilmoitus.
I='41'O I=ICHAR('A')
xx = x0-x1 yy = y0-x1 z = xx**2+yy**2 z = (x0-x1)**2+(y0-y1)**2