                         Rutine matematice pentru x51
                         ----------------------------


                                                          Student: Florin Leon

     Rezumat:

     Proiectul  contine implementarile unor rutine matematice pentru calcul in
virgula mobila (floating-point): adunare, scadere, inmultire, impartire.

     Scop:

     Nota  de  aplicatie  isi propune sa familiarizeze proiectantul cu notiuni
referitoare  la  reprezentarea  digitala  a numerelor reale in standardul IEEE
floating-point,  precum  si  cu algoritmii necesari pentru lucrul cu numere in
virgula mobila.
     Resurse: SBC 80C32, compilator C (Franklin Software Micro-C).


--------------------------------------------------------------------------------
                             Prezentarea solutiei
--------------------------------------------------------------------------------

     1. Standardul IEEE pentru aritmetica in virgula mobila

     Standardul  IEEE  (Institute  of  Electrical  and  Electronics Engineers)
defineste  modul  de  reprezentare  a numerelor in virgula mobila in simpla si
dubla  precizie.  Pentru  aplicatia  de fata, s-a considerat suficienta simpla
precizie.
     Standardul  IEEE  simpla  precizie  necesita  4 octeti (32 de biti), unde
primul  bit  este bitul de semn, urmatorii 8 reprezinta exponentul iar ultimii
23 de biti codifica mantisa (fractia):

     S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
     0 1      8 9                    31

     Astfel, valoarea numarului este:

     -  Daca  0<E<255  =>  V=(-1)^S  * 2^(E-127) * (1.F) unde "1.F" reprezinta
numarul binar 1+F (F<1)
     - Daca E=0 si F!=0 => V=(-1)^S * 2^(-126) * (0.F)
     - Daca E=0 si F=0 si S=1 => V=-0
     - Daca E=0 si F=0 si S=0 => V=0
     - Daca E=255 si F!=0 => V=NaN ("Not a number")
     - Daca E=255 si F=0 si S=1 => V=-Infinity
     - Daca E=255 si F=0 si S=0 => V=+Infinity


     De exemplu:

     0 00000000 00000000000000000000000 = 0
     1 00000000 00000000000000000000000 = -0

     0 11111111 00000000000000000000000 = +Infinity
     1 11111111 00000000000000000000000 = -Infinity

     0 11111111 00000100000000000000000 = NaN
     1 11111111 00100010001001010101010 = NaN

     0 10000000 00000000000000000000000 = +1 * 2^(128-127) * 1.0 = 2
     0 10000001 10100000000000000000000 = +1 * 2^(129-127) * 1.101 = 6.5
     1 10000001 10100000000000000000000 = -1 * 2^(129-127) * 1.101 = -6.5

     0 00000001 00000000000000000000000 = +1 * 2^(1-127) * 1.0 = 2^(-126)
     0 00000000 10000000000000000000000 = +1 * 2^(-126) * 0.1 = 2^(-127)

     In  cele  ce urmeaza, vom considera un bit suplimentar, "ascuns", in fata
mantisei. De exemplu, numarul 2.25 este:

     0 - 1000 0000 - (1)001 0000 0000 0000 0000 0000


     2. Adunarea si scaderea

     Vom considera un exemplu: adunarea 2.25+134.0625
     Numarul 134.0625 este reprezentat astfel:

     0 - 1000 0110 - (1)000 0110 0001 0000 0000 0000

     Pasul 1
     Pentru  alinierea virgulei binare, exponentul mai mic este incrementat si
mantisa este deplasata la dreapta pana cand exponentii sunt egali.

     2.25 devine:
     0 - 1000 0110 - (0)000 0010 0100 0000 0000 0000


     Pasul 2
     Mantisele sunt adunate folosind adunarea intreaga:

     0 - 1000 0110 - (0)000 0010 0100 0000 0000 0000 +
     0 - 1000 0110 - (1)000 0110 0001 0000 0000 0000
     ---------------------------------------------------
     0 - 1000 0110 - (1)000 1000 0101 0000 0000 0000


     Pasul 3
     Rezultatul  este  in  forma normala. Daca suma provoaca depasire in bitul
