5. fejezet - A számábrázolás alapjai

Tartalom

Pozitív egész számok ábrázolása
BCD ábrázolás
Gray kódolás
Prefixumok
Negatív egész számok ábrázolása
Egyes komplemens képzés
Kettes komplemens képzés
Műveletek egész számok között
Szorzás
Osztás
Lebegőpontos számábrázolás
Számok exponenciális alakja
Számok normál alakja
IEEEE szabvány
Ábrázolható számtartomány, túlcsordulás és alulcsordulás vizsgálata
A lebegőpontos számábrázolás szélsőséges esetei
Műveletek lebegőpontos számokkal
Lebegőpontos számok kerekítése
Lebegőpontos összeadás
Lebegőpontos kivonás
Lebegőpontos szorzás
Lebegőpontos osztás

Nagyon fontos, és gyakran elhanyagolt része egy programozó műveltségének a számábrázolás, mely a kifejezés szó szerinti értelmezésében egy tetszőleges környezetben a számok ábrázolásának módszereit, technikáit jelenti. Ilyen, nagyon tág értelemben ide tartozik az alfabetikus számábrázolás, amikor az alkalmazott nyelv betűivel jelölünk számokat, vagy a hieroglif ábrázolások, mint a székely rovásírás, a római számok, az azték jelölési mód stb.. A számítógépeken azonban a fogalom leszűkül a tárolás-feldolgozás gépi módjára (innen a név: „gépi tárolás”), ami azt jelenti, hogy egy számot milyen ábrázolási szakaszokban képes értelmezni a feldolgozás, vagyis az egyes bitcsoportoknak milyen, a szám képzésében meghatározó jelentést tulajdonít; pl. a később tárgyalt előjel, exponens, mantissza stb.

A számábrázolás nagyságával és pontosságával kapcsolatban a rendelkezésre álló tárhelyet szokták mint korlátot említeni (vagyis, hogy a legnagyobb ábrázolható szám alapvetően függ a tárhelytől). Az előbbi megfogalmazás azonban kicsit megengedőbb ennél, mert például, ha a feldolgozás mondjuk egy logikai művelet (például bitenkénti jelfordítás/negálás), akkor egy soros kimenettel és bemenettel kialakított 1 bites digitális gép is képes végtelen hosszúságú bináris minta (mint szám) feldolgozására.

Ezeket a szélsőséges feldolgozásokat leszámítva, vagyis a hagyományos (matematikai, logikai) műveleteket értve a feldolgozáson, fontos rögzíteni az értelmezés/feldolgozás elemi, egybetartozó bitjeinek számát. Az a legalapvetőbb bitmennyiség, melyet az informatikában régóta alkalmaznak, a „bájt”, ami egymás mögött jobbról balra emelkedő, kettes alapú helyi értékes számot jelent, szám szerint 8 helyi értéken az alábbi ábra szerint:

01100101

A bájt bitjeinek sorszáma, mint mondtuk, jobbról balra számozódik, és a számozás mindig nullával kezdődik, aminek betartásával az adott bitsorszám éppen a saját helyi értéken lévő hatványkitevővel egyenlő. Mit is jelent ez? Mint azt a Számok és számrendszerek fejezetben a polinomos felírásnál tanultuk, a bájt számjegyei együtthatók, melyeket kettő (jobbról nullával) kezdődő hatványaival (a helyi értékekkel) megszorozva, és az így keletkező részszorzatokat összeadva megkapjuk a bájt valódi értékét (lásd ).

5-1. ábra - http://gate575.hu/ITMagister/Convert

kepek/2fejezet-5-1.jpg


Pozitív egész számok ábrázolása

A bájt alapú pozitív számok ábrázolásánál a legnagyobb ábrázolható szám a 2n–1, ahol n az ábrázoláshoz feltételezett bitek száma. Ezt azért írjuk ilyen körülményesen, mert – mint később látni fogjuk – egy vagy több bájt szakaszokra bontott bitjeinek csoportjaira gyakran hivatkozunk önálló jelentéssel (lásd később: bináris maszkolás). Szokás a tömörebb felírás érdekében egy bájtot két négy digites (ún. tetrád) alakban, hexadecimálisan ábrázolni, ami a fenti példa esetén 011001012 = 6516. A számítástechnikában szokásos másik jelölés a bináris számok esetén a szám végére írt „b”, hexadecimális számoknál pedig a „h”, így a fenti példa másik felírási módja: 01100101b = 65h.

