Egy mérési eredmény lehet negatív, például −5 °C, és lehet tört érték, például 13,25 mm. A számítógép memóriájában azonban csak bitek, vagyis nullák és egyesek szerepelnek. Hogyan jelöljük ezekkel a mínuszjelet és a törtrészt?
Ehhez meg kell állapodnunk a bitek értelmezésében. Először a negatív egész számok tárolását vizsgáljuk meg, majd a törtekből kiindulva eljutunk a lebegőpontos számábrázolásig és az IEEE 754 szabvány szerinti tárolásig.
A kettes számrendszerben a helyi értékek jobbról balra kétszereződnek: 1, 2, 4, 8, 16 és így tovább. Egy bit helyén álló 1 azt jelenti, hogy az adott helyi értéket hozzáadjuk a számhoz; a 0 azt, hogy nem adjuk hozzá.
Például a 00001101 bitsorozat értéke:
| Helyi érték | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|---|
| Bit | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
A szám tehát 8 + 4 + 1 = 13.
Nyolc bit együtt egy bájt. Nyolc bitből 256 különböző bitsorozat készíthető. Ha mindegyiket nemnegatív egész számként értelmezzük, 0-tól 255-ig tudunk számokat ábrázolni. Ezt nevezzük előjel nélküli egész számábrázolásnak.
Ha negatív számokat is szeretnénk tárolni, akkor ugyanezt a 256 bitsorozatot kell másképpen felosztanunk.
A bitsorozat önmagában nem mondja meg, hogyan kell értelmezni. Tudnunk kell, milyen számábrázolási szabály tartozik hozzá.
Kézenfekvő megoldás, hogy az első bit az előjelet adja meg, a többi pedig a szám abszolút értékét, vagyis az előjel nélküli nagyságát.
Állapodjunk meg abban, hogy az első bit 0 esetén pozitív, 1 esetén negatív előjelet jelent. Nyolc bitből így egy az előjelé, hét pedig a nagyságé:
| Szám | Előjelbit | A nagyság hét biten | Teljes bitsorozat |
|---|---|---|---|
| +5 | 0 | 0000101 | 00000101 |
| −5 | 1 | 0000101 | 10000101 |
Ezt előjeles abszolútértékes ábrázolásnak nevezzük. Könnyű megérteni, de az egész számokkal végzett műveleteknél kényelmetlen:
00000000 és 10000000, azaz +0 és −0.
Például +5 és −5 matematikai összege 0. A fenti két bitsorozat szokásos bináris összeadása viszont 10001010, ami ebben az ábrázolásban −10 lenne.
Az egész számokhoz ezért általában más megoldást használunk: a kettes komplemens ábrázolást.
Olyan bitsorozatot keresünk −5 számára, amelyet +5 bitsorozatához hozzáadva az alsó nyolc biten nullát kapunk.
Nyolc biten legfeljebb 255 ábrázolható előjel nélkül. A következő szám, 256, már kilenc bitet igényel: 100000000. Ha egy nyolcbites eredményből csak az alsó nyolc bitet tartjuk meg, ebből 00000000 marad.
Melyik nemnegatív számmal kell az 5-öt kiegészíteni 256-ra? A válasz: 256 − 5 = 251.
Ezért nyolcbites kettes komplemensben a −5 tárolt bitmintája megegyezik az előjel nélkül 251-et jelentő bitmintával: 11111011.
Az eljárás két egyszerű lépésből áll, de előtte rögzíteni kell a bitszámot. Most nyolc bittel dolgozunk.
Példa: −5 előállítása.
+5 nyolc biten: 00000101 Bitek megfordítása: 11111010 Egy hozzáadása: 11111011
Az eredmény tehát −5 = 11111011 nyolcbites kettes komplemensben.
Miért működik a megfordítás és az egy hozzáadása? A nyolc egyesből álló szám értéke 255. Egy pozitív x szám bitjeinek megfordítása 255 − x-et ad, az ezt követő +1 pedig 256 − x-et. Pontosan ezt kerestük.
Nyolcbites kettes komplemensben az első bit helyi értéke −128, a többi bité változatlanul pozitív:
| Helyi érték | −128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|---|
| −5 bitmintája | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
Az érték: −128 + 64 + 32 + 16 + 8 + 2 + 1 = −5.
Ezért az első bit valóban jelzi az előjelet: 0 esetén nemnegatív, 1 esetén negatív a szám. De nem egyszerűen külön mínuszjel a többi bit elé. A maradék hét bit itt nem a negatív szám abszolút értékét tárolja.
Másik visszaolvasási módszer: az 11111011 előjel nélkül 251. Mivel az első bit 1, kivonunk 256-ot: 251 − 256 = −5.
A pozitív és negatív számok bitmintáit ugyanazzal a bináris összeadással kezelhetjük. Az összeadásban 1 + 1 eredménye 0 az adott helyen, és 1-et továbbviszünk a következő helyi értékre. Ezt átvitelnek nevezzük.
Vizsgáljuk meg az 5 + (−5) összeget:
00000101 +5 + 11111011 -5 ---------- 1 00000000
A bal oldali kilencedik bit nem fér bele a nyolcbites eredménybe. Az alsó nyolc bit 00000000, vagyis 0, ahogyan vártuk.
A kivonás is összeadássá alakítható: 7 − 5 = 7 + (−5).
00000111 +7 + 11111011 -5 ---------- 1 00000010
Az alsó nyolc bit értéke 2.
Fontos: A helyes előjeles eredményhez az is szükséges, hogy a matematikai eredmény beleférjen az adott bitszám értéktartományába. A kilencedik bit elhagyása önmagában nem oldja meg a túl nagy eredmények problémáját.
Nyolcbites kettes komplemensben:
01111111, vagyis 127;10000000, vagyis −128;00000000.A tartomány azért nem szimmetrikus, mert az első bit 0-val kezdődő 128 lehetősége közé a nulla is beletartozik: 0–127. Az 1-gyel kezdődő 128 lehetőség a −128 és −1 közötti számoké.
| Bitszám | Előjel nélküli egész | Kettes komplemens egész |
|---|---|---|
| 8 | 0 … 255 | −128 … 127 |
| 16 | 0 … 65 535 | −32 768 … 32 767 |
| 32 | 0 … 4 294 967 295 | −2 147 483 648 … 2 147 483 647 |
Általánosan n bit esetén a kettes komplemens tartománya −2n−1 … 2n−1 − 1. A felső index hatványozást jelent.
Ugyanaz a bitsorozat eltérő szabállyal mást jelent:
| Bitsorozat | Előjel nélkül | Kettes komplemens szerint |
|---|---|---|
01111111 | 127 | 127 |
10000000 | 128 | −128 |
11111111 | 255 | −1 |
A −128 pozitív párja, +128 nem fér el nyolcbites kettes komplemensben. Ezért a legkisebb negatív érték előjelének megfordítása is túlcsordulhat.
Ha egy kettes komplemens számot változatlan értékkel több bitre bővítünk, az új bal oldali biteket a régi első bit értékével töltjük ki. Ezt előjelkiterjesztésnek nevezzük.
| Szám | Nyolc biten | Tizenhat biten |
|---|---|---|
| +5 | 00000101 | 00000000 00000101 |
| −5 | 11111011 | 11111111 11111011 |
A szóköz csak az olvashatóságot segíti. Negatív szám elé tehát nem nullákat írunk, mert az megváltoztatná az értékét.
Tízes számrendszerben a vessző utáni helyi értékek: egy tized, egy század, egy ezred. Kettes számrendszerben ugyanígy folytatódik a helyiérték-rendszer, de minden új helyen kettővel osztunk:
| Hely | A vessző előtt | Első törtjegy | Második törtjegy | Harmadik törtjegy | Negyedik törtjegy |
|---|---|---|---|---|---|
| Helyi érték | 1 | 1/2 | 1/4 | 1/8 | 1/16 |
| Tízes számrendszerben | 1 | 0,5 | 0,25 | 0,125 | 0,0625 |
Például a bináris 0,101 értéke:
1 × 1/2 + 0 × 1/4 + 1 × 1/8 = 0,625.
A következőkben a szám mögötti alsó 2 a kettes, az alsó 10 a tízes számrendszert jelöli. Így az előző összefüggés:
0,1012 = 0,62510.
Ez nem azonos a tízes számrendszerbeli 0,101-gyel. A vessző mindkét esetben az egész és a tört részt választja el, de a helyi értékek különböznek.
Az egész részt és a tört részt külön vizsgáljuk:
1101.01.Tehát 13,2510 = 1101,012.
Ellenőrzés: 8 + 4 + 1 + 1/4 = 13,25.
A törtjegyeket ismételt kettővel szorzással is meghatározhatjuk. Minden lépésben felírjuk a szorzat egész részét, majd a következő lépésben csak a megmaradt törtrésszel dolgozunk.
Például 0,625 esetén:
| Lépés | Szorzás | Következő bináris jegy | Továbbvitt törtrész |
|---|---|---|---|
| 1. | 0,625 × 2 = 1,25 | 1 | 0,25 |
| 2. | 0,25 × 2 = 0,5 | 0 | 0,5 |
| 3. | 0,5 × 2 = 1,0 | 1 | 0 |
A jegyeket keletkezésük sorrendjében olvassuk: 0,1012. A maradék nulla lett, ezért a felírás véget ért.
A memóriában nincs a bitek közé rajzolt vessző. A helyét is értelmezési szabállyal kell megadnunk.
Az egyik lehetőség, hogy előre rögzítjük, hány bit tartozik a törtrészhez. Ezt fixpontos számábrázolásnak nevezzük.
Például használjunk nyolc előjel nélküli bitet, és állapodjunk meg abban, hogy az utolsó négy bit a törtrész. A tárolt 00110100 bitmintát ilyenkor 0011,0100 alakban értelmezzük:
2 + 1 + 1/4 = 3,25.
Ugyanez megfogalmazható úgy is, hogy a tárolt egész szám 52, és annak értékét 16-tal osztjuk: 52/16 = 3,25.
Ebben az egyszerű formátumban két szomszédos szám távolsága mindig 1/16 = 0,0625. A legnagyobb szám 255/16 = 15,9375. Több törtbit finomabb felbontást adna, de ugyanennyi összes bit mellett kisebb egész rész férne el.
A fixpontos ábrázolás állandó lépésközt használ. Ez hasznos lehet, ha a mérési tartomány és a szükséges felbontás előre ismert. Mi történjen azonban, ha nagyon kicsi és nagyon nagy számokkal is szeretnénk dolgozni?
A mérnöki gyakorlatban gyakran használunk hatványalakot. Például:
Mindkét számban az 1,325 hordozza az értékes számjegyeket. A tíz hatványa mondja meg, mekkora legyen a szám. A kitevő az a szám, amelyet a hatvány alapjának felső indexébe írunk: itt 4, illetve −3.
A negatív kitevő osztást jelent: 10−3 = 1/1000. Ugyanígy 2−3 = 1/8.
A lebegőpontos számábrázolás ezt az ötletet használja: külön tárolja a szám előjelét, értékes jegyeit és a nagyságrendet meghatározó kitevőt. A vessző helye a kitevőtől függ, ezért mondjuk, hogy „lebeg”.
A bináris lebegőpontos számoknál a hatvány alapja 2, nem 10.
A 13,25 korábban kapott bináris alakja 1101,01. A vesszőt három hellyel balra helyezve 1,10101-et kapunk. Ez nyolcadakkora szám, ezért 23-nal, azaz nyolccal kell szoroznunk:
1101,012 = 1,101012 × 23.
A nem nulla szám abszolút értékét úgy rendezzük át, hogy a vessző előtt pontosan egy 1-es maradjon. Ezt az alakot normalizált alaknak, az átrendezést normalizálásnak nevezzük.
Az 1,10101 részt szignifikansnak nevezzük; sok tananyag a mantissza elnevezést használja rá. Ez hordozza a szám értékes bináris jegyeit. Értéke normalizált alakban legalább 1, de kisebb 2-nél.
Egy egynél kisebb számnál negatív kitevőt kapunk:
0,001012 = 1,012 × 2−3 = 0,1562510.
Itt a vesszőt jobbra mozdítottuk három hellyel, ezért az érték megtartásához nyolccal osztunk.
Az alapötlet még nem határozza meg, hány bitet kapjon az előjel, a kitevő és a szignifikáns. Ha különböző számítógépek ugyanúgy szeretnék értelmezni az adatot, közös szabályokra van szükségük.
Az IEEE 754 a lebegőpontos számábrázolás és aritmetika szabványa. Többek között tárolási formátumokat, kerekítési szabályokat és különleges értékeket határoz meg. Itt a binary32 nevű, 32 bites bináris formátumot vezetjük le részletesen. Ezt egyszeres pontosságú ábrázolásnak is nevezik.
A 32 bitet három egymás utáni részre osztjuk. Az ilyen, meghatározott szerepű bitcsoportot mezőnek nevezzük.
| Mező | Méret | Feladat |
|---|---|---|
| Előjel | 1 bit | 0: pozitív, 1: negatív előjel |
| Eltolt kitevő | 8 bit | A kettes hatvány kitevőjének tárolása, az alább megadott eltolással |
| Törtrész | 23 bit | A normalizált szignifikáns vessző utáni bitjei |
Ez összesen 1 + 8 + 23 = 32 bit, vagyis négy bájt. A következő levezetések a normál, véges, nem nulla számokra vonatkoznak. A nulla és más különleges esetek szabályait később külön tárgyaljuk.
A normalizált bináris alak mindig 1,-gyel kezdődik. Ezt az első 1-est ezért nem szükséges külön eltárolni: visszaolvasáskor automatikusan eléírjuk a tárolt törtbiteknek.
Például az 1,10101 szignifikansból csak az 10101 rész kerül a törtrészmezőbe. A hiányzó helyeket jobbról nullákkal töltjük ki.
Az elhagyott első 1-est rejtett vezető bitnek nevezik. Emiatt a 23 tárolt törtbit a normál számoknál 24 értékes bináris jegyet biztosít. A szignifikans és a tárolt törtrészmező tehát nem pontosan ugyanaz.
A kitevő lehet pozitív és negatív is. A binary32 kitevőmezőjét azonban nem kettes komplemens szerint értelmezzük. Ehelyett a valódi kitevőhöz hozzáadunk 127-et, és ezt a nemnegatív értéket tároljuk.
Ezt az állandó hozzáadást eltolásnak nevezzük; angol neve bias.
| Valódi kitevő | Tárolt érték | A tárolt érték nyolc biten |
|---|---|---|
| −3 | 124 | 01111100 |
| 0 | 127 | 01111111 |
| +3 | 130 | 10000010 |
A normál számok tárolt kitevője 1 és 254 közötti lehet, ami −126 és +127 közötti valódi kitevőt jelent. A 0 és a 255 mezőérték különleges esetek számára van fenntartva.
A szám negatív, ezért az előjelbit 1. A továbbiakban a 13,25 abszolút értékével dolgozunk.
A korábbi levezetés szerint:
13,2510 = 1101,012 = 1,101012 × 23.
A valódi kitevő tehát 3, a szignifikáns 1,10101.
A 3-hoz hozzáadjuk az eltolást: 3 + 127 = 130.
Mivel 130 = 128 + 2, a kitevőmező nyolc bitje 10000010.
Az 1,10101 elejéről elhagyjuk a rejtett 1-est. A maradó 10101 öt bit hosszú; jobbról 18 nullával egészítjük ki 23 bitre:
10101000000000000000000.
Itt nincs szükség kerekítésre, mert az összes értékes jegy elfér.
| Előjel: 1 bit | Kitevő: 8 bit | Törtrész: 23 bit |
|---|---|---|
1 | 10000010 | 10101000000000000000000 |
A teljes 32 bites minta:
1 10000010 10101000000000000000000
A szóközök csak a mezőhatárokat mutatják, nem tárolt jelek. A bitmintát a legfelső előjelbittől a legalsó törtbit felé írtuk fel; a memóriabeli bájtsorrend külön kérdés.
Fontos különbség: itt a negatív előjelet egy külön bit tárolja. A −13,25 előállításához nem fordítjuk meg a +13,25 teljes bitmintáját, és nem adunk hozzá 1-et. A kettes komplemens az egész számoknál tanult másik ábrázolás.
10000010, vagyis 130. A valódi kitevő 130 − 127 = 3.1,10101.Jelöljük az előjelbitet s-sel, a kitevőmező előjel nélküli egész értékét E-vel, a 23 bites törtrészmező előjel nélküli egész értékét pedig F-fel. Normál binary32 számnál:
érték = (−1)s × (1 + F / 223) × 2E−127.
A képlet ugyanazokat a lépéseket foglalja össze, amelyeket az előbb külön elvégeztünk. Csak akkor alkalmazható ebben az alakban, ha 1 ≤ E ≤ 254.
Ábrázoljuk a 0,15625 számot! Mivel 0,15625 = 1/8 + 1/32, bináris alakja 0,00101.
Normalizálva: 1,012 × 2−3.
01111100.01, amelyeket 23 bitre egészítünk ki.| Előjel | Kitevő | Törtrész |
|---|---|---|
0 | 01111100 | 01000000000000000000000 |
Visszaolvasva a szignifikáns 1,25, a kettes hatvány 1/8, ezért az eredmény 1,25 / 8 = 0,15625.
A tízes számrendszerben az 1/3 felírása végtelen: 0,3333… Kettes számrendszerben is vannak végtelen felírású törtek, de nem pontosan ugyanazok.
Például a 0,110 bináris alakja 0,0001100110011…2. A 0011 rész az első törtjegy után ismétlődik.
Az ismételt kettővel szorzásnál is látszik az ismétlődés:
| Lépés | Szorzás | Kiírt bit | Maradó törtrész |
|---|---|---|---|
| 1. | 0,1 × 2 = 0,2 | 0 | 0,2 |
| 2. | 0,2 × 2 = 0,4 | 0 | 0,4 |
| 3. | 0,4 × 2 = 0,8 | 0 | 0,8 |
| 4. | 0,8 × 2 = 1,6 | 1 | 0,6 |
| 5. | 0,6 × 2 = 1,2 | 1 | 0,2 |
Az ötödik lépésben újra 0,2 maradt, ezért innentől ugyanaz a folyamat ismétlődik. A szám felírása nem ér véget.
Véges számú biten csak véges számú jegyet tárolhatunk, ezért közelítő értéket választunk. A binary32 formátumban a 0,1 legközelebbi tárolható értéke körülbelül 0,10000000149.
Ez nem meghibásodás. Hasonló ahhoz, amikor az 1/3 helyett csak 0,333-at írunk le.
Az IEEE 754 alapértelmezett bináris kerekítése a legközelebbi ábrázolható értéket választja. Pontos félútnál azt az értéket részesíti előnyben, amelynek utolsó megtartott bináris jegye 0. Ezt „legközelebbire, döntetlennél párosra” kerekítésnek nevezik.
Ezért a tárolás nem minden esetben puszta levágás: a megtartott utolsó jegyek a kerekítés hatására megváltozhatnak.
A binary32 normál számoknak 24 értékes bináris jegyük van. Amikor a kitevő nő, ugyanezek a jegyek nagyobb helyi értékeket jelölnek. Ezért a nagyobb számok között általában nagyobb a távolság.
Például binary32 esetén:
A 16 777 217 egész szám ezért nem tárolható pontosan binary32-ben, pedig nem közelíti meg a formátum legnagyobb értékét. A szomszédai 16 777 216 és 16 777 218. Az alapértelmezett kerekítés itt a 16 777 216-ot választja.
Az ábrázolható tartomány és az ábrázolás pontossága külön tulajdonság. Attól, hogy egy érték a tartományon belül van, még nem feltétlenül tárolható pontosan.
A normál alak mindig rejtett 1-essel kezdődik, ezért ezzel a szabállyal a nullát nem tudnánk leírni. A szabvány ezért bizonyos kitevőmintákhoz külön értelmezést rendel.
A következő táblázatban E a kitevőmező egész értéke, F pedig a törtrészmezőé:
| Tárolt kitevő, E | Törtrész, F | Jelentés |
|---|---|---|
| 1–254 | Tetszőleges | Normál, véges, nem nulla szám; rejtett vezető bitje 1. |
| 0 | 0 | Nulla; az előjelbittől függően +0 vagy −0. |
| 0 | Nem nulla | Szubnormális, azaz a normál tartománynál kisebb abszolút értékű, nem nulla szám. |
| 255 | 0 | Pozitív vagy negatív végtelen az előjelbit szerint. |
| 255 | Nem nulla | NaN: különleges „nem szám” érték. |
A szubnormális számoknál a vezető bit 0, a kettes hatvány kitevője pedig rögzítetten −126. Így a normál tartomány alatt is tárolhatók nullától különböző értékek, de kevesebb értékes jeggyel. A legkisebb pozitív binary32 érték 2−149, körülbelül 1,4 × 10−45.
A szubnormális érték képlete: (−1)s × (F / 223) × 2−126. Itt nem írunk vissza rejtett 1-est.
A végtelen jelölés például túl nagy eredménynél jelenhet meg. Nem egy rendkívül nagy véges számot jelent, hanem különleges érték.
A NaN az angol Not a Number rövidítése. Olyan eredményt jelölhet, amelyhez nem rendelhető szokásos számérték, például a 0/0 műveletnél. A program konkrét szabályai szerint ilyen helyzetben különleges érték vagy hibajelzés is keletkezhet.
A +0 és −0 a szokásos numerikus egyenlőségvizsgálatban egyenlő, de bitmintájuk eltér, és egyes műveletek különbséget tesznek közöttük. Ez az egész számok kettes komplemens ábrázolásának egyetlen nullájától eltérő szabály.
Az IEEE 754 másik gyakori formátuma a binary64, más néven kétszeres pontosságú ábrázolás. Ugyanarra az elvre épül, de több bitet használ a kitevőhöz és a törtrészhez is.
| Tulajdonság | binary32 | binary64 |
|---|---|---|
| Teljes méret | 32 bit, 4 bájt | 64 bit, 8 bájt |
| Előjel | 1 bit | 1 bit |
| Kitevőmező | 8 bit | 11 bit |
| Tárolt törtbitek | 23 bit | 52 bit |
| Értékes bináris jegyek normál számnál | 24 | 53 |
| Kitevő eltolása | 127 | 1023 |
| Tájékoztató pontosság tízes számrendszerben | Körülbelül 7 értékes jegy | Körülbelül 16 értékes jegy |
| Legnagyobb pozitív véges érték, közelítőleg | 3,4 × 1038 | 1,8 × 10308 |
Az „értékes jegy” nem ugyanaz, mint a „vessző utáni jegy”. Például az 1,234567 és az 1 234 567 egyaránt hét értékes decimális jegyet tartalmaz. A táblázat kerekített tájékoztatást ad, nem minden decimális számra érvényes pontos tárolási garanciát.
A binary64 lényegesen pontosabb, de a 0,1-et ez sem tárolja pontosan, mert annak bináris felírása végtelen.
Például ha két hosszúságeredmény eltérését legfeljebb 0,001 mm-ig tekintjük elfogadhatónak, azt vizsgáljuk, hogy különbségük abszolút értéke legfeljebb 0,001 mm-e. Más nagyságrendű feladatnál relatív, az érték nagyságához viszonyított tűrésre is szükség lehet.
A több megjelenített tizedesjegy nem teszi pontosabbá sem az eredeti mérést, sem a már elvégzett számítást.
11110110 nyolcbites kettes komplemens szerint?00000110; megfordítva: 11111001; egyet hozzáadva: 11111010.0; kitevő: 2 + 127 = 129, azaz 10000001; törtrész: 10100000000000000000000.
Kattints a bitekre! Ugyanazt a bitsorozatot előjel nélküli egészként és kettes komplemens szerint is értelmezzük.
Próbáld ki: állíts be 127-et, majd adj hozzá 1-et! A demonstráció nyolc bitet tart meg.
Írj be egy számot, vagy válassz példát! A program IEEE 754 binary32 formátumra alakítja. A kapott biteket külön is átkapcsolhatod.
A 0,1 példán figyeld meg a kerekítést! Normál számnál a tárolt törtbitek elé egy rejtett 1-es kerül. Nulla és szubnormális szám esetén a vezető bit 0.