ascuns,  mantisa  trebuie  deplasata  la  dreapta  si  exponentul incrementat.
Mantisa  este intotdeauna mai mica decat 2, deci suma bitilor ascunsi nu poate
fi mai mare ca 3.


     Observatii:
     - Daca diferenta dintre exponenti este mai mare decat 24, numarul mai mic
va  fi  deplasat la dreapta in intregime, producand o mantisa nula. Suma va fi
egala cu numarul mai mare.
     - Pentru numerele negative, mantisele vor fi mai intai complementate fata
de 2. Dupa efectuarea adunarii, rezultatul este convertit in forma semn-modul
     -  Cand se aduna numere de semne diferite acestea se pot anula, rezultand
o  suma  foarte mica sau 0, daca numerele sunt egale in modul. Normalizarea in
acest caz presupune deplasarea mantisei cu intreg numarul de biti din mantisa,
rezultand o serioasa diminuare a preciziei.
     - Scaderea in virgula mobila se obtine prin inversarea bitului de semn al
scazatorului si apoi prin realizarea adunarii.



     3. Inmultirea

     Vom considera exemplul inmultirii numerelor 18.0 cu 9.5:

     18.0  =  0 - 1000 0011 - (1)001 0000 0000 0000 0000 0000
      9.5  =  0 - 1000 0010 - (1)001 1000 0000 0000 0000 0000


     Pasul 1
     Inmultirea celor mantise de 24 de biti produce un rezultat pe 48 de biti,
cu 46 de biti la dreapta virgulei binare:

     01.01010110000000...0000

     Pastrand numai 24 de biti, cu bitul ascuns in paranteza, obtinem:

     (1).01010110000000000000000


     Pasul 2
     Exponentii se aduna:
     E= (e1+e2)+127 = (e1+127) + (e2+127) -127 = (E1+E2) -127.

     Suma exponentilor este:

     1000 0011 (4)  +
     1000 0010 (3)
     ----------------
     0000 0101      +
     1000 0001 (-127)
     ----------------
     1000 0110 (7)


     Pasul 3
     Mantisa  este  deja  in  forma  normala. Daca pozitia bitului ascuns este
depasita, mantisa trebuie deplasata la dreapta si exponentul incrementat.

     Pasul 4
     Semnul rezultatului este XOR-ul bitilor de semn ai operanzilor.

     Rezultatul final este:
     0 - 1000 0110 - (1)010 1011 0000 0000 0000 0000

     Observatii:
     -  Rotunjirea  are loc cand mantisa produsului este redusa de la 48 la 24
biti. Bitii mai putin semnificativi sunt pierduti.
     -  Depasirea  are  loc  cand  suma  exponentilor  depaseste  127. Cand se
intampla  acest  lucru, exponentul este facut 128 (E=255) si mantisa devine 0,
indicand  +  sau  -  infinit. Daca suma exponentilor este mai mica decat -126,
exponentul devine -127 (E=0). Daca mantisa este 0, rezultatul este 0.


     4. Impartirea

     Pasul 1
     Mantisa  deimpartitului  este  extinsa  la  48  de biti prin adaugarea de
zerouri  la dreapta celui mai putin semnificativ bit. Se realizeaza impartirea
intreaga  a  mantisei  deimpartitului  la mantisa impartitorului, rezultand un
rezultat (cat) pe 24 de biti.

     Pasul 2
     Se  scade  exponentul impartitorului din exponentul deimpartitului, adica
exponentul primului este complementat fata de 2 si apoi adunat cu al doilea.

     Pasul 3
     Rezultatul este normalizat.

     Pasul 4
     Semnul rezultatului este XOR-ul bitilor de semn ai operanzilor.

     Observatii:
     - La fel ca in cazul inmultirii, poate aparea depasire.
     -  Impartirea  la 0 este nedefinita. In cazul n/0 (n real nenul), am ales
ca  rezultatul  sa  fie  + sau - infinit, in functie de semnul lui n. In cazul
0/0, am ales ca rezultatul sa fie NaN (E=255 si M!=0).


--------------------------------------------------------------------------------
                               Programul sursa
--------------------------------------------------------------------------------

