Számábrázolás



Számábrázolás a számítógépen

A számítógépben a adatokat binárisan, bitek sorozataként ábrázoljuk. A továbbiakban tételezzük fel, hogy az adatokat egy 'n' bites tárolóegységben, ún. regiszterben tároljuk. Mivel ebben egymástól függetlenül 'n' különböző bit tárolható, ez összesen m=2n különböző bitvariációt tesz lehetővé. Tehát egy 'n' bites regiszterben 'm' számú különböző (binárisan kódolt) adatot tárolhatunk. Az 'm' számot a regiszter modulusának is szokás nevezni.
Például
– egy 8 bites regiszter modulusa m=256;
– egy 16 bites regiszter modulusa m=65536;
– egy 24 bites regiszter modulusa m=16,777,216;
– egy 32 bites regiszter modulusa m=4,294,967,296.

Egy 'n' bites regiszterben pontosan m=2n darab különböző binárisan kódolt adat tárolható.

Mivel egy regiszterben biteket tárolunk, egy 'n' bites regiszter egybites tárolóegységek sorozataként is felfogható. Ha bi a regiszter i-dik bitjét jelenti (amelynek értéke 0 vagy 1), akkor egy regisztert
    bn−1bn−2...b2b1b0
formában írhatunk le, ahol bn−1 a legnagyobb sorszámú bit, b0 pedig a legkisebb sorszámú bit.

Számok ábrázolása esetén (vagyis amikor a regiszterben tárolt bitsorozatot számként értelmezzük) a legmagasabb sorszámú bit rendszerint a szám előjelét adja meg:
    bn−1=0 esetén a regiszterben tárolt szám pozitív;
    bn−1=1 esetén a regiszterben tárolt szám negatív.
Ilyenkor a legmagasabb sorszámú bitet előjelbitnek nevezzük.

Ami egy binárisan ábrázolt szám regiszterbeli elhelyezését illeti, általános szabály, hogy a szám legkisebb helyiértékű bitjét (LSB) a legkisebb sorszámú biten (pl. b0-ban) tároljuk, és ennek megfelelően a szám nagyobb helyiértékű bitjeit jobbról balra, a magasabb sorszámú biteken tároljuk.

Például egy 8 bites nemnegatív egész szám esetén az MSB megfelel a 27=128 helyiértékű számjegynek, amit a regiszter b7 sorszámú bitjén tárolunk. A regiszter magasabb sorszámú bitjeit ilyenkor nem használjuk.

Megjegyzések:
(1) A "legkisebb sorszámú" és "legnagyobb sorszámú" az n-bites regiszter jobb szélső (0-dik), ill. bal szélső ((n−1)-dik) bitjét jelenti. A szám ábrázolása határozza meg, hogy a regiszter bitjeit hogyan értelmezzük.
(2) Egy több bájton ábrázolt szám bájt szervezésű memóriában történő tárolásakor az egyes bájtok (vagy memóriarekeszek) elhelyezésére rendszerint ugyanezt az elvet követjük, vagyis a kisebb helyiértékű számjegyeket tartalmazó ("kisebb helyiértékű") bájtok memóriacíme kisebb lesz (például felülről lefelé ábrázolva a memóriacellákat, ezek "feljebb" fognak elhelyezkedni). Az ábrázolt számot tároló bájtok memóriacíme mindig a számhoz tartozó legkisebb című memóriarekesz címe lesz.
(3) Egy több bájton ábrázolt szám fájlba írásakor azonban a bájtok sorrendje legtöbbször (pl. a Java DataOutputStream szűrőjét használva) megfordul, azaz a legnagyobb helyiértékű bájt lesz az első, és a legkisebb helyiértékű bájt az utolsó ("big-endian order").

Ha egy regiszterben számokat tárolunk, a számokat különböző módon feleltethetjük meg a regiszter bitjeinek. Ennek megfelelően a következő kódolási vagy számábrázolási módokról beszélhetünk:

  1. direkt kódolás
  2. kettes komplemens kódolás
  3. binárisan kódolt decimális (BCD) számábrázolás
  4. lebegőpontos számábrázolás

Egyes algoritmusok leírását a legtöbb esetben rövid JavaScript programokkal is bemutatjuk. A példák kipróbálásához felhasználható online JavaScript interpreter:

Online JavaScript Interpreter by Peter Jipsen, Chapman University (January 2013).
http://math.chapman.edu/~jipsen/js/ (2020-11-19)

Fontos megjegyzés: mivel a fenti link jelenleg nem működik, használjuk az alábbi linket.

A JavaScript programok folyamatábráját megjeleníthetjük az alábbi webes alkalmazás segítségével:

Live code editor. Created by Bogdan Lyashenko.
https://bogdan-lyashenko.github.io/js-code-to-svg-flowchart/docs/live-editor/index.html (2022-10-02)

A folyamatábra a 'for' ciklust nem megfelelően ábrázolja, ezért érdemes ezeket mindig átírni 'while' ciklusra, mielőtt megjelenítenénk a program folyamatábráját.



Számábrázolás a számítógépen: direkt kódolás

Ha egy regiszterben egy bináris számrendszerben ábrázolt nemnegatív egész számot tárolunk úgy, hogy a regiszter bitjeinek a szám bináris számjegyeit feleltetjük meg a helyi értékek megszokott sorrendjében (azaz az LSB-hez a legkisebb, 1-es helyiérték tartozik, majd (jobbról balra haladva) a következő bithez a 2-es helyiérték, utána a 4-es, 8-as stb.), akkor ún. direkt kódolásról (vagy egyenes kódolásról) beszélünk. Mivel direkt kódolás esetén csak nemnegatív számokat ábrázolunk, ezért nincs szükségünk előjelbitre.