A bájtokból tehát, szintén jobbról balra növekedő helyi értékeket értelmezve, tetszőleges méretű/nagyságú (csak a tárterület mérete által korlátos) pozitív egész számokat ábrázolhatunk. Ez azt is jelenti, hogy mivel a bájtok egész számú többszörösével alakítunk ki minden számot, ezért lehet, hogy a legnagyobb (balról az első, második, harmadik stb.) bájtjainkat helyiérték-pótló nulla együtthatókkal kell kiegészítenünk a helyes eredmény érdekében (pirossal jelölve).

4. bájt

3. bájt

2. bájt

1. bájt

0. bájt

00000100

01101010

10101101

01011100

10101011

A későbbiek számára jegyezzük meg, hogy minden bájt-, illetve bitsorozatban a legmagasabb helyi értékű, tehát bal oldali, és a legkisebb helyi értékű, tehát jobb oldali szélső bájtot/bitet MSB vagy LSB rövidítéssel jelölünk, ami a Most Significant Byte/Bit illetve a Last Significant Byte/Bit szavak összevonásából adódik, és a legmagasabb, illetve a legalacsonyabb helyi érték pozíciót jelöli.

Feltétlenül szólnunk kell – bár még nem tisztáztuk a fizikai memória tárhelyeinek címezhetőségét – arról az eltérő módról, ahogy az egész számokat a memóriában tárolják. Itt két eltérő sorrendű tárolási módszer terjedt el, az ún. Big-endian és a Little-endian tárolási mód. A Big-endian esetében, melyet a mikrovezérlőkben és a Motorola 6800 szériában, az IBM 370 Sparc architektúrákon alkalmaznak, úgy tárolja a bájtokat, hogy alacsonyabb címeken a magasabb helyi értékű bájtok vannak. Például, ha a memória egy bizonyos helyéről (címéről) a következő két bájtot olvassuk: 01011100 10101011, akkor ez az 10101011010111002=AB5C16 számot jelenti. A másik tárolási formában, az ún. Little-endianban, melyet az Intel, Dec, Wax architektúrákon alkalmaznak, pont fordítva van, vagyis a memóriában tárolt 01011100 10101011 az 5CAB16 számot reprezentálja.

Ezt az inkonzekvens tárolást, kissé ironikusan, az elnevezés is jellemzi, hiszen Swift „Gulliver utazásai” című művéből származik az utalás, ahol a tojás feltörésének két eltérő módja miatt (a tojás vastagabb végén [Big-endian], illetve a tojás vékonyabb végén [Little-endian]) tör ki egy háború. Az egyes implementációk közötti adatcsere esetén azonban ez a tréfás kis eltérés teljesen értelmezhetetlen jelsorozatokat eredményez, ezért a sorrendkonverzióról gondoskodni kell. Az internetprotokollok azonban rendet vágtak ebben a káoszban, és egységesen Big-endian sorrendű kódolást használnak.

BCD ábrázolás

Gyakran szükség van decimális egész számok tárolására, de a bináris konverzió rontaná a feldolgozás hatékonyságát, ezért a négy biten ábrázolható számok közül csak a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 számokat használva ún. Binárisan Kódolt Decimális (BCD) ábrázolást alkalmazunk, ahol a következő minták szerepelhetnek a négyes bitcsoportokban:

0=0000 1=0001 2=0010 3=0011 4=0100 5=0101 6=0110 7=0111 8=1000 9=1001

Ha például az 5752 számot kell ábrázolni, akkor azt a következő bitmintával tehetjük BCD alakban:

A gyakorlatban azonban nem ilyen egyszerű alakban alkalmazzuk a binárisan kódolt decimális számokat, hanem két formai megoldásban. Az egyik az ún. zónás ábrázolás, amikor egy decimális digitet egy egész bájtban helyezünk el úgy, hogy a decimálisan az előzőek szerint kódolt számjegyet a bájt alsó tetrádjában tároljuk. Ilyenkor a felső tetrádban általában csupa egyes van. Például a kilences decimális számjegy egy bájtos zónás ábrázolása:

A zónajel, a felső tetrád, általában egy hexa „F”, de lehet más is, pl. hexa „C”. Azt, hogy az adott szám negatív vagy pozitív, a legalacsonyabb helyi értékű bájtban tároljuk úgy, hogy ennek felső terádjában pozitív szám esetén hexa „C”, „A” vagy „F” található, negatív szám esetén hexa „D” vagy „B”. Általában a zónajel és a számjel együttes használatával szoktak hivatkozni egy-egy zónásan kódolt BCD számjegyre, pl. C3, F9 stb.