#include <reg51.h>     //biblioteca pentru registre x51
#include <stdio.h>     //biblioteca pentru functii de intrare/iesire (citire,
                       //scriere)


unsigned char r0,r1,r2,r3,r4,r5,r6,r7;
unsigned char x0,x1,x2,y0,y1,y2;
unsigned char z0,z1,z2,z3,z4,z5;
unsigned char t0,t1,t2,t3,t4,t5;

unsigned char a0,a1,a2,a3,sa,ea,b0,b1,b2,b3,sb,eb,op;
unsigned char c0,c1,c2,c3,sc,ec;  //rezultatul
                                  //a,b-operanzii, op-operatia: 1+ 2- 3* 4/
unsigned int temp,temp1;
unsigned char carry;
float a,b;              //numere in virgula mobila pentru partea de test
unsigned char *pa,*pb;  //pointeri pentru partea de test - functia main()


//----------------------------------------------------------------------------
void add()
{
/*
     rutina  de  adunare  a  2  intregi pe 24 de biti, construita dupa modelul
adunarii pe 32 de biti prezentata in manualul Intel - Embedded Applications
     in: x(0-2),y(0-2) => out: x(0-2),carry
*/

carry=0;
temp=x0+y0;             //octetii mai putin semnificativi
x0=temp%256;
carry=temp/256;
temp=x1+y1+carry;       //octetii "de mijloc"
x1=temp%256;
carry=temp/256;
temp=x2+y2+carry;       //octetii cei mai semnificativi
x2=temp%256;
carry=temp/256;
return;
}

//------------------------------------------------------------------------------


void mul()
{
/*
     rutina  de  inmultire  a  2 intregi pe 24 de biti, cu rezultatul pe 48 de
biti,  construita dupa modelul inmultirii pe 16 de biti prezentata in manualul
Intel - Embedded Applications
     in: x(0-2),y(0-2) => out: z(0-5),carry
*/

z5=z4=z3=z2=z1=z0=0;   //initializeaza rezultatul cu 0


temp=x0*y0;            //primii 2 octeti al rezultatului (z0,z1)
z0=temp%256;           //in z0 - partea mai putin semnificativa
z1=temp/256;           //in z1 - partea mai semnificativa

temp=x0*y1;            //urmatorii 2 octeti (z1,z2)
temp1=z1+temp%256;     //rezultatul partial de aici se aduna cu rezultatul
z1=temp1%256;          // anterior din z1
carry=temp1/256;       //daca exista depasire la adunare, carry se propaga in z2
temp1=z2+temp/256+carry; //rezultatul partial de aici se aduna cu rezultatul
z2=temp1%256;            // anterior din z2
carry=temp1/256;       //daca exista depasire la adunare, carry se propaga in z3
if (carry) z3++;

temp=x1*y0;            //continuarea inmultirii cu octetii z1,z2
temp1=z1+temp%256;
z1=temp1%256;
carry=temp1/256;
temp1=z2+temp/256+carry;
z2=temp1%256;
carry=temp1/256;
if (carry) z3++;

temp=x0*y2;            //un nou rang: octetii z2,z3
temp1=z2+temp%256;
z2=temp1%256;
carry=temp1/256;
temp1=z3+temp/256+carry;
z3=temp1%256;
carry=temp1/256;
if (carry) z4++;

temp=x1*y1;             //continuarea inmultirii cu octetii z2,z3
temp1=z2+temp%256;
z2=temp1%256;
carry=temp1/256;
temp1=z3+temp/256+carry;
z3=temp1%256;
carry=temp1/256;
if (carry) z4++;

temp=x2*y0;             //continuarea inmultirii cu octetii z2,z3
temp1=z2+temp%256;
z2=temp1%256;
carry=temp1/256;
temp1=z3+temp/256+carry;
z3=temp1%256;
carry=temp1/256;
if (carry) z4++;

temp=x1*y2;             //un nou rang: octetii z3,z4
temp1=z3+temp%256;
z3=temp1%256;
carry=temp1/256;
temp1=z4+temp/256+carry;
z4=temp1%256;
carry=temp1/256;
if (carry) z5++;

temp=x2*y1;             //continuarea inmultirii cu octetii z3,z4
temp1=z3+temp%256;
z3=temp1%256;
carry=temp1/256;
temp1=z4+temp/256+carry;
z4=temp1%256;
carry=temp1/256;
if (carry) z5++;

temp=x2*y2;             //ultimul rang: octetii z4,z5
temp1=z4+temp%256;
z4=temp1%256;
carry=temp1/256;
temp1=z5+temp/256+carry;
z5=temp1%256;
carry=temp1/256;
}


