Värdetyper: Integer & float point

Download pdf here: Value Types

Vi har kikat på datatyper och variabler i en tidigare artikel. Vi vet att det finns olika datatyper som definierar vad en variabel kan innehålla. Den form av datatyp vi då undersökt hamnar inom en (av två kategorier); Value Type (Värdetyper). Den andra kategorin är Reference Type, men vi väntar med denna. Exempel på en Value Type är int (integer). Nu är det så att det finns massvis av fler datatyper som hanterar värden vars uppgift är den samma som integer (att lagra heltal i variabler). För att förstå skillnaden mellan dessa olika datatyper inom måste vi förstå hur vi lagrar värdena. Detta innebär att vi måste förstå vad en Bit och en Byte fungerar.

Bit och Byte

En Byte innehåller åtta bitar. I bilden nedan illustreras varje Bit med klamrar [ ].

När vi lagrar information i datorn görs detta med ettor och nollor. Datorn använder alltså binärtal (0-1) istället för decimaltal (0-9). Det binära talsystemet har en bas på 2 (”två upphöjt med” eller 2^). Detta illustreras i bilden under. Första Biten (f.v) 2^0 vilket beskriver det potentiella värdet på Biten (1).

En Bit är egentligen bara en binär siffra (1 eller 0) medan en Byte är åtta binära siffror (00000001) som tillsammans bildar ett tal. Första Biten (f.v.) är 2^0 (”två upphöjt med 0”) vilket är bildar siffran 1. Andra Biten är 2^1 vilket bildar siffran 2. Tredje Biten är 2^2 vilket bildar siffran 4. Fjärde Biten är 2^3 vilket bildar talet 8. Det jag hoppas ni ser nu är att talen som bildas alltid ökar med det dubbla: 1, 2, 4, 8, 16, 32, 64 och 128. Det andra som jag hoppas att ni ser är att vi börjar med noll (2^0) och inte ett. För en grafiker som mig är den bästa kopplingen för att komma ihåg hur detta fungerar är att tänka på ”the power of two” som förklarar sprite- och texturstorlekar.

Det vi vet är att varje Bit ökar i värde. Varje Bit är antingen det givna värdet (1, 2, 4, 8, 16, 32, 64, 128) eller 0. Detta görs genom att man placerar antingen 1 eller 0 i varje Bit. I exemplet nedan beskrivs har Biten längst till höger en etta i sig. Vi vet att Biten är värd 1 (2^0 = 1). Genom att placera 1 i Biten så multipliceras Bitens värde (1) med talet 1 (1*1) vilket då definierar värdet på Biten vilket är 1. Om vi sätter 0 i samma Bit (som är värd 1 (2^0)) multiplicerar vi värdet 1 med 0 vilket definierar att värdet INTE är 1 utan 0. Vi kan räkna på Biten längst till vänster (2^7) eller valfri annan Bit för att exemplifiera en gång till. Biten längst till vänster har ett värde på 128 (2^7). Detta gör att Biten antingen kommer att bli 128 eller 0 beroende på om vi placerar 1 eller 0 i Biten. För att få ett värde på 128 så placerar vi 1 i denna Bit (128*1 = 128). För att få ett värde på 0 placerar vi 0 i denna Bit (128*0 = 0). Det handlar alltså om ”antingen eller”.

Vi kan beskriva 1 och 0 som: (1) ”Ja, använd denna Bit” eller (0)”Nej, använd inte denna Bit”.

Nu när vi vet hur man räknar varje Bit så kan vi räkna ut vad de tillsammans skapar för värde, alltså värdet på vår Byte. Detta görs med simpel addition. I exemplet nedan illustreras en Byte med ett värde på 1. Alla Bitar har ett värde på 0 utom Biten längst till vänster som har ett värde på 1. Detta gör vår uträkning mycket enkel: 0+0+0+0+0+0+0+1 = 1. Denna Byte har ett värde på 1.

Välj gärna att sätta ettor och nollor i olika Bitar och räkna på dem, vad får du för resultat? Kan du komma till en slutsats av det minsta möjliga värde på en Byte och dess maximala värde?

Hoppas du funderat och räknat lite på det nu. Vi kan få ett värde mellan 0 och 255, alltså: 0+0+0+0+0+0+0+0 = 0 och 0+2+4+8+16+32+64+128 = 255. Du kan alltså skapa vilket värde du vill inom detta spann, alltså 256 olika värden. Här nedan följer ett exempel på en Byte innehållande talet 220.

Som ni märker är det tämligen omständigt att räkna på detta sätt, så vi kan vara glada över att vi slipper räkna på detta och egentligen bry oss om det över huvudtaget. Pjuh, vi är alltså inte helt körda om vi inte förstår det. Däremot är det viktigt att ha en uppfattning om vad det handlar om då vi måste förstå vilka värden som våra olika datatyper kan innehålla. Vi har än så länge tittar på en Byte som kan innehålla ett värde mellan 0 och 255, alltså enbart positiva tal. Denna typ kallas för ”unsigned”. Nu ska vi titta på en typ av Byte som innehåller negativa och positiva tal, denna typ kallas för ”signed”. Den har ett lika stort spann av värden som ”unsigned” (alltså 256 möjliga värden), men spannet går mellan -128 till +127.