Mivel – különösen a korai időkben – ez a fajta tárolás a tárigény vonatkozásában elég pazarlónak tűnt, ezért bevezettek egy másik, ún. pakolt, vagy tömörített BCD ábrázolást, melyben egy bájtban már két decimális digitet helyeztek el, kivéve a legalacsonyabb bájtot, ahol annak felső tetrádjában egy értékes számjegy, az alsó tetrádjában pedig az előjel kapott helyett. (Figyelem, épp fordítva, mint a zónás ábrázolásnál.)

Tehát, ha a decimális −57110-et akarjuk ábrázolni a két BCD kódolásban, akkor azok így néznek ki (pirossal jelöltük az előjel bitmintáját, mely a negatív szám miatt hexa „D”):

Figyelemmel a BCD ábrázolással szemben inkább a korai időkben megfogalmazott ellenérvekre (bonyolultabb műveletvégzés, pazarló tárhely igény), és figyelembe véve, hogy korunkban a nagy pontosságot igénylő pénzügyi és gazdasági számítások jelentősége igen megnőtt, jelenleg is van létjogosultsága a BCD aritmetikán alapuló műveletvégzésnek, mint azt a kézi kalkulátorainkban láthatjuk

BCD aritmetika használata esetén, ha az eredmény nagyobb lesz, mint kilenc, akkor ún. BCD korrekciót kell végrehajtanunk (ami annyit jelent, hogy az átvitelt tízes számrendszerben kell képezni). Erre szinte minden processzorban beépített utasítás van, mint azt később látni és tapasztalni fogjuk.

Gray kódolás

Szintén a múltból származó, ám ma is igen jelentős egészszám-reprezentáció az ún. Gray-kódolás, mely eredeti használatának az volt az oka, hogy a korabeli számítógépek és vezérlők a számlálási feladatokra elektromechanikus kapcsolókat alkalmaztak. Ezek nem tudják egyszerre több biten zavarmentesen a jelváltást követni, vagyis egy több bites váltást követően a számláló kapcsolóinak szinkronhibája miatt egy ideg hazárdos/hibás kimenet keletkezett. Ezért kellett egy olyan ábrázolási rendszer, ahol az egymást követő számok csak egy bitben térnek el egymástól, vagyis a számláláskor csak egy mechanikus kapcsoló lép működésbe.

A Gray-kódolásban létrehozott számsorozat képzésének szabálya az, hogy ismernünk kell az n. számsorozat megalkotásához az n–1. számsorozatban szereplő számokat. Indulásként, ha n=1, akkor a számsorozat [0,1]. Az n. számsorozat elemeit úgy képezzük, hogy az n–1. számsorozat minden elemét balról egy 0-val egészítjük ki. Ezt követően fordított sorrendben vesszük az n–1. számsorozat tagjait, mindegyiket balról 1-el kiegészítve. Tehát minden n. számsorozat 2n darab, n hosszúságú tagból áll. Lássunk egy példát:

Ha jól csináltuk, akkor a Frank Gray (1953, Bell laboratórium) nevéhez fűződő számsorozat minden eleme egy bitben különbözik az őt megelőző és az őt követőtől. Ellenőrizzük, hogy logikai hálózattal, vagy algoritmikusan a Gray-kód valójában a megelőző kód mintájából úgy is előállítható, hogy minden bitet eggyel jobbra tolunk (balról ilyenkor egy nullával töltjük fel), majd kizáró vagy kapcsolatba hozzuk az eredeti szám bitmintájával.

Például:

2 bitmintája binárisan „gray”-ben kódolva 011, ezt jobbra eltolva egy bittel, keletkezik a 001, amit kizáró vagy kapcsolatba hozva az eredetivel (011):

001 ⊕ 011 = 010

A jobbra eltolást „>>” –val jelölve így is írhatjuk:

(011>>) ⊕ 011 = 010

A fenti meggondolás alapján igen gyors, hardverben realizált számlálókat és más érdekes eszközöket építhetünk, nagyon olcsón. Ennek a kódolásnak nagy „történelme” van, és ma is használják a kriptográfiában (adatrejtés), a helymeghatározásban, a digitális földfelszíni televíziós és kábelrendszerek kommunikációja adatainak hibajavításában.