//----------------------------------------------------------------------------


void div()
{
/*
     rutina  de  impartire  a  2  intregi  pe  48,  respectiv  24  de biti, cu
rezultatul  pe 24 de biti, construita dupa modelul impartirii pe 32/16 de biti
prezentata in manualul Intel - Embedded Applications
     in: z(0-5),y(0-2) => out: x(0-2),carry
*/

r7=r6=r5=0;             //restul partial este facut zero
t0=t1=t2=t3=t4=t5=0;
r2=y2; r1=y1; r0=y0;    //incarcare impartitor
r4=48;                  //initializare contor (deimpartit pe 48 de biti)
carry=0;

Div_loop:
;
goto Shift_D;   //shift-eaza impartitorul si returneaza MSB in carry

SD:
;
temp=r5; temp<<=1; r5=temp%256+carry; carry=temp/256;  //shift-eaza carry in
temp=r6; temp<<=1; r6=temp%256+carry; carry=temp/256;  //LSB al restului
temp=r7; temp<<=1; r7=temp%256+carry; carry=temp/256;  //partial

if (carry) goto Can_sub;        //test daca r7:r6:r5 >= r2:r1:r0

carry=0;
temp=r7-r2;             //se scade r2 din r7 pentru a se vedea daca r2<r7
if (temp>255) carry=1; else carry=0;  //carry=1 daca r7<r2
if (carry) goto Cant_sub;
//aici r7>=r2
if (temp) goto Can_sub;   //salt daca r7>r2


carry=0;
temp=r6-r1;
if (temp>255) carry=1; else carry=0;  //carry=1 daca r6<r1
if (carry) goto Cant_sub;
if (temp) goto Can_sub;

carry=0;
temp=r5-r0;
if (temp>255) carry=1; else carry=0;  //carry=1 daca r5<r0
if (carry) goto Cant_sub;

Can_sub:        //se scade impartitorul din restul partial, cu propagarea
;               //imprumutului (borrow)
temp=r5-r0; r5=temp%256;
if (temp>255) carry=1; else carry=0;

temp=r6-r1-carry; r6=temp%256;
if (temp>255) carry=1; else carry=0;

temp=r7-r2-carry; r7=temp%256;
carry=1;           //shift-eaza un 1 in cat
goto Quot;

Cant_sub:
;
carry=0;           //shift-eaza un 0 in cat

Quot:              //shift-eaza bitul carry in cat
;
goto Shift_Q;

SQ:
;
r4--;
if (r4) goto Div_loop;  //test daca impartirea s-a terminat
goto End;

Shift_D:
;
//shift-eaza impartitorul un bit la stanga si returneaza MSB in carry
carry=0;
temp=z0; temp<<=1; z0=temp%256+carry; carry=temp/256;
temp=z1; temp<<=1; z1=temp%256+carry; carry=temp/256;
temp=z2; temp<<=1; z2=temp%256+carry; carry=temp/256;
temp=z3; temp<<=1; z3=temp%256+carry; carry=temp/256;
temp=z4; temp<<=1; z4=temp%256+carry; carry=temp/256;
temp=z5; temp<<=1; z5=temp%256+carry; carry=temp/256;
goto SD;

Shift_Q:
;
//shift-eaza catul un bit la stanga si shift-eaza carry in LSB
temp=t0; temp<<=1; t0=temp%256+carry; carry=temp/256;
temp=t1; temp<<=1; t1=temp%256+carry; carry=temp/256;
temp=t2; temp<<=1; t2=temp%256+carry; carry=temp/256;
temp=t3; temp<<=1; t3=temp%256+carry; carry=temp/256;
temp=t4; temp<<=1; t4=temp%256+carry; carry=temp/256;
temp=t5; temp<<=1; t5=temp%256+carry; carry=temp/256;
goto SQ;

End:
;
if (t3) carry=1;
x2=t2; x1=t1; x0=t0;
}