Direkt kódolás esetén például egy 8 bites regiszterben tárolható legkisebb szám 0000|00002=010, a legnagyobb pedig 1111|11112=25510.



Számábrázolás a számítógépen: kettes komplemens kódolás

Tároljunk egy 'n' bites (m=2n modulusú) regiszterben egész számokat a következőképpen:

Ezt a kódolást kettes komplemens kódolásnak nevezzük.

Ábrázoljunk példaként egy 8 bites regiszterben kettes komplemens kódban néhány számot (a bitsorozatok után alsó indexben megadott '2' most kettes komplemens kódban ábrázolt számot jelöl):

decimális érték kettes komplemens kód decimális érték kettes komplemens kód
010 0000|00002
110 0000|00012 −110 1111|11112
210 0000|00102 −210 1111|11102
310 0000|00112 −310 1111|11012
...
2310 0001|01112 −2310 1110|10012
...
12610 0111|11102 −12610 1000|00102
12710 0111|11112 −12710 1000|00012
−12810 1000|00002

Például −2310=1110|10012 mivel 0001|01112=1110|10002 (egyes komplemens) és ehhez 1-et binárisan hozzáadva 1110|10002+12=1110|10012 adódik.
Jegyezzük meg, hogy kettes komplemens kódban 12710 a legnagyobb ábrázolható pozitív szám, és −12810 a legkisebb ábrázolható negatív szám.

Ha képezzük a −2310+2310 összeget 0001|01112+1110|10012=1|0000|00002 adódik, ami éppen a 8 bites regiszter m=256 modulusának 2-es számrendszerben ábrázolt értéke. Általánosan is igaz, hogy egy 'n' bites regiszterben (a megengedett −m/2≤x<m/2 számtartományon belül) egy kettes komplemens kódban ábrázolt negatív szám és a vele abszolút értékben megegyező nemnegatív szám összege a regiszter modulusát adja. Formálisan kifejezve: ha a megengedett számtartományon belül 'v' egy nemnegatív egész számot jelöl, 'w' pedig ennek kettes komplemens kódját, akkor v+w=m vagy másképpen kifejezve v+w=0 (mod m) teljesül.

Két fontos szabály:

Negatív egész számokat kettes komplemens kódban ábrázolva a kivonást összeadásra tudjuk visszavezetni.

Ennek megfelelően kétféle túlcsordulás fordulhat elő:


A fenti algoritmusokat megvalósító JavaScript programok:

(1) Decimális szám kettes komplemens kódban ábrázolt bináris számmá alakítása:

// decimális szám átalakítása kettes komplemens kódban ábrázolt bináris számmá (8 biten)

function dec2bin(x) {
 var b="";
 var q=1;

 while(q>0) {
  q=Math.trunc(x/2); // egész osztás!!
  if(x%2==1) {
   b="1"+b;
   }
  else {
   b="0"+b;
   }
  x=q;
  }

 while(b.length<m) {
  b="0"+b; // vezető 0 hozzáadása
  }
 return b;
 }

function bin2binc(x) {
 var xc="";
 for(var i=0;i<x.length;i++) {
  if(x[i]=="1") {
   xc=xc+"0";
   }
  else {
   xc=xc+"1";
   }
  }
 return xc; 
 }

function inc(x) {
 var xc="";
 var j=x.length-1; // utolsó karakter indexe
 var atvitel=1;
 while(j>=0) {
  if(x[j]=="0" && atvitel==0) {
   xc="0"+xc;
   }
  else if(x[j]=="0" && atvitel==1) {
   xc="1"+xc;
   atvitel=0;
   }
  else if(x[j]=="1" && atvitel==0) {
   xc="1"+xc;
   }
  else {
   xc="0"+xc;
   atvitel=1;
   }
  j=j-1;
  }
 return xc; 
 }

/* feltétel: nyolc biten ábrázoljuk a számokat (m=8), tehát -128<=xd<127 teljesül */

var m=8; // bitek száma
var xd=-127; 
var xb="";

writeln("Decimális szám: "+xd);
writeln();

if(xd>=0) {
 xb=dec2bin(xd);
 }
else {
 var xa,x;
 xd=-xd;
 writeln("Abszolút érték: "+xd);
 writeln();

 xa=dec2bin(xd);
 writeln("Bináris érték:     "+xa);
 x=bin2binc(xa);
 writeln("Egyes komplemens:  "+x);
 xb=inc(x);
 writeln();
 }

writeln("Kettes komplemens: "+xb);

writeln("__________");

(2) Kettes komplemens kódban adott bináris szám decimálissá alakítása:

// kettes komplemens kódban adott (8 bites) bináris szám átalakítása decimális számmá

function bin2dec(x) {
 var d=0;
 var helyiertek=1;

 for(var i=1;i<x.length;i++) {
  helyiertek*=2;
  }

 for(var i=0;i<x.length;i++) {
  var sz;
  if(x[i]=="1") {
   sz=1;
   }
  else {
   sz=0;
   }
  var r=sz*helyiertek;
  d+=r;
  helyiertek/=2;
  }

 return d;
 }

function bin2binc(x) {
 var xc="";
 for(var i=0;i<x.length;i++) {
  if(x[i]=="1") {
   xc=xc+"0";
   }
  else {
   xc=xc+"1";
   }
  }
 return xc; 
 }

function inc(x) {
 var xc="";
 var j=x.length-1; // utolsó karakter indexe
 var atvitel=1;
 while(j>=0) {
  if(x[j]=="0" && atvitel==0) {
   xc="0"+xc;
   }
  else if(x[j]=="0" && atvitel==1) {
   xc="1"+xc;
   atvitel=0;
   }
  else if(x[j]=="1" && atvitel==0) {
   xc="1"+xc;
   }
  else {
   xc="0"+xc;
   atvitel=1;
   }
  j=j-1;
  }
 return xc; 
 }

