Merkkijonoissa ja kommenteissa voi yleensä käyttää muitakin merkkejä.
Lause päättyy rivin loppuun, ellei muuten osoiteta.
Rivin lopussa oleva &-merkki ilmoittaa, että lause jatkuu seuraavalla rivillä. Lauseen maksimipituus 40 riviä.
Rivin loppu huutomerkistä eteenpäin on kommenttia, joka ei vaikuta ohjelman toimintaan.
integer real logical (arvo .true. tai .false. ) complex double precision characterMuuttuja voidaan alustaa määrittelyn yhteydessä:
integer :: n=0 real :: x=0.1Vakiot:
integer, parameter :: maxn=1000 real, parameter :: pi=3.141592654
Määritellään kind-määreellä:
integer, (kind=1) :: nKind-määreen arvot toteutuskohtaisia. Siis ei käytetä näin, vaan haetaan sopiva arvo systeemifunktiolla:
integer, (kind=selected_int_kind(5)) :: nNyt muuttujalle n varataan tila, johon mahtuu ainakin 5 numeron kokonaisluku.
real (kind=selected_real_kind(5)) :: a, b real, (kind=selected_real_kind(10,50)) :: xMuuttujien a ja b tarkkuus 5 merkitsevää numeroa, muuttujassa x 10 merkitsevää numeroa ja eksponentti välillä [-50, 50].
integer, parameter :: short=selected_int_kind(4), & long=selected_int_kind(7), & longreal=selected_int_kind(10, 100) integer (kind=short) :: i,j integer (kind=long) :: isoluku real (kind=longreal) :: bigVakiot:
Kokonaisluvut
123 123_short 1234567_longReaaliluvut
1.5 -1.5 1.5E10 1.5E-10 1.5_longreal 1.5E-10_longrealKompleksiluvut
complex z z = (1.0, -1.0) ! z=1-i
program koe character a='A' character (len=3) :: b='xyz' character (len=6) :: c,d,e c = b//a//'qq' ! katenaatio d = c d(1:2)='--' e='X' write(6,*) a,b,c,d,e end programOhjelman tulostus
A xyz xyzAqq --zAqq X
i=100 x=1.5Ensin lasketaan koko oikea puoli ja muunnetaan ennen sijoitusta vasemman puolen mukaiseksi.
1.0+2.0*y/z**2-3.5*sqrt(y+x)Normaali assosiatiivisuus:
Kokonaislukujen jakolaskun tulos on kokonaisluku (osamäärän kokonaisosa)
sin(x), cos(x), tan(x) asin(x), acos(x), atan(x), atan2(y,x) sinh(x), cosh(x), tanh(x) exp(x), log(x), log10(x), sqrt(x) min(x, y, ...), max(x, y, ...) abs(x)
== .eq. /= .ne. < .lt. <= .le. > .gt. >= .ge.Loogiset vakiot:
.true. .false.Loogiset operaattorit:
.and. .or. .not.X.and.Y on tosi, jos ja vain jos X==.true. ja Y==.true..
X.or.Y on tosi, jos X==.true. tai Y==.true. tai molemmat ovat tosia.
.not.X on tosi, jos X==.false.
Samalla rivillä voi olla useita lauseita, jotka erotetaan puolipisteellä.
if (x > 0.0) y = 1/x if (x > 0.0 .and. x < 100.0) y=exp(x) if (x > 0.0) then y=1/x z=log(x) end if
Kaksi vaihtoehtoa
if (x > 0.0) then y=1/x else y=0.0 end if
Useampia vaihtoehtoja
if (x > 0.0) then y=log(x) else if (x < 0.0) then y=-log(abs(x)) else y=0.0 end if
sum=0.0 do i=1,100 sum=sum+i end do
sum=0.0 do i=0,100,2 ! parillisten lukujen summa sum=sum+i end do
Testataan silmukan suoritusehtoa ennen silmukan suoritusta. Jo ehto on heti epätosi, silmukkaa ei suoriteta kertaakaan.
sum=0.0 ; term = 1.0 do while (term > 1.0E-5) sum=sum+term term=term*0.1 end doTestataan lopetusehtoa silmukan keskellä (n+1/2 kierroksen silmukka):
sum=0.0 ; i = 1 do sum=sum+1.0/i if (sum > 10) exit i=i+1 end do
x0 = 0.5 n=0 do x1=(1.0+x0)**0.2 if (abs(x1-x0) < 0.0001) exit n=n+1 if (n > 100) exit x0=x1 end do
read (laitenumero, formaatti) muuttujaluettelo write (laitenumero, formaatti) muuttujaluettelo open (laitenumero, tiedoston attribuutit) close (laitenumero)Kullakin tiedostolla on yksikäsitteinen laitenumero (LUN, logical unit number).
Perinteisesti 5=kortinlukija (nykyisin yleensä pääte), 6=rivikirjoitin (se sama pääte).
Formaatti on merkkijono, joka määrittelee, miten tulostus muotoillaan. Vapaan formaatin merkki on *.
Vapaamuotoinen tulostus:
i=10; x(i)=1.2345 write (6,*) i, x(i) 10 1.23450005Muotoiltu tulostus
write (6, '(I3,F5.2)') i,x(i)Muotoimet:
In kokonaisluku n numerolla
Fn.d reaaliluku, kaikkiaan n merkkiä, d desimaalia
En.d tulostus eksponenttimuodossa
Jos luku ei mahdu kenttään, tulostetaan n tähteä; jos luku ei täytä koko kenttää, se tasataan oikeaan reunaan
An n merkin merkkijono; jos tulostettava merkkijono ei mahdu kenttään, tulostetaan vain n ensimmäistä merkkiä; jos merkkijono on lyhempi kuin n, se tasataan kentän oikeaan reunaan
nX ohitetaan n merkkiä
Tn (tabulaattori) siirrytään sarakkeelle n
/ rivinvaihto
Automaattinen rivinvaihto jokaisen writen jälkeen.
Jos tulostettavia on enemmän kuin muotoimia, tehdään rivinvaihto ja aloitetaan muotoinluettelo uudelleen alusta.
real x(10) write(6,'(F5.2)') x ! tulostaa 10 rivia write(6,'(10F5.2)') x ! tulostaa samalle riville write(6,'(30F5.2)') x ! tulostaa vain 10 lukua write(6,'(3F5.2)') x ! tulostaa 4 riviä (3+3+3+1 lukua)
Muotoin on vain merkkijono, jota ei tarkisteta käännösaikana. Suoritus voi kaatua ajoaikana, jos muotoin ei vastaa tulostettavan luvun tyyppiä.
read: samat muotoimet kuin tulostuksessa.
Vapaamuotoinen syöttö: muuttujat annetaan pilkuilla erotettuina:
real x integer n read(5,*) x,n 1.5,20Muotoiltu syöttö (lähinnä tiedostojen lukemiseen):
read(5,'(F4.1I2)') x,n ! 1.520 !1.5 20 ! 1520Kaikki antavat tuloksen x=1.5, n=20. Viimeisessä tapauksessa luetaan 4 merkin kenttä ( 15), josta yksi merkki tulkitaan desimaaliosaksi.
1) Pääohjelma + mahdollisia sisäisiä proseduureja
2) Yksi tai useampia ulkoisia proseduureja
3) Moduuli, joka voi sisältää muuttujien määrittelyjä ja omia sisäisiä proseduurejaan
1) Funktio, joka palauttaa jonkin arvon:
program ... y = sinc(1.5) contains real function sinc(x) real x sinc = sin(x)/x end function end program
2) Aliohjelma, jonka toiminta perustuu sivuvaikutuksiin: aliohjelma muuttaa parametrejaan tai globaaleja muuttujia, tulostaa jotakin jne.
Aliohjelmaa kutsutaan call-lauseella.
program ... call store (n) contains subroutine store(n) integer n write(6,*) n return end subroutine end program
real, save :: xJos usein kutsuttavassa aliohjelmassa suuria dynaamisesti varattavia taulukoita, toiminta hidastuu
program esimerkki real x, y, z, u x=0.1 y=1.0 z=1.0 u=f(x) write (*,'(4F10.4)') x,y,z,u contains real function f(x) real x, y y=x**2 z=sin(x) f=z * y end function end program esimerkkiTulostus:
0.1000 1.0000 0.0998 0.0010Pääohjelman muuttujat x, y, z, u ovat globaaleja.
Funktion y on paikallinen, joten sen muuttaminen ei vaikuta kutsuvan ohjelman muuttujaan y.
Funktion sisällä ei ole määritelty muuttujaa z, joten se viittaa globaaliin muuttujaan z. Tämä on funktion sivuvaikutus, eikä välttämättä toivottu.
x=1 call sub(x) write(6,*) x ! 2 call sub(1) ! ?? call sub(x+y) ! ?? subroutine sub(x) real x x=x+1 end
subroutine sub (x) real, intent(in) :: x x=x+1 ! kielletty! end
Intent-attribuutti
out: todellinen argumentti saa olla vain muuttuja; aliohjelman on annettava sille arvo, mutta muuttujaa ei saa käyttää esim. sijoituslauseen oikealla puolella.
inout: ei käyttörajoituksia, mutta todellisen argumentin oltava muuttuja.
Intent-attribuutti puuttuu: ei mitään rajoituksia.
Avainsanaparametri (keyword): jrjestys vapaa, parametri tunnistetaan nimen perusteella.
subroutine huu(x,y,z) real x, y, z ... endKutsu voi olla
real a, b, c call huu(a, b, c) call huu(a, z=b, y=1.0) call huu(z=b, x=a, y=c) call huu(x=a, b, c) ! kiellettyValinnainen parametri voi puuttua:
subroutine haa(x,y,z) real x real, optional :: y,z real zz=42.0 .. if (present(z)) zz=z endSopii tilanteeseen, jossa muuttujalla yleensä järkevä oletusarvo.
call haa(a) call haa(a, 0.1) call haa(a, b, c) call haa(a, z=1.5) call haa(x=a, z=1.5, y=1.0)argumentti voi olla muuttuja, vakio tai lauseke.
Funktiolla voi olla myös sivuvaikutuksia; niitä tulisi välttää.
Funktiolle on aina määriteltävä tyyppi.
real function sinc(x) real, intent(in) :: x if (abs(x) < epsilon) sinc=1.0 else sinc = sin(x)/x endif end functionFunktion arvo voi olla mikä tahansa muuttujatyyppi
real x(3),y(3) x(:) = (/ 1, 2, 3 /) y=inv(x,3) ... function inv(x,n) real, dimension(:), intent(in) :: x real, dimension(size(x)) :: inv integer n inv=x(n:1:-1) end
Funktio voi olla rekursiivinen:
recursive function fibonacci(n) result(f) integer :: f integer, intent(in) :: n if (n<=2) then f=1 else f=fibonacci(n-2)+fibonacci(n-1) endif endMelko vähän käyttä numeerisissa tehtävissä.
Sopii esimerkiksi puiden ksittelyyn:
program tree integer, parameter :: n=5 integer left(n), right(n), data(n) left(:) = (/ 2, 4, 5, 0, 0 /) right(:) = (/ 3, 0, 0, 0, 0 /) data(:) = (/ 10, 20, 30, 40, 50 /) writetree (1) contains recursive subroutine writetree(n) integer n if (left(n) > 0) writetree(left(n)) write (6,*) data(n) if (right(n) > 0) writetree(right(n)) end end program
module funcs contains real function sinc(x) ... end function sinc ... end module funcsModuuli käännetään erikseen ja otetaan käyttöön use-lauseella:
program koe use funcs ... u=sinc(x) ... end programKäännös esimerkiksi
f95 -c funcs.f90 ... f95 koe.f90 funcs.o
Ohjelman paloittelu toiston välttämiseksi tai aliohjelmien koon pitämiseksi pienenä voi johtaa huonoon lujuuteen.
Ulkoiset kytkennät:
Mitä enemmän aliohjelma riippuu globaaleista muuttujista
ja muista aliohjelmista sitä vaikeampi ohjelmaa on muuttaa.
Ideaalitilanne on, että kaikki tieto välitetään parametreina (vrt. sin, sqrt).
real x(3) real, dimension(3) :: a,b,c real, (kind=selected_int_kind(8)), dimension(0:5) :: zIndeksin alarajan oletusarvo on 1. Voidaan muuttaa määrittelyssä:
real x(0:10) real, dimension(-10:10) :: yMyös taulukko voidaan alustaa määrittelyn yhteydessä:
real, dimension(3) :: x = (/ 0.0, 0.5, 1.0 /) real, dimension(-10:10) :: y = 0.0Monet operaatiot voivat kohdistua kokonaisiin taulukoihin:
a=0.0 a(1)=1.0 a=b+c a=a+1 a=sqrt(b)
Taulukon indeksinä voi olla myös kokonaislukutaulukko:
integer, dimension(3) :: ind = (/ 4, 1, 3 /) integer, dimension(5) :: x = (/ 0, 2, 5, 1, 3 /) write(*,*) x(ind) 1 0 5
real, dimension (n) :: x real :: tmp integer :: i,j do i=1,n-1 do j=i+1,n if (x(j) < x(i)) then tmp=x(i) ; x(i)=x(j) ; x(j)=tmp end if end do end foAjankäyttö verrannollinen n2. Järkevää vain pienille taulukoille; Ei kannata suurille, kun on parempiakin menetelmiä.
Quicksort (rekursiivinen) yleensä nopea, mutta huono jo valmiiksi järjestyksessä olevalle aineistolle.
Kekolajittelu (heapsort) takaa, että aika korkeintaan n log n.
real y(2,3) ! y(1,1) y(1,2) y(1,3) ! y(2,1) y(2,2) y(2,3) x = y(i, j) y(1, i-j) = z+0.5 * y(2,i)
real, dimension(-1:1,0:100) :: z ! z(-1,0) z(-1,1) ... z(-1,100) ! z( 0,0) z( 0,1) ... z( 0,100) ! z( 1,0) z( 1,1) ... z( 1,100)Useampiulotteiset samalla tavalla:
real, dimension(2,2,2) :: u ! u(1,1,1) u(1,1,2) ... u(2,2,2)
Fortranissa 2-ulotteinen taulukko talletetaan sarakkeittain:
real y(0:1,0:2)
y(0,0) y(0,1) y(0,2) y(1,0) y(1,1) y(1,2)Tämän alkiot ovat muistissa järjestyksessä
y(0,0) y(1,0) y(0,1) y(1,1) y(0,2) y(1,2)C:n taulukko y[2][3] talletetaan riveittäin
y[0][0] y[0][1] y[0][2] y[1][0] y[1][1] y[1][2]Asialla merkitystä tehokkuuden kannalta, jos käsiteltävä taulukko on hyvin suuri.
integer, dimension (3) :: x, y, & a = (/ 0, 1, 2 /), & b = (/ 1, 3, 1 /) x = a+b ! x = (/ 1, 4, 3 /) y = a*b ! y = (/ 0, 3, 2 /) y = 2*b ! y = (/ 2, 6, 2 /)Operaattorit kohdistuvat vastinalkioihin; * ei ole matriisitulo.
Lausekkeessa esiintyvien taulukoiden oltava yhteensopivia.
Varusfunktiot voivat kohdistua kokonaiseen taulukkoon
real, dimension (100) :: x, y x=0.1*(/ (i, i=1,100) /) y=sqrt(x)Sijoituslauseen molemmilla puolilla oltava yhteensopivat taulukot.
Poikkeus: skalaari (yksinkertainen muuttuja) on yhteensopiva kaikkien taulukoiden kanssa:
real, dimension (100) :: x, y real :: a y = 1.0 x = y + aYhden alkion taulukko ei ole yksinkertainen muuttuja:
real, dimension(1) :: x real :: y ... x = y ! OK y = x ! KIELLETTY
real, dimension (100) :: x real :: x0, x1 integer, dimension(1):: k0, k1, i0, i1 ! HUOM, taulukkoja k0 = lbound(x) ! indeksin alaraja k1 = ubound(x) ! ylaraja x0 = minval(x) ! pienin arvo x1 = maxval(x) ! suurin arvo i0 = minloc(x) ! pienimman arvon indeksi i1 = maxloc(x) ! suurimman arvon indeksiToimivat myös useampiulotteisille taulukoille:
real, dimension (2,3) :: x integer lo(2), hi(2), i1(2) x(1,:) = (/ 1, 2, 3 /) x(2,:) = (/ 2, 5, 1 /) lo=lbound(x) ! lo = (/ 1, 1/) hi=ubound(x) ! hi = (/ 2, 3/) i1=maxloc(x) ! i1 = (/ 2, 2/)Maxloc = suurimman alkion paikka taulukon alun suhteen:
real, dimension (10:14) :: & x=(/ 0.0, 1.0, 5.0, 2.0, 1.0 /) integer, dimension(1):: l, n, i l = lbound(x) ! l = (/ 10 /) n = ubound(x) ! n = (/ 14 /) i = maxloc(x) ! i = (/ 3 /)
real, dimension (2,2) :: a, b, c real, dimension(3) :: & v1 = (/ 1.0, 2.0, 3.0 /), & v2 = (/ 2.0, 0.0, 1.0 /) real :: z, s, p a (1,:) = (/ 1.0, 1.0 /) a (2,:) = (/ 0.0, 1.0 /) b (1,:) = (/ 2.0, 0.0 /) b (2,:) = (/ 0.0, 1.0 /) s = sum(a) ! alkioiden summa s = 3.0 p = product(v1) ! alkioiden tulo p = 3.0 ! skalaaritulo ! z = v1(1)*v2(1) + v1(2)*v2(2) + v1(3)*v2(3) ! ( = sum(v1*v2) ) z = dot_product(v1, v2) ! z = 5.0 c = matmul (a, b) ! matriisitulo ! c(1,1) = 2.0 c(1,2) = 1.0 ! c(1,1) = 0.0 c(1,2) = 1.0 c = matmul (b, a) ! c(1,1) = 2.0 c(1,2) = 2.0 ! c(1,1) = 0.0 c(1,2) = 1.0
real, dimension(100) :: a, b, c real, dimension(10, 100) :: d integer :: i,j b(1:10) = c(51:60) a = d(1,:) c = a(100:1:-1)+b i=4 ; j=20 d(1:3,1:5) = d(i:i+4:2, j:j+4) d(:,1) = d(5, 10:19)Taulukkosektio voi olla mielivaltainen suorakulmainen, tasavälinen hila. Sijoituslauseen oikea puoli lasketaan aina kokonaan ennen sijoitusta.
integer a(3) a= (/ 0, 1, 2 /) a (2:3) = a (1:2) ! a=(/ 0, 0, 1 /)Tämä toimii eri tavalla kuin silmukka
do i=2,3 a(i) = a (i-1) end doTaulukoiden käsittelyyn where-lause:
where (x /= 0.0) y=1/x where (x > 0.0) y = 1/x z = log(x) end where where (x > 0.0) y = 1/x z = log(x) elsewhere y = 0.0 z = 0.0 end whereSama asia silmukalla:
do i=1,n if (x(i) > 0.0) then y(i) = 1/x(i) z(i) = log(x(i)) else y(i) = 0.0 z(i) = 0.0 end if end do
do i=1,100000 x=a(i) ... end doUseimmissa tapauksissa viitattu alkio on samalla sivulla kuin edellinenkin, joten tarvittava sivu on todennäköisesti jo valmiiksi muistissa.
Jos viittaukset kohdistuvat kaukana toisistaan oleviin alkioihin, ne osuvat usein eri sivuille. Mikäli kyseessä on suuri taulukko, aikaisemmin käytettyjä sivuja ehditään ehkä palauttaa levylle ennen kuin niihen viitataan uudestaan. Sivunpuutoskeskeytysten määrä voi kasvaa huomattavasti.
Muistiviittausten lokaalisuus: peräkkäiset viittaukset kohdistuvat aina lähellä toisiaan oleviin osoitteisiin.
Lokaalisuus parantaa muistin käytön tehokkuutta ja siitä on etua myös välimuistin (cache) käytön optimoinnissa.
Useampiulotteisten taulukoiden käsittely voi aiheuttaa ongelmia. Fortranissa taulukot talletetaan muista ohjelmointikielistä poiketen sarakkeittain eikä riveittäin.
do i=1,1000 do j=1,1000 x=a(i,j) ... end do end doSisemmässä silmukassa haetaan taulukosta {\tt a} joka tuhannes alkio, jotka ovat kaikki eri sivuilla.
Ohjelma toimii paljon tehokkaammin, jos silmukoiden järjestys voidaan vaihtaa:
do j=1,1000 do i=1,1000 x=a(i,j) ... end do end do