//----------------------------------------------------------------------------


void complem2()
{
/*
     rutina de complementare fata de 2 a unui operand pe 24 de biti
     in: x(0-2) => out: x(0-2)
*/
x2=255-x2;      //not x2 (complementare fata de 1)
x1=255-x1;      //not x1
x0=255-x0;      //not x0
y0=1; y1=y2=0;  //adunare a rezultatului din x cu 1
add();          //pentru obtinerea complementului fata de 2
}

//----------------------------------------------------------------------------


void ShiftL()
{
/*
     rutina de deplasare stanga cu o pozitie a unui operand pe 24 de biti
     in: t(0-2) => out: t(0-2)
*/

carry=0;
temp=t0; temp<<=1; t0=temp%256+carry; carry=temp/256;
temp=t1; temp<<=1; t1=temp%256+carry; carry=temp/256;
temp=t2; temp<<=1; t2=temp%256+carry; carry=temp/256;
}


//----------------------------------------------------------------------------

void ShiftR()
{
/*
     rutina de deplasare dreapta cu o pozitie a unui operand pe 24 de biti
     in: t(0-2) => out: t(0-2)
*/

carry=0;
temp=t2; temp1=temp&1; temp>>=1; t2=temp+carry*128; carry=temp1;
temp=t1; temp1=temp&1; temp>>=1; t1=temp+carry*128; carry=temp1;
temp=t0; temp1=temp&1; temp>>=1; t0=temp+carry*128; carry=temp1;
}

//----------------------------------------------------------------------------


void adunare()
{
/*
     rutina de adunare a 2 numere in virgula mobila, cu mantisa pe 24 de biti,
exponent si semn
     in: a,b[0-2],ea,eb,sa,sb => out: c[0-2],ec,sc
*/

if (ea<eb) goto Sch;
if (ea>eb) goto Cont;

//ea=eb
if (b2>a2) goto Sch;
if (b2<a2) goto Cont;

//b2=a2
if (b1>a1) goto Sch;
if (b1<a1) goto Cont;

//b1=a1
if (b0>a0) goto Sch;
if (b0<a0) goto Cont;

//b0=a0
if (sa==sb) goto Cont;

//c3=c2=c1=c0=ea=0;
return;


Sch:
;     //interschimbare "a" cu "b" pentru ca in "a" sa fie operandul mai mare
   t2=a2; t1=a1; t0=a0; t3=ea; t4=sa;
   a2=b2; a1=b1; a0=b0; ea=eb; sa=sb;
   b2=t2; b1=t1; b0=t0; eb=t3; sb=t4;

Cont:
;

ec=ea; sc=sa;      //exponentul si semnul rezultatului = semnul si rezultatul
                   //operandului mai mare

if (a3 || a2 || a1 || a0)
   a2|=0x80;  //a(0-2) - mantisa cu 1 in MSB

if (b3 || b2 || b1 || b0)
   b2|=0x80;  //b(0-2) - mantisa cu 1 in MSB

while (eb<ea)            //daca exponentii sunt diferiti, se shifteaza dreapta
   {                     //operandul mai mic si i se incrementeaza exponentul
   t2=b2; t1=b1; t0=b0;  //pana exponentii devin egali
   ShiftR();
   b2=t2; b1=t1; b0=t0;
   eb++;
   }

if (sa)   //daca "a" este negativ, se complementeaza fata de 2
   {
   x2=a2; x1=a1; x0=a0;
   complem2();
   a2=x2; a1=x1; a0=x0;
   }

if (sb)  //daca "b" este negativ, se complementeaza fata de 2
   {
   x2=b2; x1=b1; x0=b0;
   complem2();
   b2=x2; b1=x1; b0=x0;
   }

x2=a2; x1=a1; x0=a0;
y2=b2; y1=b1; y0=b0;
add();                 //se aduna mantisele
c2=x2; c1=x1; c0=x0;   //rezultatul este depus in "c"

r1=carry;              //se salveaza carry rezultat in r1

if (sc)                //daca "c" este negativ, se complementeaza fata de 2
   {
   x2=c2; x1=c1; x0=c0;
   complem2();
   c2=x2; c1=x1; c0=x0;
   r1=1-r1;            //se complementeaza si carry
   }

if (sa!=sb) r1=0;

if (r1)         //daca s-a produs depasire, se shift-eaza "c" dreapta si i se
   {            //incrementeaza exponentul
   t2=c2; t1=c1; t0=c0;
   ShiftR();
   c2=t2; c1=t1; c0=t0;
   ec++;
   c2|=128;     //se seteaza MSB
   }


if (!c2 && !c1 && !c0) goto End_adun;

while (c2<128)         //se normalizeaza rezultatul
      {
      t2=c2; t1=c1; t0=c0;
      ShiftL();
      c2=t2; c1=t1; c0=t0;
      ec--;
      }


End_adun:
;
return;
}