/* feltétel: nyolc biten ábrázoljuk a számokat (m=8), tehát xb.length=8 teljesül */

var xb="10000001"; 
var s;

writeln("Bináris szám: "+xb);
writeln();

if(xb[0]==0) { // előjelbit pozitív
 s="+";
 }

else { // előjelbit negatív
 s="-";
 var x;
 x=bin2binc(xb);
 writeln("Egyes komplemens: "+x);
 xb=inc(x);
 writeln("Kettes komplemens: "+xb);
 writeln();
 }

writeln("Decimális szám: "+s+bin2dec(xb));

writeln("__________");

(3) Decimális szám kettes komplemens kódban ábrázolt bináris számmá alakítása és a kettes komplemens kódban adott bináris szám visszaalakítása decimális számmá:

// decimális szám átalakítása kettes komplemens kódban ábrázolt bináris számmá és ennek visszaalakítása függvényekkel

function dec2bin(x) {
 var b="";
 var q=1;

 while(q>0) {
  q=Math.trunc(x/2); // egész osztás!!
  if(x%2==1) {
   b="1"+b;
   }
  else {
   b="0"+b;
   }
  x=q;
  }

 while(b.length<m) {
  b="0"+b; // vezető 0 hozzáadása
  }
 return b;
 }

function bin2dec(x) {
 var d=0;
 var helyiertek=1;

 for(var i=1;i<x.length;i++) {
  helyiertek*=2;
  }

 for(var i=0;i<x.length;i++) {
  var sz;
  if(x[i]=="1") {
   sz=1;
   }
  else {
   sz=0;
   }
  var r=sz*helyiertek;
  d+=r;
  helyiertek/=2;
  }

 return d;
 }

function bin2binc(x) {
 var xc="";
 for(var i=0;i<x.length;i++) {
  if(x[i]=="1") {
   xc=xc+"0";
   }
  else {
   xc=xc+"1";
   }
  }
 return xc; 
 }

function inc(x) {
 var xc="";
 var j=x.length-1; // utolsó karakter indexe
 var atvitel=1;
 while(j>=0) {
  if(x[j]=="0" && atvitel==0) {
   xc="0"+xc;
   }
  else if(x[j]=="0" && atvitel==1) {
   xc="1"+xc;
   atvitel=0;
   }
  else if(x[j]=="1" && atvitel==0) {
   xc="1"+xc;
   }
  else {
   xc="0"+xc;
   atvitel=1;
   }
  j=j-1;
  }
 return xc; 
 }

/* feltétel: nyolc biten ábrázoljuk a számokat (m=8), tehát -128<=xd<127 teljesül */

var m=8; // bitek száma
var xd=-127; 
var xb="";

writeln("Decimális szám: "+xd);
writeln();

if(xd>=0) {
 xb=dec2bin(xd);
 }
else {
 var xa,x;
 xd=-xd;
 writeln("Abszolút érték: "+xd);
 writeln();

 xa=dec2bin(xd);
 writeln("Bináris érték:     "+xa);
 x=bin2binc(xa);
 writeln("Egyes komplemens:  "+x);
 xb=inc(x);
 writeln();
 }

writeln("Kettes komplemens: "+xb);
writeln();

// kettes komplemens kódban adott (8 bites) bináris szám visszaalakítása decimális számmá

var s; // előjelbit

if(xb[0]==0) { // előjelbit pozitív
 s="+";
 }

else { // előjelbit negatív
 s="-";
 var x;
 x=bin2binc(xb);
 writeln("Egyes komplemens: "+x);
 xb=inc(x);
 writeln("Kettes komplemens: "+xb);
 writeln();
 }

writeln("Decimális szám: "+s+bin2dec(xb));

writeln("__________");

(4) Decimális szám kettes komplemens kódban ábrázolt bináris számmá alakítása és a kettes komplemens kódban adott bináris szám visszaalakítása decimális számmá függvények használatával:

// decimális szám átalakítása kettes komplemens kódban ábrázolt bináris számmá és ennek visszaalakítása függvényekkel

function dec2bin(x) {
 var b="";
 var q=x;
 while(q>0) {
  if(q%2==1) {
   b="1"+b;
   q=q-1;
   }
  else {
   b="0"+b;
   }
  q=q/2;
  }
 while(b.length<m) {
  b="0"+b; // vezető 0-k
  }
 return b;
 }

function bin2dec(x) {
 var d=0;
 var h=1;
 for(var i=x.length-1;i>=0;i--) {
  if(x[i]=="1") {
   d=d+h;
   }
  h=h*2;
  }
 return d;
 }

function bin2binc(x) {
 var xc="";
 for(var i=0;i<x.length;i++) {
  if(x[i]=="1") {
   xc=xc+"0";
   }
  else {
   xc=xc+"1";
   }
  }
 return xc; 
 }

function inc(x) {
 var xc="";
 var carry="1";
 for(var j=x.length-1;j>=0;j--) {
  var t=x[j]+carry;
  switch(t) {
   case "00": xc="0"+xc;break;
   case "01": 
    xc="1"+xc;
    carry="0";
    break;
   case "10": xc="1"+xc;break; 
   case "11": 
    xc="0"+xc;
    carry="1";
    break;
   }
  }
 return xc; 
 }

function dec2binc(xd) {
 var xb;
 if(xd>=0) {
  xb=dec2bin(xd);
  }
 else {
  var xa,x;
  xd=-xd;
  xa=dec2bin(xd);
  x=bin2binc(xa);
  xb=inc(x);
  } 
 return xb;
 }

