Reprezentacia necelych cisel

02.11.2007 11:50 | kabel

Ako to je s reprezentaciou necelych cisel v pocitacoch, ako sa ukladaju do pamate.

Na zaciatok by sa chcelo vidiet nieco o tom ako to vlastne s cislami v pocitaci vobec je.
Zacneme celymi cislami.
Majme C program:

int main () {
  int a = 5;
  printf("%i\n", a);
}

Tento program si vyhradi nejake miesto v pamati do ktoreho je schopny ulozit cislo typu int (int a = 5). Typ int zabera v pamati 4 bajty = 32 bitov (1 bajt = 8 bitov). To znamena, ze cislo 5 ktore don ulozime zaberie 32 bitov a v dvojkovej sustave sa zapise ako:
5 = 00000000 00000000 00000000 00000101
(Obycajny prevod do dvojkovej sustavy).

Takto mozno dosiahnut celkovo 232 = 4,294,967,296 roznych cisel. Typ int moze obsahovat aj zapornu hodnotu, a to pocitanim z opacnej strany - odpocitavanim z najvyssej hodnoty 232, napriklad cislo -1 bude reprezentovane ako 232-1:

+3 = 00000000 00000000 00000000 00000011
+2 = 00000000 00000000 00000000 00000010
+1 = 00000000 00000000 00000000 00000001
+0 = 00000000 00000000 00000000 00000000
-1 = 11111111 11111111 11111111 11111111
-2 = 11111111 11111111 11111111 11111110

To znamena, ze int moze obsahovat hodnoty od -231 do 231-1 (od -2147483648 do 2147483647), co je dohromady spominanych 232 cisel (aj s nulou).

Tiez celosicelne typy short a char su na tom takto:

short - (2 bajty = 16 bitov)
  2^16 = 65,536 roznych hodnot od -32768 do 32767,
char - (1 bajt = 8 bitov)
  2^8 = 256 roznych hodnot od -128 do 127.

Popripade este je 8 bajtov = 64 bitov dlha hodnota pouzivana pre velke cisla (v cecku sa nazyva long long int).

Ak dopredu vieme, ze nebudeme pouzivat zaporne cisla, premennej mozme pridelit predponu unsigned (unsigned int, unsigned short, ...).
Potom ma napriklad typ unsigned int mozne hodnoty od 0 do 232-1 (od 0 do 4294967295).

Suhrn:

8B = long long int ( = long long )
4B = long int ( = long = int )
2B = short int ( = short )
1B = char

char          od -128 do 127
short        od -32768 do 32767
int          od -2147483648 do 2147483647
long long    od -9223372036854775808 do 9223372036854775807

unsigned char        od 0 do 255
unsigned short        od 0 do 65535
unsigned int          od 0 do 4294967295
unsigned long long    od 0 do 18446744073709551615



Desatinne cisla

V pripade desatinnych cisel je to inak. Kedze nevieme, kde v cisle sa bude nachadzat desatinna ciarka (a zapisat ju niekde pevne, napriklad ze ma byt presne v polovici cisla nie je vyhodne, pretoze na vacsie cisla by sme potrebovali vela pamate), vyriesilo sa to inac.
Najviac je pouzivany Medzinarodny standard pre binarnu desatinnu aritmetiku IEEE 754.

V tomto clanku opisem IEEE 754 single precision. V cecku sa takemuto typu nadava float.

Kazde cislo sa sklada z troch casti: znamienko, exponent a mantissa.
Pre ulozenie do 32 bitoveho priestoru (single precision) je zlozenie desatinneho cisla taketo:

S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
S - sign (znamienko) 1 bit
E - exponent 8 bitov
M - mantissa 23 bitov
hodnota = (-1)S * 2E-127 * (1.M)

To znamena ze prva cast urcuje znamienko:
ak S = 0, cislo je kladne,
sk S = 1, cislo je zaporne.

Druha cast je umocnenie cisla 2 na exponent (od ktoreho sa odpocita hodnota 127).

Tretia cast mantissa je vlastne zvysny podiel ktorym treba nasobit aby sme dosiahli nase cislo. POZOR: Mantissa obsahuje skrytu jednotku na zaciatku, ktora tam je vzdy a preto sa nezapisuje (1.M). Napriklad ak je mantissa zapisana ako:

00110011001100110011001
v skutocnosti to je
1.00110011001100110011001

Preco sa od exponentu odcitava hodnota 127? Je to preto, aby sme mohli dosiahnut presnost za desatinnou ciarkou (teda aj zaporne hodnoty, ak E=3, v skutocnosti je exponent 3-127 = -124).

Priklad premeny 0.75:
Chceme premenit cislo 0.7510 do standardu IEEE 754 signle precision.
0.7510 = 0.112      (premenene do dvojkovej sustavy)
0.7510 = 1.1 * 2-1   (normalizovane dvojkove cislo)

Cislo sme normalizovali preto, aby sme na zaciatku mali pred desatinnou ciarkou jednotku, ktora je skryta.

Cislo je kladne: S = 0.
Exponent pri dvojke je -1, E je vzdy zvascene o 127:
E = -1 + 127 = 126 = 01111110.
Desatinna cast manissy:
M = 10000000000000000000000 (23 bitov)

Cislo 0.75 sa vo formate IEEE 754 single precision reprezentuje ako:
0 01111110 10000000000000000000000 (32 bitov)


Priklad premeny -2345.125:
-2345.12510 = -100100101001.0012
-2345.12510 = -1.00100101001001 * 211   (normalizovane)
Cislo je zaporne: S = 1.
Exponent pri dvojke je 11, E je zvacene o 127:
E = 11 + 127 = 138 = 10001010.
M = 00100101001001000000000 (23 bitov)

Cislo -2345.125 sa vo formate IEEE 754 single precision reprezentuje ako:
1 10001010 00100101001001000000000 (32 bitov)


Specialne pripady
Exponent E moze byt v rozmedzi od 0 do 255. Odcitany moze byt v rozmedzi -127 do 128. V skutocnosti vsak iba od -126 do 127, pretoze hodnoty -127 a 128 (E=00000000 a E=11111111) sa pouzivaju na specialne pripady cisel:
Ak E = 0 a S = 0
  hodnota cisla = 0
Ak E = 0 a S = 1
  nenormalizovane cislo, (vysledk tzv. underflowu pri nasobeni)
Ak E = 255 a S = 0
  infinity (nekonecno). Napriklad pri deleni nulou.
Ak E = 255 a S = 1
  NaN (Not A Number). Napriklad pri deleni nuly nulou.