//----------------------------------------------------------------------------


void scadere()
{
/*
     rutina de scadere a 2 numere in virgula mobila, cu mantisa pe 24 de biti,
exponent si semn
     in: a,b[0-2],ea,eb,sa,sb => out: c[0-2],ec,sc
*/

sb=1-sb;         //se schimba semnul lui "b" si se opereaza adunarea
adunare();
}


//----------------------------------------------------------------------------


void inmultire()
{
/*
     rutina  de  inmultire  a  2 numere in virgula mobila, cu mantisa pe 24 de
biti, exponent si semn
     in: a,b[0-2],ea,eb,sa,sb => out: c[0-2],ec,sc
*/

sc=sa^sb;       //semnul rezultatului este un XOR intre semnele operanzilor
temp=ea+eb;

if (temp>380)   //se testeaza depasirile in functie de exponenti
   {
   printf("Depasire plus\n");
   ec=0xff;
   return;
   }
if (temp<128)
   {
   printf("Depasire minus\n");
   return;
   }

if (a3 || a2 || a1 || a0)
   a2|=0x80;  //a(0-2) - mantisa cu 1 in MSB
else
    return;

if (b3 || b2 || b1 || b0)
   b2|=0x80;  //b(0-2) - mantisa cu 1 in MSB
else
    return;

x2=a2; x1=a1; x0=a0;
y2=b2; y1=b1; y0=b0;
mul();                //se efectueaza inmultirea mantiselor
c2=z5; c1=z4; c0=z3;  //se salveaza rezultatul in "c" - se retin cei 3 octeti
                      //mai semnificativi
x2=0; x1=0; x0=ea;
y2=0; y1=0; y0=eb;
add();                //se aduna exponentii
y2=0; y1=0; y0=-127;
add();       //se aduce rezultatul la forma IEEE - se scade 127 din exponent
ec=x0+1;

if (c2<128)  //se normalizeaza rezultatul
   {
   t2=c2; t1=c1; t0=c0;
   ShiftL();
   c2=t2; c1=t1; c0=t0;
   ec--;
   }
}


//----------------------------------------------------------------------------