function binc2dec(xb) {
 var xd;
 var s;
 if(xb[0]==0) { 
  s="0";
  }
 else { 
  s="1";
  var x;
  x=bin2binc(xb);
  xb=inc(x);
  }
 xd=bin2dec(xb);
 if(s=="1") {
  xd=-xd;
  }
 return xd;
 }

/* feltétel: m=8, -128<=xd<127 */

var m=8; // bitek száma
var xd=-58; 
var xb="";

writeln("Decimális szám: "+xd);
writeln();

xb=dec2binc(xd);

writeln("Kettes komplemens: "+xb);
writeln();

xd=binc2dec(xb);

writeln("Decimális szám: "+xd);

writeln("__________");

(5) Két decimális szám kettes komplemens kódban ábrázolt bináris számokká alakítása és ennek ellenőrzése a számok összegének kiszámításával:

// két decimális szám kettes komplemens kódban ábrázolt bináris számokká alakítása és az összeg ellenőrzése

function dec2bin(x) {
 var b="";
 var q=x;
 while(q>0) {
  if(q%2==1) {
   b="1"+b;
   q=q-1;
   }
  else {
   b="0"+b;
   }
  q=q/2;
  }
 while(b.length<m) {
  b="0"+b; // vezető 0-k
  }
 return b;
 }

function bin2dec(x) {
 var d=0;
 var h=1;
 for(var i=x.length-1;i>=0;i--) {
  if(x[i]=="1") {
   d=d+h;
   }
  h=h*2;
  }
 return d;
 }

function bin2binc(x) {
 var xc="";
 for(var i=0;i<x.length;i++) {
  if(x[i]=="1") {
   xc=xc+"0";
   }
  else {
   xc=xc+"1";
   }
  }
 return xc; 
 }

function inc(x) {
 var xc="";
 var carry="1";
 for(var j=x.length-1;j>=0;j--) {
  var t=x[j]+carry;
  switch(t) {
   case "00": xc="0"+xc;break;
   case "01": 
    xc="1"+xc;
    carry="0";
    break;
   case "10": xc="1"+xc;break; 
   case "11": 
    xc="0"+xc;
    carry="1";
    break;
   }
  }
 return xc; 
 }

function dec2binc(xd) {
 var xb;
 if(xd>=0) {
  xb=dec2bin(xd);
  }
 else {
  var xa,x;
  xd=-xd;
  xa=dec2bin(xd);
  x=bin2binc(xa);
  xb=inc(x);
  } 
 return xb;
 }

function binc2dec(xb) {
 var xd;
 var s;
 if(xb[0]==0) { 
  s="0";
  }
 else { 
  s="1";
  var x;
  x=bin2binc(xb);
  xb=inc(x);
  }
 xd=bin2dec(xb);
 if(s=="1") {
  xd=-xd;
  }
 return xd;
 }

function addition(x,y) {
 var xb="";
 var c="0";
 var car="";
 var res="";
 for(var i=x.length-1;i>=0;i--) {
  var t=x[i]+y[i]+c;
  var r;
  switch(t) {
   case "000":r="0";c="0";break;
   case "001":r="1";c="0";break;
   case "010":r="1";c="0";break;
   case "011":r="0";c="1";break;
   case "100":r="1";c="0";break;
   case "101":r="0";c="1";break;
   case "110":r="0";c="1";break;
   case "111":r="1";c="1";break;
   }
  car=(c=="0"?"-":"c")+car;
  res=r+res;
  xb=r+xb;
  }
 writeln(x);
 writeln(y);
 writeln(car);
 writeln(res);
 writeln();
 return xb;
 }

/* feltétel: m=8, -128<=xd<127 */

var m=8; // bitek száma
var xd1=-100; 
var xb1="";
var xd2=200;
var xb2="";
var xbx; // xb1 és xb2 összege kettes komplemens kódban
var sum;
var xsum;

writeln("1. decimális szám: "+xd1);
xb1=dec2binc(xd1);
writeln("   Kettes komplemens: "+xb1);
writeln();

writeln("2. decimális szám: "+xd2);
xb2=dec2binc(xd2);
writeln("   Kettes komplemens: "+xb2);
writeln();

/* az összeg kiszámítása */

sum=xd1+xd2;

writeln("A számok összege: "+sum);
xsum=dec2binc(sum);
writeln("   Kettes komplemens: "+xsum);
writeln();

xbx=addition(xb1,xb2);
writeln("   Kettes komplemens: "+xbx);

writeln("__________");



Számábrázolás a számítógépen: binárisan kódolt decimális (BCD) kódolás

BCD számábrázolás esetén tízes számrendszerben megadott egész számokat kódolunk a decimális számjegyek adott számú biten történő bináris megadásával.

Például az 12310 egész számot a következőképpen ábrázolhatjuk:

A BCD számábrázolás két típusa:
– pakolt, csomagolt vagy tömörített ("packed") BCD esetén a decimális számjegyeket 4 biten (1 tetrádon) ábrázoljuk (egy bájt felső vagy alsó 4 bitje egy ún. fél bájt vagy tetrád, angolul "nibble");
– pakolatlan, kibontott vagy zónázott ("unpacked") BCD esetén a decimális számjegyeket 8 biten (1 bájton) ábrázoljuk (a felső 4 bitet az ún. zónabitek alkotják, az alsó 4 bit pedig az ábrázolandó decimális számjegy bináris alakját tartalmazza).