Principen för att räkna och lagra värdena är den samma. Lägst tal till höger och högst tal till vänster. Aktivera Bitens värde eller ge Biten ett värde på noll, och därefter räkna ihop alla Bitarna så vet vi vad Bytens värde är. Skillnaden från ”unsigned” är att det största talet (t.v) på 2^7 (i en ”signed”) är att biten representerar ett negativt tal, alltså -128 och aldrig 128. Alla andra Bitar är positiva. I exemplet nedan visas överst en signed byte innehållande ett positivt tal (9) och nederst en signed byte innehållande ett negativt tal (-120). Som ni ser är skillnaden mellan dessa att den största biten är satt till 0 vilket gör talet positivt, medan det andra exemplet är den största biten satt till 1 vilket gör talet negativt.

Hur räknar vi detta då? På samma sätt som tidigare, skillnaden ligger enbart i det största talet. I det övre exemplet räknar vi 0+0+0+0+8+0+0+1 vilket ger 9. I det nedre exemplet räknar vi -128+0+0+0+8+0+0+0 vilket ger -120.

Okej, nu har vi en grundläggande förståelse för vad en Byte är; att 8 Bitar ger 1 Byte, att en Byte innehåller ett värde inom ett spann på 256 olika värden, att det finns ”unsigned” Bytes som enbart innehåller positiva tal och ”signed” Bytes innehåller både positiva och negativa tal.

Så vad har detta med datatyper att göra?

Vi har ju tittat på int (integer) tidigare, men det finns en massa olika versioner av integer. Skillnaden mellan de olika varianterna av integer är att de kan innehålla olika mycket data (olika stora värden). Ju mer data de kan innehålla, ju mer plats tar de i minnet. Detta innebär att vi kan välja bättre eller sämre datatyper för ändamålet. I våra exempel (i andra artiklar) har vi exemplifierat med datatypen int för att spara undan mycket små tal, detta är inte helt optimalt då int tar mer minne än vad vi behöver för att spara undan värdet 10.

I denna artikel har vi kikat på en ”unsigned” Byte (0 till 255) och en ”signed” Byte (-128 till 127). En unsigned byte heter kort och gott Byte, medan en signed Byte heter sByte.

Datatypen byte är en 8-bitars unsigned integer. Den kan hålla tal mellan 0 till 255 (0 : 2^8-1). Datatypen sbyte är även den en 8-bitars integer, men signed. Den kan alltså hålla tal mellan -128 till 127 (-2^7 : 2^7-1). Dessa två datatyper är de datatyper som tar minst plats på minnet att använda sig av, men talen måste hamna inom just spannet för 256.

Den datatyp vi använt oss av i texterna tidigare som exempel har varit int. Int är en 32-bitars signed integer. Den byggs alltså upp av tre byte (32-bitar) och kan hålla värden mellan -2 147 483 648 och 2 147 483 647 (om jag räknat rätt), lättare skrivet är -2^31 till 2^31-1. Det är alltså väldigt stora tal vi kan lagra i en int.

Datatypen mellan sByte och int är short. Denna datatyp är en 16-bitars signed integer, vilken kan hålla tal mellan -32 768 och 32 767 (-2^15 till 2^15-1).

Nedan följer en lista på olika integer-datatyper vi kan använda oss av när vi kodar (i fallande storleksordning):

  • sbyte                               8-bit signed                                  -128 till 127 (-2^7 till 2^7-1)
  • byte                                 8-bit unsigned                             0 till 255 (0 till 2^8-1)
  • short                               16-bit signed                                -32 768 till 32 767 (-2^15 till 2^15-1)
  • ushort                            16 bit unsigned                           0 till 65 535 (0 till 2^16-1)
  • int                                     32-bit signed                                -2^31 till 2^31-1
  • uint                                  32 bit unsigned                           0 till 2^32-1
  • long                                 64-bit signed                                -2^63 till 2^63-1
  • ulong                               64 bit unsigned                           0 till 2^64-1

Okej, nu vet ni om att det finns fler än en typ av integer, alla till för att anpassa hur mycket minne varje variabel ska behöva ta. Alla dessa integer-typer tar ju bara heltal, men det gjorde ju float-datatypen, eller hur? Precis som integer finns float i några olika varianter:

  • float är en 32-bitars ”Single Precision Floating Point”. Vad det egentligen innebär är att den inte är så himla exakt. Den ger ett flyttalsvärde på 7 siffror.
  • double är en 64-bitars “Double Precision Floating Point”. Detta innebär fortfarande att den inte är särskilt exakt, men kan hantera ett flyttalsvärde på 15 siffror.

Dessa två är som sagt inte särskilt exakta, stå ska ni göra någon mjukvara för forskning så låt bli dessa. Det ni kan använda istället är:

  • decimal som är en 128-bitars ”high precision decimal notation member”. Denna är mycket mer precis än både float och double.

Om ni vill läsa på mer om skillnaderna mellan float, double och decimal har jag två länkar här:

http://www.programmersheaven.com/user/pheaven/blog/191-Float-Double-and-Decimal-do-you-know-the-differences/

http://roque-patrick.com/windows/final/bbl0027.html