Rösta på artikeln
Räkna med Delphi
Enkla datatyper
I Object Pascal finns en mängd olika datatyper att
välja bland för en variabel, beroende på vad för slags data som skall lagras i variabeln
och dels på vilket sätt man skall använda data på.
I detta kapitel skall vi beröra datatyper för heltal och
s k flyttal. Dessa hör till de enkla datatyperna till skillnad från string som
är en sammansatt datatyp.
Till de enkla datatyperna räknas alla heltalstyper och flyttalstyper
samt dessutom datatyperna char och boolean som behandlas senare.
Heltalstyper
Det som karakteriseras av en datatyp för heltal är
naturligtvis att alla värden i talområdet är hela tal. Men det innebär också att alla
värden i datatypen går att räkna upp, det finns endast ett ändligt antal. Ett
givet tal i talområdet kan alltid representeras av exakt av en heltalsvariabel. Beroende
på storleken av talområdet krävs olika många minnesceller, byte, till de olika heltalstyperna.
En minnescell i datorn svarar mot en byte, som i sin tur kan innehålla 8 bitar. En
bit kan bara innehålla ett binärt värde, 0 eller 1.
I tabellen nedan presenteras de datatyper för heltal som finns
i Object Pascal.
Datatyp
|
Talområde
|
Byte
|
shortint |
-128..127 |
1 |
smallint |
-32768..32767 |
2 |
integer, longint |
-2147483648..2147483647 |
4 |
byte |
0..255 |
1 |
word |
0..65535 |
2 |
cardinal |
0..2147483547 |
4 |
Flyttalstyper
Utmärkande för flyttalstyperna är att de skall kunna
representera tal med ett flytande decimaltecken, dvs decimala tal.
Notera följande!
-
Flyttal skrivs alltid med en decimalpunkt, aldrig ett decimalkomma.
-
En flyttalstyp kan innehålla oändligt många värden även om talområdet
är begränsat.
-
Ett flyttal kan vara exakt lika stort som ett givet tal.
Oftast är flyttalet endast ungefär lika stort som det givna talet. Detta hänger
ihop med att flyttalet skall representera det givna talet med hjälp av ett begränsat
antal minesceller.
I tabellen nedan menas med skrivsättet +-2.9*10-39 ..
+-1.7*1038 både talområdet -1.71038 och talområdet
2.9*10-39.. 1.7*1038. Den näst sista datatypen i tabellen
är inget flyttal. Comp är en datatyp som utnyttjar matematikprocessorn och kan enbart
representera tal.
Tabell med datatyper för flyttal.
Datatyp
|
Talområde
|
Signifikanta siffror
|
Byte
|
real |
+-2.9*10-39 ..
+-1.7*1038 |
11 - 12 |
6 |
single |
+-1.5*10-45 ..
+-3.4*1038 |
7 - 8 |
4 |
double |
+-5.0*10-324 .. +-1.7*10308 |
15 - 16 |
8 |
extended |
+-1.9*10-4932 ..
+-1.1*104932 |
19 - 20 |
10 |
comp |
-263 ..
263 -1 |
19 - 20 |
8 |
currency |
-922337203685477.5808 .. 922337203685477.5807 |
19 - 20 |
8 |
Heltal contra flyttal
Heltalstyper
-
kan representera talvärden exakt
-
tar liten plats
-
går snabbt att räkna med
Flyttalstyper (t ex double)
-
kan representera stora tal
-
men endast ungefär
-
tar stor plats
-
tar längre tid att räkna med
Allmänt gäller
-
Kan du klara dig med heltal så väljer du en heltalstyp. En heltalstyp
tar mindre plats och representerar ett exakt värde som går snabbare att göra beräkningar
med.
-
Flyttal används vid mycket stora tal och vid decimala tal.
Deklaration och tilldelning av talvariabler
Talvariabler deklareras på samma sätt som strängvariabler. Namnen
på variablerna väljer du efter de namngivningsregler som vi har diskuterat tidigare.
var
x, y, faktor : double;
i,j,k : integer;
a,b : word;
|
I variabeldeklarationen räknas upp ett antal variabler. För
varje variabel anges en datatyp, så att till variabeln kan reserveras det minne som
krävs. Variabler av olika datatyp går bra att räkna upp i samma variabeldeklaration.
Några exempel av variabeltilldelningar.
x := 1e-12; {double}
y := 2.718; {double}
k := 2.718; {integer}
a := 2000000000; {word}
|
Konvertering mellan talsträng och talvärde
Eftersom utskrifter alltid sker med hjälp av strängar,
t ex med hjälp av Caption för en Label, måste man kunna översätta talvärden till strängar.
Inmatning av ett värde görs i Delphi oftast med hjälp av egenskapen Text hos editeringsrutan,
dvs inmatningen görs till en talsträng som som du inte kan utföra räkneoperationer
med. Här måste det då göras en översättning från en talsträng till motsvarande talvärde.
Översättningar (konverteringar) från talsträngar till talvärde eller tvärtom är därför
en viktig detalj i Delphi.
Några konverteringsexempel. Först görs några variabeldeklarationer:
var
a : integer;
x : double;
s : string;
|
...sedan följer således några konverteringsexempel:
a =: StrToInt('123'); {Strängen '123' översätts
till talvärdet 123 och lagras i variabeln a}
x = : StrToFloat('123,456'); {Strängen '123,456'
översätts till talvärdet 123.456 och lagras i variabeln x}
s = : IntToStr(123); {Talet 123 översätts till strängen '123' och lagras i variabeln
s}
s = : FloatToStr(123.456); {Talet 123.456 översätts till strängen '123,456'
och lagras i variabeln s}
|
Vid konverteringen från sträng till flyttal och tvärtom med
dessa rutiner används den representation av decimaltecknet som gäller för Windows.
I de här fallen måste alltså decimaltecknet i strängarna skrivas som ett decimalkomma.
Och när Delphi översätter från ett talvärde till en talsträng skriver Delphi decimaltecknet
som ett decimalkomma.
Andra konverteringsrutiner
Med konverteringsrutinerna ovan klara du av de flesta
situationer. När man vill översätta ett flyttal till en sträng vill man emellertid
ofta ha möjlighet att formatera textsträngen. Man kanske vill ha ett visst antal decimaler,
eller kanske ha talet på decimalform eller på exponentform etc.
En konverteringsrutin som klarar detta är FloatToStrF.
I föregående exempel användes instruktionen
Label.Caption := FloatToStr(x);
Om vi istället vill använda FloatToStrF och vill att resultatet
skall bli ett decimalt tal med två decimaler och 4 gällande siffror så skriver vi:
Label.Caption := FloatToStrF(x,ffFixed,4,2);
Allmänt skriver man
Label.Caption := FloatToStrF(x,format,precision,digits);
där format är formateringssättet, precision är antalet gällande
siffror och digits antingen står för antalet decimaler eller antalet siffror i exponenten.
I tabellen nedan beskrivs de olika formateringssätten.
Formateringssätt
|
Innebörd
|
ffFixed |
Decimalformat. Talet konverteras till en sträng på formatet
"-ddd.dd". Strängen inleds med ett minustecken om talet är negativt och minst en siffra
föregår alltid decimaltecknet. Den angivna precisionen anger hur många siffror som
skall vara gällande. Om precisionen är mindre än antalet siffror före decimaltecknet
skrivs talet på exponentform. Antalet decimaler anges med digits i intervallet 0..18. |
ffExponent |
Exponentformat. Talet skrivs på formen " -d.ddd...E+dddd". Strängen
inleds med ett minustecken om talet är negativt och precis en siffra föregår decimaltecknet.
Den angivna precisionen anger hur många värdesiffror som strängen skall innehålla. |
ffGeneral |
Allmänt format. Talvärdet Talvärdet konverteras till kortast
möjliga talsträng på decimal- eller exponentformat. Decimaltecknet visas enbart om
det behövs. |
ffNumber |
Decimalformat. Samma som ffFixed med tillägget att talsträngen
förses med avgränsare för tusental. |
ffCurrency |
Myntformat. Samma som ffNumber med myntslaget angivet efter
strängen, dvs "kr". |
Kompabilitet mellan heltalstyper
Här följer en procedur som demonstrerar kompabiliteten mellan
olika datatyper.
procedure TForm1.Button1Click(Sender: TObject);
var
a : byte;
b : word;
c : integer;
x : double;
begin
x := 8; {Tilldelning med konstantvärde}
c := 7; {Tilldelning mellan variabler av olika heltalstyp går bra så länge
a := c; värdet ryms inom typerna}
b := c;
Label1.Caption := IntToStr(a);
Label2.Caption := IntToStr(b);
Label3.Caption := IntToStr(c);
Label4.Caption := FloatToStr(x);
end;
|
Konverteringarna mellan heltalstyperna i proceduren ovan möter
inga problem så länge värdena håller sig inom ramen för vad datatyperna tillåter och
de kan därmed sägas vara kompatibla.
Följande sats däremot protesterar kompilatorn emot.
a := x; {OBS! fungerar ej!}
Vi försöker här tilldela en bytevariabel värdet av en flyttalsvariabel.
En bytevariabel tar upp en byte av minnet medan en flyttalsvariabel av typen double
kräver 8 minnesceller. Av det skälet fungerar inte denna tilldelning. Däremot går
det omvända alldeles utmärkt:
x
:= a; {Fungerar!!!}
Beräkningsuttryck
Naturligtvis går det bra att använda variabler i
beräkningsuttryck. För att demonstrera detta skall vi göra ett litet ränteexempel.
Placera ut två editeringsrutor på ett formulär. Förse dem med etiketter med ledtexter
enligt bilden. Sätt Caption för Label3 till en tom sträng.
Dubbelklicka sedan på knappen och komplettera händelseproceduren
enligt nedan.
procedure TForm1.BitBtn1Click(Sender: TObject);
var
proc, kap, nykap : double;
begin
proc := StrToFloat(Edit1.Text);
kap := StrToFloat(Edit2.Text);
nykap := kap*(1+proc/100);
Label3.Caption := 'På ett år växer detta till ' + FloatToStrF(nykap, ffCurrency,10,2);
end;
|
-
Provkör sedan programmet.
I proceduren tilldelas variablerna sina värden från editeringsrutorna.
Därefter utförs ränteberäkningen och läggs i variabeln nykap. Värdet i nykap konverteras
till en textsträng med hjälp av FloatToStrF till myntformat (kr). Slutligen
skrivs resultatet ut i Label3.
Spin och Gauge
Vi skall nu se hur variabler kan användas i ett program,
där vi samtidigt passar på att bekanta oss med komponenterna Spin och Gauge.
Du hittar dessa på fliken Samples i komponentpaletten.
Gauge-komponenten är en slags visare som kan visa värden
i intervallet 0..100%. Spin-komponenten är avsedd för upp- eller nedräkning.
Placera ut en Spin- och en Gauge-komponent på ett formulär.
Lägg även till en etikett och en editeringsruta enligt bilden nedan. Ändra editeringsrutans
ReadOnly-egenskap till True.
Ändra sedan Gaugekomponentens egenskap MinValue till
10 och MaxValue till 30. Sätt egenskapen Kind till gkPie (cirkel).
Välj sedan Spinkomponenten i Objektinspektorn och klicka på fliken Events.
Komplettera därefter händelsen OnDownClick enligt nedan.
procedure TForm1.SpinButton1DownClick(Sender:
TObject);
var a : integer;
begin
a := Gauge1.Progress - 1;
Gauge1.Progress:= a;
Edit1.Text := IntToStr(Gauge1.Progress);
end;
|
Klicka i värderutan för händelsen OnUpClick och komplettera
proceduren.
procedure TForm1.SpinButton1UpClick(Sender:
TObject);
var a : integer;
begin
a := Gauge1.Progress + 1;
Gauge1.Progress:= a;
Edit1.Text := IntToStr(Gauge1.Progress);
end;
|
Kör sedan programmet!
Som du ser ändras värdet på Gauge-komponenten med 5% i taget.
Ord, Pred och Succ
På alla skalära datatyper kan du använda ordningsfunktionerna
Ord, Pred och Succ. Här skall vi visa ett exempel på hur dessa används.
Placera en editeringsruta försedd med texten "Testvärde". Koppla
en UpDown-komponent till editeringsrutan. Ändra Position för UpDown-komponenten till
50 i Objektinspektorn. Placera ytterligare tre etiketter under editeringsrutan och
en knapp med texten "Visa ordningstal". Klicka på knappen och skriv följande procedur.
procedure TForm1.Button1Click(Sender: TObject);
var a,y,z : smallint;
begin
x := UpDown1.Position;
y := Pred(x);
z := Succ(x);
Label2.Caption := 'Talet '+Edit1.Text+
'har ordningsnumret '+IntToStr(Ord(x));
Label3.Caption := 'Föregående tal är '+IntToStr(y);
Label4.Caption := 'Efterföljande tal är '+IntToStr(z);
end;
|
Ord(x) ger alltså ordningsnumret på det värde som x innehåller.
Pred(x) och Succ(x) ger föregående resp efterföljande
värde till x.
Att som ovan använda Ord på heltalstyper är självfallet
meningslöst men kan vara till nytta på typerna char och boolean.
Däremot kan Pred och Succ vara användbara på heltal.
Pred(x) ger värdet
x-1
Succ(x) ger
värdet x+1
Funktionerna Ord, Pred och Succ kan inte
användas på flyttalstyper.
Low och High
Dessa två funktion används för att ta reda på det
minsta resp det största värdet i en viss datatyp.
Ett exempel:
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text := IntToStr(Low(shortint));
Edit2.Text := IntToStr(Low(smallint));
end;
|
Inc och Dec
Två andra mycket snabba funktioner är Inc och Dec som
är avsedda att räkna upp eller ned värden av heltalstyper.
Inc(x) är detsamma
som x := x + 1;
Dec(x) är
detsamma som x := x - 1;
Vill man ändra värdet med mer än ett steg, anger man ett värde
för detta avgränsat med kommatecken.
Inc(x,3) är detsamma
som x := x + 3;
Dec(x,5) är
detsamma som x := x - 5;
Div och Mod
Två användbara heltalsoperatorer är div och mod.
Exempel på dessa.
41 div 7
= 5
Anger hur många hela gånger som 7 går i 41.
41 mod 7 = 6
Utgör den rest som blir över vid divisionen, dvs. 41-7*5
Trunc(x) och Round(x)
Trunc(x) ger det trunkerade, "avklippta", heltalsvärdet av flyttalet
x.
-
Round(x) ger det avrundade heltalsvärdet av x.
Exempel på funktionerna Trunc(x) och Round(x).
Trunc(8.4) ger
heltalsvärdet 8.
Trunc(8.7) ger
heltalsvärdet 8.
Trunc(-9.2) ger
heltalsvärdet -9.
Trunc(-8.7) ger
heltalsvärdet -8.
Round(8.4) ger
heltalsvärdet 8.
Round(8.5) ger
heltalsvärdet 9.
Round(-9.4) ger
heltalsvärdet -9.
Round(-9.5) ger
heltalsvärdet -10. |
Int och Frac
-
Int(x) trunkerar ett flyttal och resultatet blir av flyttalstyp.
-
Frac(x) ger decimaldelen av ett flyttal.
Exempel på funktionerna Int(x) och Frac(x).
Int(8.7) ger
flyttalsvärdet 8.0000
Frac(8.7) ger
flyttalsvärdet 0.70000
Int(-9.2) ger
flyttalsvärdet -9.0000
Frac(-9.2) ger
flyttalsvärdet -0.20000 |
Slumptal
Funktioner som skapar slumptal är Random och Random(n).
-
Random ger slumptal av flyttalstyp från 0 upp till 1.
-
Random(n) ger slumptal i form av heltal från 0 och upp
t o m n-1.
Anta att x är en flyttalsvariabel och a är en
heltalsvariabel.
x := Random; {Ger slumptal 0.0000 <=x< 1.0000}
x := 100*Random; {Ger slumptal
0.0000 <=x< 100.0000}
x := 5+10*Random; {Ger slumptal
5.0000 <=x< 15.0000}
a := Random(10); {Ger slumptal
0 <=a< 10-1}
a := Random(6); {Ger slumptal
0 <=a<= 5}
a := 1+Random(6); {Ger slumptal
1 <=a<= 6}
a := -5+Random(11); {Ger slumptal
-5 <=a<= 5}
|
I Object Pascal genereras alltid slumptalen på ett visst sätt.
Vill man ha en följd av slumptal anropar man Random-funktionen för så många
tal man vill ha. Problemet är bara att det alltid är samma slumptalsföljd man får.
För att komma bort från denna olägenhet kan man använda proceduren Randomize.
Med Randomize garanteras att slumptalföljden alltid startar med ett slumpvis
startvärde. Man får då verkligen en slumpmässig följd.
Det räcker med att anropa Randomize en enda gång i händelseproceduren.
|