Az x86-os architektúra numerikus adatfeldolgozó processzora (NDP) támogatja az előjeles pakolt BCD formátumot. Az így ábrázolt adatok rögzített méretűek (10 bájt hosszúak):
– a jobb szélső 9 bájt tartalmazza a decimális számjegyeket (18 számjegy);
– a bal szélső bájt bal szélső bitje előjelbit: a bit 0 értéke esetén a szám pozitív, 1 értéke esetén a szám negatív (a fennmaradó 7 bit kihasználatlan).


A pakolt BCD számábrázolás kódolásakor szükségünk lesz egy olyan függvényre, amely egy megadott decimális számjegyet egy 4 bites kettes számrendszerbeli számmá alakít. Ehhez először ismételjük át, hogyan tudunk egy decimális számot bináris számmá alakítani, majd módosítsuk a programot úgy, hogy a 'b' véltozóban előállított bitsorozat egy legalább négy bites bináris szám legyen:

// decimális számjegy átalakítása 4 bites bináris számmá 

var x=3; 

writeln("Decimális számjegy: "+x);
writeln();

var b="";
var q,m;

while(x>0) {
 if(x%2==1) {
  m=1;
  x=x-1;
  }
 else {
  m=0;
  }
 q=x/2;
 b=m+b;
 x=q;
 }

var i=b.length;
while(i<4) {
 b="0"+b; // vezető 0 hozzáadása
 i=i+1;
 }

writeln("Bináris szám: "+b);

writeln("__________");

Ezután hajtsuk végre a következő lépéseket:
    (1) hozzunk létre egy 'dec2bin4' nevű függvényt a program elején, és adjuk meg zárójelek közt a függvény argumentumát szolgáltató 'x' változót, majd
    (2) a programnak azt a részét, amely az 'x' változó megadott értékéből előállítja a 'b' változóban a keresett 4 bites kettes számrendszerbeli számot, tegyük bele a 'dec2bin4' nevű függvény blokkjába, és végül
    (3) a blokk utolsó utasításának adjuk meg a 'return b;' utasítást, amely a 'dec2bin4(...)' függvény értékét adja vissza.
Így a következő programhoz jutunk:

// decimális számjegy átalakítása 4 bites bináris számmá függvény segítségével

function dec2bin4(x) { 
// függvény blokkjának kezdete

var b="";
var q,m;

while(x>0) {
 if(x%2==1) {
  m="1";
  x=x-1;
  }
 else {
  m="0";
  }
 q=x/2;
 b=m+b;
 x=q;
 }

var i=b.length;
while(i<4) {
 b="0"+b; // vezető 0 hozzáadása
 i=i+1;
 }

return b;
// függvény blokkjának vége
} 

var x=3; 

writeln("Decimális számjegy: "+x);
writeln();

writeln("Bináris szám: "+dec2bin4(x));

writeln("__________");

Figyeljük meg, hogy a függvény kipróbálásához elegendó a program végén (az ún. "főprogramban") 5 sor. A függvényt pedig innentől kezdve akárhányszor meghívhatjuk anélkül, hogy a számítás lépéseit újra és újra le kellene írnunk.

Felhasználva a 'dec2bin4' függvényt, a pakolt, előjel nélküli BCD számábrázolást megvalósító algoritmust például a következőképpen írhatjuk le egy JS program segítségével:

// decimális szám átalakítása előjel nélküli pakolt BCD formátumra

function dec2bin4(x) {

var b="";
var q,m;

while(x>0) {
 if(x%2==1) {
  m="1";
  x=x-1;
  }
 else {
  m="0";
  }
 q=x/2;
 b=m+b;
 x=q;
 }

var i=b.length;
while(i<4) {
 b="0"+b; // vezető 0 hozzáadása
 i=i+1;
 }

return b;
} 

var x="314"; 

writeln("Decimális szám: "+x);
writeln();

var i=0;
var bcd="";

while(i<x.length) {
 bcd=bcd+dec2bin4(x[i])+" ";
 i=i+1;
 }

if(x.length%2!=0) {
 bcd="0000"+" "+bcd;
 }

writeln("Pakolt előjel nélküli BCD kód: ");
writeln(bcd);

writeln("__________");

Az előjeles BCD számábrázolást megvalósító algoritmust hasonlóképpen kódolhatjuk:

// decimális szám átalakítása előjeles pakolt BCD formátumra

function dec2bin4(x) {

var b="";
var q,m;

while(x>0) {
 if(x%2==1) {
  m="1";
  x=x-1;
  }
 else {
  m="0";
  }
 q=x/2;
 b=m+b;
 x=q;
 }

var i=b.length;
while(i<4) {
 b="0"+b; // vezető 0 hozzáadása
 i=i+1;
 }

return b;
} 

var x="-314"; 
var sign=0; // alapértelmezésben pozitív
if (x[0]=="-"){
 sign=1;
 };

writeln("Decimális szám: "+x);
writeln();

var i=0;
var bcd="";

while(i<x.length) {
 bcd=bcd+dec2bin4(x[i])+" ";
 i=i+1;
 }

if(x.length%2==0) {
 bcd="0000"+" "+bcd;
 }

if(sign==0) {
 bcd=bcd+"1100"; // hexa 'C' jelzi a pozitív előjelet
 }
else {
 bcd=bcd+"1101"; // hexa 'D' jelzi a negatív előjelet
 }

writeln("Pakolt előjeles BCD kód: ");
writeln(bcd);

writeln("__________");

Az előjel nélküli pakolatlan ("zónázott") BCD számábrázolást megvalósító algoritmus:

// decimális szám átalakítása előjel nélküli pakolatlan BCD formátumra