void impartire()
{
/*
     rutina  de  impartire  a  2 numere in virgula mobila, cu mantisa pe 24 de
biti, exponent si semn
     in: a,b[0-2],ea,eb,sa,sb => out: c[0-2],ec,sc
*/

int dif;
sc=sa^sb;   //semnul rezultatului este un XOR intre semnele operanzilor

if (!b3 && !b2 && !b1 && !b0)
   {
   if (!a3 && !a2 && !a1 && !a0)        //impartire 0/0
       {
       printf("Forma fara sens\n");
       ec=0xff;
       c2=1;                            //rezultat "not a number"
       }
   else    //impartire x/0
       {
       printf("Impartire la 0\n");
       ec=0xff;                         //rezultat "+INF" sau "-INF"
       }
   return;
   }
if (!a3 && !a2 && !a1 && !a0)           //impartire 0/x => rezultat 0
   return;
dif=eb-ea;
if (dif>127)           //se testeaza depasirile in functie de exponenti
   {
   printf("Depasire minus\n");
   return;
   }
dif=ea-eb;
if (dif>127)
   {
   printf("Depasire plus\n");
   ec=0xff;
   return;
   }

if (a3 || a2 || a1 || a0)
   a2|=0x80;  //a(0-2) - mantisa cu 1 in MSB

if (b3 || b2 || b1 || b0)
   b2|=0x80;  //b(0-2) - mantisa cu 1 in MSB


z5=a2; z4=a1; z3=a0; z2=0; z1=0; z0=0;  //se completeaza cei 3 octeti
y2=b2; y1=b1; y0=b0;                    //mai putin semnificativi cu 0
div();                                  //se impart mantisele
r1=carry;                               //se salveaza carry in r1
c2=x2; c1=x1; c0=x0;              //se salveaza rezultatul impartirii in "c"

x2=0; x1=0; x0=ea;
y2=0; y1=0; y0=-eb;
add();                            //se scad exponentii

y2=0; y1=0; y0=127; //+127
add();                            //in IEEE exponentii sunt in functie de 127

ec=x0-1;

if (r1)                           //se normalizeaza rezultatul
   {
   t2=c2; t1=c1; t0=c0;
   ShiftR();
   c2=t2; c1=t1; c0=t0;
   ec++;
   }
}


//----------------------------------------------------------------------------



void main()
{
/*
     secventa de test
*/

printf("A="); scanf("%f",&a);          //se citesc cei 2 operanzi - tip float
printf("B="); scanf("%f",&b);
printf("Operatia: "); scanf("%d",&op); //se citeste operatia: 1+ 2- 3* 4/

pa=(unsigned char *)&a;         //adresele celor 2 operanzi float (a si b)
pb=(unsigned char *)&b;

a0=pa[0]; a1=pa[1]; a2=pa[2]; a3=pa[3];  //se trec in a,b(0-3) cei 4 octeti
b0=pb[0]; b1=pb[1]; b2=pb[2]; b3=pb[3];  //pe care se reprezinta un float


if (a3>=128) sa=1; else sa=0;     //se converteste reprezentarea IEEE float
if (b3>=128) sb=1; else sb=0;     //intr-o reprezentare mantisa-exp-semn
                                  //sa reprezinta semnul lui a (0+ 1-)
a3<<=1; if (a2>=128) a3++; ea=a3; //a(0-2) reprezinta mantisa ea-exponentul
b3<<=1; if (b2>=128) b3++; eb=b3; //analog b


c3=c2=c1=c0=ec=sc=0;            //se initializeaza rezultatul cu 0

switch (op)                     //se efectueaza operatia dorita
       {
       case 1: printf("Adunare\n");
               adunare();
               break;
       case 2: printf("Scadere\n");
               scadere();
               break;
       case 3: printf("Inmultire\n");
               inmultire();
               break;
       case 4: printf("Impartire\n");
               impartire();
               break;
       }


carry=ec&1;               //se converteste reprezentarea mantisa-exp-semn
c3=ec/2;                  //in reprezentarea standard IEEE float

if (carry) c2|=128; else c2&=127;
c3=sc*128+c3;

pa[0]=c0; pa[1]=c1; pa[2]=c2; pa[3]=c3; //se trec in "a" cei 4 octeti-rezultat

printf("Rezultat: %f",a);               //se afiseaza rezultatul
}



--------------------------------------------------------------------------------
                                  Concluzii
--------------------------------------------------------------------------------

     Rutinele   prezentate   pot  fi  utilizate  in  orice  situatie  in  care
proiectantul  nu  dispune  de  rutine floating-point predefinite. Fiind scrise
intr-un  limbaj  de nivel inalt (C), rutinele sunt independente de sistemul de
operare,  putand  fi  folosite  pe  platformele care dispun de un compilator C
(SBC, DOS, Windows, Unix).
     De  asemenea,  functiile  urmaresc  indeaproape  reprezentarea  interna a
datelor  si  simplitatea instructiunile masina, deci pot constitui un punct de
plecare pentru implementarea rutinelor in limbaj de asamblare.

     Referinte:
        www.psc.edu/general/software/packages/ieee/ieee.html
        www.cs.uaf.edu/~cs301/notes/Chapter6/
        Manualul Intel - Embedded Applications
