2.4. Teckensträngar och logiska uttryck I Fortran sparar man text i variabler av typen CHARACTER. För varje tecken reserveras normalt 1 byte i minnet. För att deklarera en teckenvariabel TEXT och samtidigt reservera 30 tecken för den, använder man deklarationen CHARACTER (LEN=30) :: TEXT. Om man reserverar olika mycket utrymme för flere teckenvariabler, kan detta göras med en enda sats, t.ex. CHARACTER :: a*10, b*20, c*30, som reserverar 10 tecken för variabeln a, 20 tecken för variabeln b och 30 tecken för variabeln c. En teckenvariabel kan definieras genom att sätta den lika med ett uttryck, vars värde är en teckensträng. Ett sådant uttryck kan t.ex. vara en teckensträng omgiven av apostrofer, så att t.ex. TEXT = ABCDE definierar värdet av en teckenvariabel TEXT med 5 tecken. Om man skriver en teckensträng med mindre antal tecken än vad som har reserverats för teckenvariabeln ifråga, kommer den att utfyllas med mellanrum (blanka tecken) till sin fulla längd. Detta innebär, att om för en teckenvariabel TEXT reserverats 10 tecken, och den har definierats som TEXT = tecken, så betyder detta detsamma som TEXT = tecken. Om man å andra sidan skriver en teckensträng med flere tecken än vad som reserverats, så kommer strängen att stympas, så att den får den rätta längden. Om vi t.ex. definierar variabeln TEXT i exemplet ovan som TEXT = teckensträng, så kommer detta att betyda detsamma som TEXT = teckensträ. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 1
Som vi tidigare omnämnt i samband med utskrift av text, gäller också för teckenvariabler att apostrofer dubbleras, om sådana förekommer i teckensträngen. Sålunda skriver man t.ex. TEXT = Descartes filosofi. Man kan också utföra en operation på teckensträngar, nämligen sammanlänkning (eng.: concatenation) med sammanlänkningsoperatorn //. Ett exempel på sammanlänkning är TEXT = tec // ken. Också understrängar kan definieras genom att man skriver två heltalsuttryck efter variabelnamnet innanför parentes, samt åtskilda av ett kolon, t.ex. TEXT(2:4), som i ovanstående fall betecknar strängen eck. Om man bara vill ändra en del av en sträng, kan man också ge ett värde åt en understräng. Ett exempel på detta är t.ex. instruktionerna CHARACTER (6) :: str str = fyrtio str(2:3) = em som förvandlar fyrtio till femtio. Som ett exempel på manipulation av teckensträngar kan vi se på följande program, som skriver ut en hälsning på skärmen: Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 2
PROGRAM goddag! Exempel på manipulation av textsträngar IMPLICIT NONE CHARACTER :: titel*10, fornam*20, tilnam*20 CHARACTER (52) :: fulnam! Fråga namnet: PRINT *, Var god skriv fullständigt namn i önskad form PRINT *, Titel (herr, fru, fröken, etc...): READ *, titel PRINT *, Förnamn: READ *, fornam PRINT *, Tillnamn: READ *, tilnam! Konstruera hela namnet: fulnam = TRIM(titel)// //TRIM(fornam)// //TRIM(tilnam)! Skriv en hälsning: PRINT *, Goddag,,TRIM(fulnam),! PRINT *, Eller får jag säga,trim(fornam),? END PROGRAM goddag Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 3
Observera, att teckensträngarna utfylls till sin fulla längd. Därför har TRIM-funktionen, som putsar bort extra mellanrum använts i programmet. Vi skall nu diskutera logiska variabler, som är av betydelse speciellt i villkorssatser. En logisk variabel test deklareras med en instruktion av formen LOGICAL :: test, och definieras med ett logiskt uttryck, som antingen kan vara sant (.TRUE.), eller falskt (.FALSE.). Logiska uttryck (eller booleska uttryck) kan konstrueras med relationsoperatorer. Det finns sex relationsoperatorer i Fortran 90, som har varsin motsatta operator: Relationsoperator Motsatt operator < (mindre än) >= (större el. lika med) <= (mindre el. lika med) > (större än) == (lika med) /= (inte lika med) >= (större el. lika med) < (mindre än) > (större än) <= (mindre el. lika med) /= (inte lika med) == (lika med) Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 4
Om a och b är två reella variabler, så kan vi t.ex. konstruera logiska uttryck av formen a > b och a <= b, som är varandras motsatser. För att ange motsatsen till ett logiskt uttryck kan man också använda den logiska operatorn.not., vilket t.ex. betyder att a <= b är detsamma som.not. ( a > b). Dessutom finns det fyra andra logiska operatorer, nämligen.and. ( och ),.OR. ( eller ),.EQV. ( ekvivalent med ) och.neqv. ( inte ekvivalent med ). Med hjälp av dessa logiska (eller booleska) operatorer är det möjligt att konstruera mer komplicerade logiska uttryck. Logiska operatorer får endast verka på logiska uttryck, vilket innebär att om t.ex. a, b och c är reella variabler, så är a > b.or. a < c ett korrekt konstruerat logiskt uttryck, medan a.or. b < c är felaktigt. De logiska operatorerna följer en prioritetsordning, enligt vilken.not. har den högsta prioriteten, därpå följer.and., sedan.or., och sist.eqv. och.neqv., som alltså har den lägsta prioriteten. Denna prioritetsordning kan givetvis förändras med hjälp av parenteser. För att bestämma värdet av ett logiskt uttryck använder man en sanningstabell: Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 5
Log. uttryck Logisk Log. uttryck Logiskt A operator B resultat.not..true..false.false..true..true..and..true..true..true..false..false..false..true..false..false..false..false..true..or..true..true..true..false..true..false..true..true..false..false..false..true..eqv..true..true..true..false..false..false..true..false..false..false..true..true..neqv..true..false..true..false..true..false..true..true..false..false..false. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 6
Operatorerna.EQV. och.neqv., som är mer speciella, ger till resultat sanna värden om operanderna är ekvivalenta, resp. icke-ekvivalenta (dvs har samma logiska värden, resp. motsatta). Med hjälp av dessa operatorer kan man förenkla endel komplicerade uttryck. Sålunda innebär t.ex. (a < b.and. c < d).or. ( a >= b.and. c >= d) detsamma som a < b.eqv. c < d. Den viktigaste användningen av logiska uttryck är i villkorssatser, som har den allmänna strukturen IF ( logiskt uttryck ) THEN... ELSE... END IF Om det logiska uttrycket i ovanstående villkorssats har värdet.true., utförs satserna mellan THEN och ELSE, i motsatt fall utförs satserna mellan ELSE och ENDIF. Om ELSE fattas, kommer exekveringen att fortsätta efter ENDIF, ifall det logiska uttrycket är osant. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 7
Man kan också placera flera sådana IF-block innanför varandra: IF ( villkor 1 ) THEN... ELSE IF ( villkor 2 ) THEN... ELSE IF ( villkor 3 ) THEN... ELSE... END IF I detta fall kommer satserna mellan det sista ELSE och END IF att utföras endast om inte ett enda av villkoren 1, 2 eller 3 gäller. Endast ett av blocken kommer att utföras. Som ett exempel på användningen av villkorssatser skall vi välja ett program, som beräknar kubikroten ur ett givet tal med formeln a 1/3 = e ln a/3, (a > 0). Programmet testar, om talet till sitt absoluta värde är så litet, att roten kan anses vara noll, och beaktar dessutom, att kubikroten ur ett negativt tal fås genom att byta förtecken framför kubikroten ur det motsvarande positiva talet. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 8
PROGRAM root3! Program som beräknar tredje roten av ett givet tal IMPLICIT NONE REAL :: a, eps, x, sign eps = 1.E-20! Läs in talet PRINT *, Skriv in talet: READ *, a! Kontrollera att talet inte är noll: IF (ABS(a) < eps) THEN x = 0. ELSE sign = 1. IF (a < 0.) THEN sign = -1. END IF x = sign*exp(log(abs(a))/3.0) END IF! Skriv ut resultatet: PRINT *, Kubikroten ur,a, är,x STOP END PROGRAM root3 Detta program innehåller två IF-block innanför varandra. Kubikroten beräknas med instruktionen x = sign*exp(log(abs(a))/3.0), där absoluta värdet av argumentet använts för att man också skall kunna korrekt behandla kubikroten ur negativa tal. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 9
Vi skall nu studera ett mera komplicerat IF-block. Vi ska undersöka, om en given punkt (x, y) ingår i rektangeln A: {0 x 2, 0 y 1}, rektangeln B: {1 x 2, 0 y 2} eller i bägge två. Programmet ser ut såhär: PROGRAM punkter IMPLICIT NONE LOGICAL rektangel_a, rektangel_b REAL x,y PRINT *, Skriv ett talpar x, y: READ *, x, y rektangel_a = (x>=0.and. x<=2.and. y>=0.and. y<=1) rektangel_b = (x>=1.and. x<=2.and. y>=0.and. y<=2) IF(rektangel_A.AND. rektangel_b) THEN PRINT *, Punkten finns i båda rektanglarna! ELSE IF(rektangel_A) THEN PRINT *, Punkten finns i rektangel A ELSE IF(rektangel_B) THEN PRINT *, Punkten finns i rektangel B ELSE PRINT *, Punkten är utanför rektanglarna! END IF END PROGRAM punkter Som vi ser, kan logiska variabler lätt konstrueras med hjälp av logiska uttryck. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 10
2.5. DO-slingor och programkontroll I Fortran 90 finns en särskild satskonstruktion för att välja ett av flere möjliga alternativ, beroende av värdet för ett uttryck. Denna konstruktion kallas CASE, och har följande allmänna form: SELECT CASE ( uttryck ) CASE ( selektor ) ( Fortran-satser ) CASE ( selektor ) ( Fortran-satser )... END SELECT Den första satsen i CASE-konstruktionen har formen SELECT CASE (uttryck), där uttrycket kan vara ett heltalsuttryck, teckenuttryck eller logiskt uttryck (observera: inte reellt uttryck!). Värdet av detta uttryck beräknas, varpå satserna som följer efter den lämpligaste CASE-satsen utföres. En CASE-sats har antingen formen CASE (selektor) eller CASE DEFAULT (ifall inte någon av de övriga CASE-satserna går att tillämpa). Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 11
En selektor kan se ut på fyra olika sätt: a) ett enkelt värde. I detta fall utförs de efterföljande Fortran-satserna endast om det ovannämnda uttrycket är lika med detta värde. b) ett värde efterföljt av kolon (:). I detta fall utförs de efterföljande Fortran-satserna endast om detta värde är mindre eller lika med ovannämnda uttryck. c) ett värde som föregås av kolon (:). I detta fall utförs de efterföljande Fortran-satserna endast om det ovannämnda uttrycket är mindre eller lika med detta värde. d) två värden, åtskiljda av ett kolon. I detta fall utförs de efterföljande satserna endast om det mindre värdet är mindre eller lika med uttrycket och uttrycket är mindre eller lika med det större värdet. Som ett enkelt exempel på användningen av en dylik CASE-konstruktion skall vi studera ett program, som svarar Gomorron, Goddag, Goafton eller Gonatt, beroende på vad klockan är: Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 12
PROGRAM dagstid IMPLICIT NONE CHARACTER (LEN=5) :: klockan CHARACTER (LEN=2) :: timmen! Fråga tiden: PRINT *, "Vad är klockan (skriv tiden som xx:yy)" READ *, klockan! Ta reda på timmen: timmen = klockan(1:2)! Skriv ett svar SELECT CASE (timmen) CASE ("06":"11") PRINT *, "Gomorron!" CASE ("12":"17") PRINT *, "Goddag!" CASE ("18":"23") PRINT *, "Goafton!" CASE ("00":"05") PRINT *, "Gonatt!" CASE DEFAULT PRINT *, "Omöjligt!" END SELECT STOP END PROGRAM dagstid Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 13
Ett annat exempel är ett program som löser en andragradsekvation, och använder en SELECT-konstruktion för att skilja mellan de olika fallen (två reella rötter, två sammanfallande rötter, eller ingen reell rot). PROGRAM kvadekv IMPLICIT NONE REAL, PARAMETER :: eps=1.e-7 REAL :: a,b,c,d,d1,x1 INTEGER :: selektor PRINT *, "Ge koefficienterna a, b och c:" READ *, a,b,c! Räkna ut diskriminanten d = b*b - 4*a*c! Dividera med eps (mindre tal räknas som noll) selektor = d/eps x1 = -b/(a+a) SELECT CASE (selektor) CASE (1:)! Två rötter d1 = SQRT(d)/(a+a) PRINT *, "Ekvationen har rötterna: ",x1+d1," och ",x1-d1 CASE (0)! En rot PRINT *, "Ekvationen har roten ",x1 CASE (:-1)! Inga rötter PRINT *, "Ekvationen har inga reella rötter!" END SELECT STOP END PROGRAM kvadekv Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 14
Numeriska beräkningar görs mycket ofta iterativt, dvs man upprepar en viss sekvens av instruktioner många gånger tills önskat resultat uppnås. I Fortran sker detta med hjälp av DO-slingor, som inleds av DOinstruktion DO n ind = i 1, i 2, i 3. Här betecknar ind den s.k. DO-variabeln (vanligen en heltalsvariabel), som bestämmer hur många gånger slingan upprepas. Uttrycket i 1 anger DO-variabelns begynnelsevärde, i 2 dess slutvärde, och i 3 ökningen (som bör vara olika 0). Om i 3 lämnas bort, antas ökningen vara 1. När en DO-sats utförs, kommer DO-variabelns begynnelsevärde, slutvärde och tillskott först att räknas ut, varefter den antar sitt begynnelsevärde i 1. Därpå beräknas iterationstalet enligt formeln max[int( i 2 i 1 +i 3 i ), 0], där int anger en heltalsdivision. Om iterationstalet blir lika med 0, avbryts 3 utförandet av slingan, och kontrollen flyttas över till den första instruktionen efter slingan, som blir inaktiv. Slingan DO i=1,42,5 kommer således att utföras max[int( 42 1+5 5 ), 0] = 9 gånger. Som vi ser, kommer inga iterationer att utföras, om i 1 > i 2 och i 3 > 0 eller i 1 < i 2 och i 3 < 0. Så länge iterationstalet är positivt utförs instruktionerna i DO-slingan ända till den sista satsen, som har satsnumret n (i kolumnerna 1-5). I Fortran 77 var denna sats vanligen CONTINUE, men kunde också vara någon annan sats, som inte förändrar programflödets riktning. I Fortran 90 avslutas en DO-slinga av kommandot END DO, som också godkänns av många kompilatorer som följer den äldre standarden. Detta kommando behöver inte något satsnummer. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 15
Den allmänna formen av en programslinga är därför enklare i Fortran 90: DO ind = i1, i2, i3... ( Programsatser )... END DO Här bör DO-variabeln ind bör vara en heltalsvariabel, och dess begynnelsevärde, slutvärde och tillskott är heltalsuttryck. Sedan programflödet nått slutet av slingan, ökas DO-variabeln med värdet av i 3, och iterationstalet minskas med 1, varpå iterationstalet testas. På grund av DO-variabelns speciella betydelse för DO-slingan, är det inte tillåtet att förändra dess värde i någon sats inom slingan. Man bör ytterligare observera, att det inte är DO-variabelns värde som bestämmer vad som händer, utan istället iterationstalet, vars värde minskar med 1 för varje genomgång av slingan. När alla iterationer har utförts, kommer DO-variabeln att anta det värde den skulle ha fått ifall slingan skulle ha genomgåtts en gång till. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 16
Som ett exempel skall vi studera ett program, som skriver ut multiplikationstabellerna från 2 till 10 i formen 2:ans tabell 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 2 x 4 = 8 2 x 5 = 10 2 x 6 = 12 2 x 7 = 14 2 x 8 = 16 2 x 9 = 18 2 x 10 = 20... 3:ans tabell 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 3 x 4 = 12 3 x 5 = 15 3 x 6 = 18 3 x 7 = 21 3 x 8 = 24 3 x 9 = 27 3 x 10 = 30 Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 17
Programmet, som använder två DO-slingor ser ut såhär: PROGRAM tabula IMPLICIT NONE! Ett program för att skriva ut multiplikationstabeller INTEGER :: i,j DO i=2,10 PRINT *, PRINT *, i, :ans tabell DO j=1,10 PRINT *, i, x, j, =,i*j END DO END DO STOP END PROGRAM tabula I detta exempel ligger de båda DO-slingorna i sin helhet innanför varandra. Observera, att det inte är tillåtet att låta två slingor korsa varandra. Vi skall se på ett annat exempel, som visar hur man kan beräkna en fakultet (t.o.m. 12!) med en DO-slinga, där tillskottet är negativt. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 18
PROGRAM fakult! Program för att beräkna fakulteter IMPLICIT NONE INTEGER :: n, fac, i PRINT *, Ge ett positivt heltal: READ *, n! Bilda produkten n*(n-1)*...*2*1 fac = 1 DO i=n,2,-1 fac = fac*i END DO! Skriv resultat: PRINT *, Fakulteten är,fac STOP END PROGRAM fakult Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 19
Som ett ytterligare exempel på användningen av DO-slingor skall vi se på ett program, som beräknar ett nollställe av f(t) = cos(t) 1/t med Newtons metod: Program newt! Programmet söker ett nollställe av f(t)=cos(t)-1/t! med Newtons metod IMPLICIT NONE REAL :: t INTEGER :: i PRINT *, Ange ett begynnelsevärde för t: READ *, t DO i=1,20 t = t-(cos(t)-1./t)/(-sin(t)+1./(t*t)) PRINT *, it =,i, t =, t END DO END PROGRAM newt Denna funktion har många nollställen, som vi lätt kan se. Introduktion till vetenskapliga beräkningar II, Tom Sundius 2009 20