function dec2bin4(x) {

var b="";
var q,m;

while(x>0) {
 if(x%2==1) {
  m="1";
  x=x-1;
  }
 else {
  m="0";
  }
 q=x/2;
 b=m+b;
 x=q;
 }

var i=b.length;
while(i<4) {
 b="0"+b; // vezető 0 hozzáadása
 i=i+1;
 }

return b;
} 

var x="314"; 

writeln("Decimális szám: "+x);
writeln();

var i=0;
var bcd="";
var zona="1111";

while(i<x.length) {
 bcd=bcd+zona+dec2bin4(x[i])+" ";
 i=i+1;
 }

writeln("Pakolatlan előjel nélküli BCD kód: ");
writeln(bcd);

writeln("__________");

Az előjeles pakolatlan ("zónázott") BCD számábrázolást megvalósító algoritmus pedig a következő:

// decimális szám átalakítása előjeles pakolatlan BCD formátumra

function dec2bin4(x) {

var b="";
var q,m;

while(x>0) {
 if(x%2==1) {
  m="1";
  x=x-1;
  }
 else {
  m="0";
  }
 q=x/2;
 b=m+b;
 x=q;
 }

var i=b.length;
while(i<4) {
 b="0"+b; // vezető 0 hozzáadása
 i=i+1;
 }

return b;
} 

var x="314"; 
var sign=0; // alapértelmezésben pozitív
if (x[0]=="-"){
 sign="1";
 };

writeln("Decimális szám: "+x);
writeln();

var i=0;
var bcd="";
var zona="1111";

while(i<x.length) {
 if(i==x.length-1) { // utolsó bájt
  if(sign==0) {
   zona="1010"; // hexa 'C' jelzi a pozitív előjelet
   }
  else {
   zona="1011"; // hexa 'D' jelzi a negatív előjelet
   }
 }
 bcd=bcd+zona+dec2bin4(x[i])+" ";
 i=i+1;
 }

writeln("Pakolatlan előjeles BCD kód: ");
writeln(bcd);

writeln("__________");



Számábrázolás a számítógépen: lebegőpontos számábrázolás

Lebegőpontos számábrázolás esetén 2-es normál alakban megadott valós számokat kódolunk adott pontossággal. Ennek alapja az, hogy az ábrázolandó 'x' valós számot
x = s*m*2k
normál alakban adjuk meg, ahol 's' a szám előjele (s=±1), 'm' a kettedes tört formában megadott ún. mantissza (m∈ℝ, normál esetben 1≤m<2), és 'k' az ún. karakterisztika (k∈ℤ).

A mantissza számjegyeinek (bitjeinek) a száma a számábrázolás pontosságát, a karakterisztika pedig az ábrázolható számok nagyságrendjét határozza meg (vö. Nyakóné Juhász 2011: 21).

A lebegőpontos számok ábrázolása

A továbbiakban az egyszeres pontosságú, 32 bites lebegőpontos számábrázolással foglalkozunk. (Az Institute of Electrical and Electronics Engineers (IEEE) által a nyolcvanas években kiadott IEEE 754 nevű szabvány alapján, vö. Nyakóné Juhász 2011: 21-22).

Ha egyszeres pontossággal, 32 biten ábrázolunk egy lebegőpontos számot, akkor
– az előjelet a bal szélső 1 biten a szokásos módon,
– a karakterisztikát a következő 8 biten többletes kódolással,
– a mantisszát pedig a fennmaradó 23 biten fixpontos kódolással
ábrázoljuk.

b b b ... b b b b b b b ... b b b
előjel (sign, 1 bit)
karakterisztika (exponent, 8 bit)
mantissza (fraction, 23 bit)

Jelöljük
– az ábrázolt valós számot 'x'-szel;
– a karakterisztika tényleges értékét 'k'-val, az egyszeres pontosságú lebegőpontos számnak a karakterisztika számára fenntartott 8 bitjén direkt kódolással ábrázolt "többletes" (127-tel, ill. kis számok esetén 126-tal eltolt) értéket pedig exp-val;
– a mantissza tényleges értékét 'm'-mel, az egyszeres pontosságú lebegőpontos számnak a mantissza számára fenntartott 23 bitjén fixpontos kódolással ábrázolt értéket pedig frac-val.

Három esetet különböztetünk meg:

(1) "normál" eset:
– a karakterisztika legalább −126 (azaz k≥−126), és az ábrázolt exponens legalább 1 (exp≥1, azaz exp≠0);
– a karakterisztika legfeljebb 127 (azaz k≤127), és az ábrázolt exponens legfeljebb 254 (exp≤254, azaz exp≠255);

Normál esetben az ábrázolandó 'x' valós számra 1≤m<2 miatt
    |x|≥2−126≈1.1754943508222875079687365372222*10−38
és
    |x|<2128≈3.4028236692093846346337460743177*1038
teljesül.

Összefoglalva:

Ha a karakterisztika (k) kódolt értéke nem zérus (vagyis a karakterisztika −126-nál nem kisebb egész szám), a mantissza tényleges értékét (m) egy olyan kettedes törttel fejezzük ki, amelynek egész része mindig 1 (vagyis a mantissza 1≤m<2 közötti valós szám). Az egyszeres pontosságú lebegőpontos számnak a mantissza számára fenntartott 23 bitje ilyenkor a mantissza tört részének bináris számjegyeit adja meg.

Megjegyzések:
– a karakterisztika tényleges értékének (k) fenti módon történő kódolását ún. 127-es többletes kódolásnak nevezzük (ez k+127 direkt kódban történő ábrázolását jelenti adott számú (ti. 8) biten);
– a kettedestörtek számjegyeinek (az egész résznek és/vagy a tört résznek) adott számú biten történő ábrázolását nevezzük ún. fixpontos számábrázolásnak (a mantissza ábrázolása ezt a kódolási formát követi, mivel a mantissza tört részének bináris számjegyeit rögzített számú (ti. 23) biten adjuk meg);
– az (1) esetben ábrázolható legkisebb szám esetén exp=1 és frac=0, tehát
    x(1),min=1.0000...*2−126=2−126;
– az (1) eset ekvivalens azzal, amikor a karakterisztika −125≤k≤128 közötti egész szám és a mantissza 1/2≤m<1 közötti valós szám (vagyis a mantisszát 0.1-re normáljuk). Ekkor a karakterisztikát 8 biten 126-os többletes kódban adjuk meg, azaz az exp=k+126 egész számot ábrázoljuk direkt kódban (1≤exp≤254), és a mantissza kettedestört alakjában a mantissza 0.1 utáni bináris számjegyeit ábrázoljuk a rendelkezésre álló 23 biten.

(2) a zérushoz közeli ("kis") számok esete: a karakterisztika −126, és az ábrázolt exponens zérus

Zérushoz közeli számok esetén az ábrázolandó 'x' valós számra
    |x|<2−126≈1.1754943508222875079687365372222*10−38
teljesül.

Ha az ábrázolandó valós számra 0≤|x|<2−126 teljesül, akkor

Ha a karakterisztika (k) kódolt értéke zérus (vagyis a karakterisztika értéke −126), a mantissza tényleges értékét (m) egy olyan kettedes törttel fejezzük ki, amelynek egész része mindig 0 (vagyis a mantissza 0≤m<1/2 közötti valós szám). Az egyszeres pontosságú lebegőpontos számnak a mantissza számára fenntartott 23 bitje ilyenkor is a mantissza tört részének bináris számjegyeit adja meg. Ha a mantissza értéke zérus, akkor a lebegőpontos szám értéke is zérus (az előjeltől függetlenül).

Megjegyzések:
– ha az (1) esetben a mantisszát 0.1-re normáljuk (azaz 1/2≤m<1 teljesül), akkor a (2) eset annak a speciális esetnek felel meg, amikor a karakterisztika k=−126 (és exp=0); de mivel szeretnénk a zérust is ábrázolni, most megengedjük az 1/2-nél kisebb nemnegatív mantisszákat is (vagyis ebben az esetben 0≤m<1 teljesül);
– a (2) esetben alkalmazott kódolás lehetővé teszi a zérus ábrázolását ("lebegőpontos nulla"), sőt valójában ez kétféleképpen is lehetséges: ha az egyszeres pontosságú lebegőpontos számok számára rendelkezésre álló 32 biten csupa 0 szerepel, "pozitív" zérusról, ha pedig az első bit 1, és utána 31 biten csupa 0 szerepel, "negatív" zérusról beszélhetünk;
– a (2) esetben ábrázolható legnagyobb szám m=0.1111... és exp=0 (azaz k=−126) miatt
    x(2),max=0.1111...*2−126≲2−126.

(3) túlcsordulás: a karakterisztika legalább 128, és az ábrázolt exponens 255 (azaz binárisan 1111|1111) (az abszolút értékben "túlságosan" nagy, ezért lebegőpontosan már nem ábrázolható számok esete)

Ha az ábrázolandó számra 2128≤|x| teljesül, akkor a valós szám már nem ábrázolható az egyszeres pontosságú lebegőpontos formátumban. Ekkor

Túlcsorduláskor az ábrázolt bitsorozatot a mantissza értékétől függetlenül nem számként értelmezzük, hanem az előjelbittől függően plusz, ill. minusz végtelenként (±∞). A túlcsordulás szokásos jelölése NaN ("not a number").

1. példa (vö. Nyakóné Juhász 2011: 22): Tekintsük az alábbi 32 bites bitsorozatot, amely egy egyszeres pontosságú lebegőpontos számot határoz meg:
    x=1 10000111 101000000000000000000002
Határozzuk meg, ez milyen valós számnak felel meg!

A lebegőpontos számábrázolás (1) esetét alapul véve
– mivel az előjelbit 1, ezért 'x' negatív;
– mivel k'=1000|01112=13510, ezért a karakterisztika értéke k=k'−127=8;
– mivel az 1-re normált mantissza m=1.101000...2, ezért
m=1+1/2+1/8=8/8+5/8=13/8

Tehát a keresett valós szám 28=256 miatt
x=−13/8*28=−13/8*256=−416

Vizsgáljuk meg azt az esetet, amikor a mantisszát 0.1-re normáljuk. Ekkor a következőket kapjuk:
– mivel az előjelbit 1, ezért 'x' negatív;
– mivel k'=1000|01112=13510, ezért a karakterisztika értéke k=k'−126=9;
– mivel a 0.1-re normált mantissza m=0.1101000...2, ezért
m=1/2+1/4+1/16=8/16+4/16+1/16=13/16
Tehát a keresett valós szám 29=512 miatt
x=−13/16*29=−13/16*512=−416
megegyezik az előző értékkel.


Az algoritmus egyszerű megvalósításához fel fogjuk használni a JavaScript nyelv Math.pow(x,k) függvényét, amely egy 'x' szám 'k'-dik hatványát (azaz xk értékét) számolja ki. A fenti algoritmust megvalósító JavaScript program ezek után a következő:

// lebegőpontos számot ábrázoló bináris számsorozat átalakítása decimális számmá (1. példa)

function bin2dec(x) {
 var d=0;
 var helyiertek=1;

 for(var i=1;i<x.length;i++) {
  helyiertek*=2;
  }

 for(var i=0;i<x.length;i++) {
  var sz;
  if(x[i]=="1") {
   sz=1;
   }
  else {
   sz=0;
   }
  var r=sz*helyiertek;
  d+=r;
  helyiertek/=2;
  }

 return d;
 }

function binf2decf(x) {
 var d=0;
 var helyiertek=1/2;

 for(var i=0;i<x.length;i++) {
  var sz;
  if(x[i]=="1") {
   sz=1;
   }
  else {
   sz=0;
   }
  var r=sz*helyiertek;
  d+=r;
  helyiertek/=2;
  }

 return d;
 }

/* feltétel: exp>0 vagyis a lebegőpontos számábrázolás (1) esetének megfelelő algoritmust valósítjuk meg */

var s="1";
var exp="10000111";
var frc="10100000000000000000000"; 

writeln("Lebegőpontos szám: "+s+" "+exp+" "+frc);
writeln();

var e;
var k;
var m;

if(s=="0") {
 e=1;
 }
else {
 e=-1;
 }

k=bin2dec(exp)-127;

m=1+binf2decf(frc);

writeln("Előjel: "+e);
writeln("Karakterisztika: "+k);
writeln("Mantissza: "+m);
writeln();

var d=e*Math.pow(2,k)*m;

writeln("Decimális szám: "+d);

writeln("__________");


2. példa: Tekintsük az alábbi 32 bites bitsorozatot, amely most is egy egyszeres pontosságú lebegőpontos számot határoz meg:
    x=0 00000000 101000000000000000000002
Határozzuk meg, ez (közelítőleg) milyen valós számnak felel meg!

A lebegőpontos számábrázolás (2) esetét alapul véve
– mivel az előjelbit 0, ezért 'x' pozitív;
– mivel k'=0000|00002=010, ezért a karakterisztika értéke k=k'−126=−126;
– mivel a 0.-val kezdődő mantissza m=0.101000...2, ezért
m=1/2+1/8=5/8

Tehát a keresett valós szám
x=5/8*2−126≈7.3468...10−39


A fenti algoritmust megvalósító JavaScript program:

// lebegőpontos számot ábrázoló bináris számsorozat átalakítása decimális számmá (2. példa)

function binf2decf(x) {
 var d=0;
 var helyiertek=1/2;

 for(var i=0;i<x.length;i++) {
  var sz;
  if(x[i]=="1") {
   sz=1;
   }
  else {
   sz=0;
   }
  var r=sz*helyiertek;
  d+=r;
  helyiertek/=2;
  }

 return d;
 }

/* feltétel: exp=0 vagyis a lebegőpontos számábrázolás (2) esetének megfelelő algoritmust valósítjuk meg */

var s="0";
var exp="00000000";
var frc="10100000000000000000000"; 

writeln("Lebegőpontos szám: "+s+" "+exp+" "+frc);
writeln();

var e;
var k;
var m;

if(s=="0") {
 e=1;
 }
else {
 e=-1;
 }

k=-126;

m=binf2decf(frc);

writeln("Előjel: "+e);
writeln("Karakterisztika: "+k);
writeln("Mantissza: "+m);
writeln();

var d=e*Math.pow(2,k)*m;

writeln("Decimális szám: "+d);

writeln("__________");


3. példa: Tekintsük az alábbi valós számot:
    x=7.510
Határozzuk meg, a szám lebegőpontos ábrázolása milyen bitekből áll!

A szám lebegőpontos ábrázolása x≫2−126 miatt egészen nyilvánvalóan a normál esetnek felel meg.

A fentiek alapján x=7.5 lebegőpontosan ábrázolt alakja
    x= 0 10000001 11100000000000000000000 2
formában fejezhető ki.


A fenti algoritmust megvalósító JavaScript program:

// decimális szám átalakítása lebegőpontos számot ábrázoló bináris számsorozattá

function dec2bin(x,maxi) {
 var b="";
 var helyiertek=1;
 
 while(2*helyiertek<=x) {
  helyiertek*=2;
  }
 
 while(helyiertek>=1) {
  if(helyiertek<=x) {
   b+="1";
   x-=helyiertek;
   }
  else {
   b+="0";
   }
  helyiertek/=2;
  }
 
 while(b.length<maxi) {
  b="0"+b; // vezető 0
  }
 return b;
 }

function decf2binf(x,maxi) {
 var s="";
 
 var i=1;
 while(x>0 && i<=maxi) {
  x*=2;
  if(x<1) {
   s+="0";
   }
  else {
   s+="1";
   x=x-1;
   }
  i++;
  }

 while(s.length<maxi) {
  s=s+"0" // záró 0
  }
 return s;
 }

/* feltétel: x abszolút értéke elegendően nagy (x>>0); a lebegőpontos számábrázolás normál (1) esetének megfelelő algoritmust valósítjuk meg */

var x=7.5;
// var x=-0.15;

writeln("Ábrázolandó decimális szám: "+x);
writeln();

var s;
var exp;
var frc; 

var e;
var k;
var m;

if(x>0) {
 e=1;
 s="0";
 }
else {
 e=-1;
 s="1";
 x=-x; // abszolút érték
 }

k=0;
if(x>=2) {
 while(x>=2) {
  x=x/2;
  k=k+1;
  }
 }
else if(x<1) {
 while(x<1) {
  x=x*2;
  k=k-1;
  }
 }

exp=dec2bin(k+127,8);

m=x;
frc=decf2binf(m-1,23);

writeln("Előjel: "+e);
writeln("Karakterisztika: "+k);
writeln("Mantissza: "+m);
writeln();

// var d=e*Math.pow(2,k)*m;
// writeln("Ábrázolandó decimális szám: "+d);

writeln("Lebegőpontos szám: "+s+" "+exp+" "+frc);

writeln("__________");




Tartalom
Boda István, 2023-2025.