|
particularitati si exceptii.Implementarea lor pentru algoritmi numerici
|
səhifə | 9/10 | tarix | 16.12.2017 | ölçüsü | 1,03 Mb. | | #35021 |
| particularitati si exceptii.Implementarea lor pentru algoritmi numerici
a ridicat numeroase probleme de ordin tehnic sau conceptual (sunt celebre
dificultatile intampinate de misiunea Apollo 13,calculul orbitelor pla-
netare,calculul numarului PI etc.).Acest manual,nu are decat pretentia
unui abecedar si se va rezuma doar la cateva exemple simpliste,elementare,
care vor ilustra cat mai clar cu putinta modul concret de implementare,
pentru instructiunile 8087,in mediul de programare Borland Pascal 7.0,cu
ajutorul limbajului assembler integrat in program.
Instructiunile 8087 vor fi prezentate succint,in grupuri,ordonate
in functie de principala operatie executata.Pentru transferul numerelor
reale,se pot utiliza urmatoarele instructiuni:
FLD mem -Introduce mem in ST (mem =4,8 sau 10 bytes)
FLD ST(nr) -Introduce o copie a ST(nr) in ST
FST mem -Copiaza ST in mem
FST ST(nr) -Copiaza ST in registrul specificat
FSTP mem -Extrage o copie a lui mem din ST
FSTP ST(nr) -Extrage ST din registrul specificat,care este inlocuit
FXCH [[ST(nr)]] -Schimba ST cu ST(nr)
FXCH -Schimba ST(0) cu ST(1)
Pentru adunare simpla se pot utiliza urmatoarele instructiuni:
FADD -Aduna ST si ST(1).Rezultatul in ST.Distruge operanzii.
FADD ST(nr),ST -Aduna cei doi registri.Inlocuieste ST(nr) cu rezultatul.
FADD ST,ST(nr) -Aduna cei doi registri.Inlocuieste ST cu rezultatul.
FADD mem -Adauga mem la ST.Inlocuieste ST cu rezultatul.
FIADD mem -Adauga un intreg din mem la ST.Rezultatul in ST.
FADDP ST(nr) -Aduna ST+ST(nr).Rezultat in ST(nr).Distruge operamzii.
Cea mai simpla adunare se poate efectua astfel:
EXEMPLU: program assmb84;
{$N+}
uses WinCRT;
var n1,n2,n3:double;
begin
n1:=73.1517;
n2:=11.6539;
asm
FLD n1
FADD n2
FST n3
end;
writeln(n1:2:4,' + ',n2:2:4,' = ',n3:2:4);
end.
Pentru emularea 8087 am utilizat directiva de precompilare $N+,iar pentru
numere am utilizat formatul double (real este pe 6 biti=nereprezentabil).
-77-
Procesorul 8087 accepta urmatoarele tipuri de data:
1 Real (32 de biti = 4 bytes)
2 Long real (64 biti = 8 bytes )
3 Temporary Real (80 biti = 10 bytes)
4 Integer word (16 biti = 2 bytes)
5 Integer (32 biti = 4 bytes)
6 Long integer (64 de biti = 8 bytes)
7 Packed BCD Integer (80 biti -16 digits + sign = 10 bytes)
Pentru mediul de operare Pascal,acestor tipuri de data le corespund:
1 single (7-8 digits 32 biti = 4 bytes)
2 double (15-16 digits 64 biti = 8 bytes)
3 extended (19-20 digits 80 biti = 10 bytes)
4 comp (10-20 digits 64 biti = 8 bytes)
5 integer ( 16 biti = 2 bytes)
6 longint ( 32 biti = 4 bytes)
7 word ( 16 biti = 2 bytes)
Nu toate instructiunile accepta toate tipurile de data.De exemplu,tipul
de data real din Pascal are un format de 6 bytes si nu poate fi incarcat
in ST prin nici una dintre instructiunile de transfer (chiar daca in
registri exista suficient loc pentru acest tip de data.
In exercitiul precedent am transferat in ST prima valoare,la care am
adaugat valoarea din cea de a doua variabila de memorie prin instructiunea
FADD mem.O alta modalitate de a aduna doua numere reale se poate realiza
incarcand cele doua numere in ST si respectiv ST(1) dupa care se va face
adunarea celor doi registri prin instructiunea FADD:
EXEMPLU: program assmb85;
{$N+}
uses WinCRT;
var n1,n2,n3:double;
begin
n1:=123.4567;
n2:=543.8732;
asm
FLD n2
FST ST(1)
FLD n1
FADD
FST n3
end;
writeln(n1:3:4,' + ',n2:3:4,' = ',n3:3:4);
end.
in exemplul de mai sus,am transferat n2 in ST,apoi am copiat registrul ST
in ST(1),dupa care am transferat n1 in ST si am adunat cei doi registri.
Am preluat rezultatul din ST (cei doi operanzi sunt distrusi automat).
Pentru a transfera datele din ST in ST(1),nu este neaparat necesar sa
apelam instructiunea FST ST(nr).Registrii ST actioneaza sub forma de stiva
conform principiului LIFO (LAST IN FIRST OUT).Astfel este suficient sa
transferam o noua valoare in registrul ST,pentru ca valoarea initiala din
registrul ST sa avanseze in registrul ST(1).Daca transferam o noua
valoare in ST,valoarea din ST(1) avanseaza in ST(2),pentru a face loc
celei din ST(0),care avanseaza in ST(1) pentru a face loc noii valori:
-78-
EXEMPLU: program assmb86;
{$N+}
uses WinCRT;
var n1,n2,n3,n4:double;
begin
n1:=1315.1715;
n2:=3375.3792;
n3:=2277.5533;
asm
FLD n1
FLD n2
FLD n3
FXCH ST(2)
FST n4
end;
writeln('ST(0) contine valoarea: ',n4:4:4);
end;
La prima instructiune FLD valoarea n1 este transferata in ST(0).La cea
de a doua instructiune FLD valoarea n1 avanseaza in ST(1) iar la cea de
a treia instructiune FLD,n1 avanseaza in registrul ST(2).Apoi prin in-
structiunea FXCH ST(2) se inlocuieste valoarea din ST(0) cu cea din
registrul ST(2).In final,FST copiaza ST in variabila n4.
Astfel,daca dorim ca variabilele sa fie stocate in ordine crescatoare,
ele trebuiesc transferate in ST in ordine inversa (de la coada la cap).
EXEMPLU: program assmb87;
{$N+}
uses WinCRT;
var n1,n2,n3,n4:double;
begin
n1:=1111.1111;
n2:=2222.2222;
n3:=3333.3333;
asm
FLD n3
FLD n2
FLD n1
FADD ST,ST(2)
FST n4
end;
writeln(n3:4:4,' + ',n1:4:4,' = ',n4:4:4);
end.
In acest mod,variabilele transferate in registri vor fi amplasate in
ordinea crescatoare: n1 in ST,n2 in ST(1) si n3 in ST(2).Acest mod
de incarcare a stivei poate fi util pentru o evidenta mai simpla a
pozitiei fiecarei variabile in stiva.In exemplul de mai sus,se vor
putea efectua facil oricare dintre operatiile n1+n3 sau n1+n2,dar va
fi mai complicat de realizat operatia n2+n3.
Adunarea dintre doua valori se poate face si utilizand numere repre-
zentate in formate diferite,cu conditia sa se apeleze instructiunea co-
respunzatoare.Pentru a aduna un numar intreg la un numar real exista
instructiunea FIADD mem:
-79-
EXEMPLU: program assmb88;
{$N+}
uses WinCRT;
var n1,n3:double;
n2:longint;
begin
n1:=3355.7713;
n2:=123456;
asm
FLD n1
FIADD n2
FST n3
end;
writeln(n1:4:4,' + ',n2,' = ',n3:4:4);
end.
Pentru ca scrierea si/sau citirea unui program sa se desfasoare cat mai
simplu,este bine sa aveti o plansa cu toate instructiunile grupate in
functie de operatia principala.Daca este necesar,adaugati cate un comen-
tariu dupa fiecare operatie efectuata,sau cel putin in punctele in care
intervin modificari greu de observat la prima vedere.
Instructiunile 8087 se pot grupa in patru seturi principale:
1 Setul CORE -contine instructiunile de transfer si cele pentru operatiile
aritmetice simple:adunare,scadere,inmultire,impartire
2 Setul EXTENDED -contine instructiunile de transfer a formatelor speciale
3 Setul SPECIAL FUNCTION-contine instructiunile de extragere a radacinii
patrate si suportul pentru functiile transcedentale
4 Setul ADMINISTRATIVE -contine instructiunile pentru modificarea context-
ului si cele pentru controlul procesorului
Pentru transferul numerelor intregi simple exista urmatoarele instructiuni
FILD mem -Introduce o copie a mem in ST mem = 2,4,8 sau 10 bytes
FIST mem -Copiaza ST in mem mem = 2 sau 4 bytes
FISTP mem -Extrage ST din mem mem = 2,4 sau 8 bytes
Pentru transferul numerelor BCD impachetate se folosesc instructiunile:
FBLD mem -Indroduce o copie a mem in ST (10 bytes)
FBSTP mem -Introduce ST in mem (10 bytes)
Exista si o serie de instructiuni speciale,care transfera in registrul
ST cateva constante utile,cum ar fi zero,unu,PI,log 2e,log 10 2,log e 2:
FLDZ -Introduce 0 in ST
FLD1 -Introduce 1 in ST
FLDPI -Introduce PI in ST
FLDL2E -introduce valoarea lui log2 e in ST
FLDL2T -introduce valoarea lui log2 10 in ST
FLDLG2 -introduce valoarea lui log10 2 in ST
FLDLN2 -introduce valoarea lui loge 2 in ST
Transferul direct al constantelor simplifica operatiile curente prin
eliminarea unor etape intermediare,pentru calculul suprafetelor circulare
si pentru calculul logaritmic.
-80-
EXEMPLU: program assmb89;
{$N+}
uses WinCRT;
var n1:double;
n2:longint;
begin
n2:=12300;
asm
FILD n2
FLDPI
FADD
FST n1
FISTP n2
end;
writeln('12300 + PI = ',n1:4:12);
writeln('Valoarea intreaga este: ',n2);
end.
Pentru scadere simpla se pot utiliza urmatoarele instructiuni:
FSUB -Scade ST din ST(1) si extrage rezultatul in ST
FSUB ST(nr),ST -Scade ST din ST(nr) si inlocuieste ST(nr) cu rezultatul
FSUB ST,ST(nr) -Scade ST(nr) din ST si inlocuieste ST cu rezultatul
FSUB mem -Scade mem din ST si inlocuieste ST cu rezultatul
FISUB mem -Scade numarul intreg mem din ST.Rezultatul in ST.
FSUBP ST(nr),ST -Scade ST din ST(nr).Distruge operanzii.Rezultat in ST(nr)
EXEMPLU: program assmb90;
{$N+}
uses WinCRT;
var n1:double;
begin
n1:=1.3333;
asm
FLDL2T
FSUB n1
FST n1
end;
writeln('Log2 10 - 1.3333 = ',n1:2:8);
end.
In exercitiul de mai sus,am incarcat constanta cu ajutorul instructiunii
FLDL2T,dupa care am scazut din ST valoarea variabilei de memorie.Este
cel mai simplu algoritm pentru o operatie de scadere simpla.Pentru
instructiunile cu doi operanzi,trebuie transferata cate o valoare atat
in ST cat si in ST(1),dupa care se efectueaza operatia de scadere propriu
zisa.Atentie la ordinea in care se efectueaza transferul datelor in stiva
(principiul LIFO).O eroare foarte frecventa apare atunci cand se utili-
zeaza un algoritm cu mai multe operatii succesive.In acest caz,trebuie
tinut cont de faptul ca dupa o operatie de scadere,rezultatul ramane in
ST (sau in ST(1) ) si la un nou transfer de data avanseaza in registrul
urmator.Daca se introduc prea multe date succesiv,se depaseste stiva si
se va returna un mesaj de eroare in executie (run time error).
-81-
Pentru numere intregi se poate utiliza un exercitiu de genul:
EXEMPLU: program assmb91;
{$N+}
var n1,n2,n3:longint;
begin
n1:=55577715;
n2:=33312341;
asm
FILD n2
FILD n1
FSUB ST,ST(1)
FISTP n3
end;
writeln(' 55577715 - 33312341 = ',n3);
end.
Pentru scaderea inversa se pot utiliza urmatoarele operatii:
FSUBR -Scade ST(1) din ST.Distruge operanzii.Rezultat in ST.
FSUBR ST(nr),ST -Scade ST(nr) din ST.Inlocuieste ST(nr) cu rezultatul.
FSUBR ST,ST(nr) -Scade ST din ST(nr).Inlocuieste ST cu rezultatul.
FSUBR mem -Scade ST din mem.Inlocuieste ST cu rezultatul.
FISUBR mem -Scade ST din numarul intreg mem.Rezultatul in ST.
FSUBRP ST(nr),ST-Scade ST(nr) din ST.Rezultat in ST(nr).Distruge operanzii
EXEMPLU: program assmb92;
{$N+}
uses WinCRT;
var n1,n2,n3,n4:double;
begin
n1:=11111.33333;
n2:=777.55555;
asm
FLD n1
FLD n2
FSUB
FST n3
FLDZ
FLDZ
FLD n1
FLD n2
FSUBR
FST n4
end;
writeln('FSUB: ',n1:5:5,' - ',n2:5:5,' = ',n3:5:5);
writeln('FSUBR: ',n2:5:5,' - ',n1:5:5,' = ',n4:5:5);
end.
Se observa usor ca scaderea inversa este identica cu cea simpla,dar se
inverseaza operanzii (descazutul devine scazator iar scazatorul devine
descazut).Pentru a evita coruperea registrilor am transferat de doua ori
valoarea zero,inainte de a reincarca valorile.Acest gen de artificiu nu
se poate repeta prea des,deoarece se supraincarca stiva in mod inutil.
-82-
Pentru inmultirea numerelor reale,se pot utiliza urmatoarele instructiuni:
FMUL -Inmulteste ST cu ST(1).Rezultat in ST.Operanzii distrusi.
FMUL ST(nr),ST -Inmulteste ST(nr) cu ST.Rezultatul in ST(nr).
FMUL ST,ST(nr) -Inmuulteste ST cu ST(nr).Rezultatul in ST.
FMUL mem -Inmulteste ST cu variabila mem.Rezultatul in ST.
FIMUL mem -Inmulteste ST cu numarul intreg mem.Rezultatul in ST.
FIMULP ST(nr),ST -Inmulteste valorile si extrage rezultatul in ST.
EXEMPLU: program assmb93;
{$N+}
uses WinCRT;
var a,b,c:double;
begin
a:=1713.1539;
b:=5.1423;
asm
FLD a
FMUL b
FST c
end;
writeln('1713,1359 x 5,1423 = ',c:5:6);
end.
Sau,pentru a calcula aria unui cerc:
EXEMPLU: program assmb94;
{$N+}
uses WinCRT;
var a,b,c:double;
begin
writeln('Introduceti raza cercului: ');
read(a);
asm
FLD a
FMUL a
FLDPI
FMUL ST,ST(1)
FST c
end;
writeln('Aria cercului este: ',c:8:8);
end.
In mod similar se pot construi diverse functii.Eventual incercati
sa grupati diverse functii programate in assembler,sub forma unei unitati
sau a unei biblioteci DLL.
Pentru impartire,se pot utiliza urmatoarele instructiuni:
FDIV -Imparte ST(1) la ST.Rezultatul in ST.Distrige operanzii.
FDIV ST(nr),ST -Imparte ST(nr) la ST.Rezultatul in ST(nr).
FDIV ST,ST(nr) -Imparte ST la ST(nr).Rezultatul in ST.
FDIV mem -Imparte ST la variabila mem.Rezultatul in ST.
FIDIV mem -Imparte ST la numarul intreg mem.Rezultatul in ST.
FDIVP ST(nr),ST -Imparte ST(nr) la ST.Rezultatul in ST(nr).Ambii operanzi
sunt distrusi.
-83-
EXEMPLU: program assmb95;
{$N+}
uses WinCRT;
var a,b:double;
begin
writeln('Introduceti valoarea dorita: ';
read(a);
asm
FLD a
FLDPI
FDIV ST(1),ST
FXCH
FST b
end;
writeln(a:5:5,' impasrtit la 3.14...=',b:5:5);
end.
Pentru impartire inversa,se pot utiliza urmatoarele instructiuni:
FDIVR -Imparte ST la ST(1).Rezultatul in ST.Operanzii distrusi.
FDIVR ST(nr),ST -Imparte ST la ST(nr).Rezultatul in ST(nr).
FDIVR ST,ST(nr) -Imparte ST(nr) la ST.Rezultatul in ST.
FDIVR mem -Imparte variabila mem la ST.rezultatul in ST.
FIDIVR mem -Imparte numarul intreg mem la ST.Rezultatul in ST.
FIDIVRP ST(nr),ST-Imparte ST la ST(nr).Rezultatul in ST(nr).
EXEMPLU: program assmb96;
{$N+}
uses WinCRT;
var a,b,c,d:double;
begin
writeln('Introduceti primul numar: ');
read(a);
writeln('Introduceti al doilea numar: ');
read(b);
asm
FLD b
FLD a
FDIVR
FST c
FLDZ
FLD a
FLD b
FDIVR
FST d
end;
if c > d then
writeln('primul numar este mai mare !');
if c < d then
writeln('al doilea numar este mai mare !');
if c = d then
writeln('cele doua numere sunt egale !');
end.
-84-
In exercitiul anterior,puteti verifica precizia introducand progresiv
numere care difera prin zecimala a 4-a pana la a 10-a zecimala.
Alte operatii sunt implementate prin instructiunile:
FABS -Semnul valorii din ST devine pozitiv (valoarea absoluta)
FCHS -Inverseaza semnul din ST (+ in - sau - in +)
FRNDINT -Rotunjeste valoarea din ST la un numar intreg
FSQRT -Inlocuieste ST prin radacina sa patrata (radical din valoare)
FSCALE -Factorizeaza puterile lui 2,adaugand valoarea din ST(1) la
exponentul valorii din ST.Astfel multiplica valoarea din
varful stivei cu 2 la puterea ST(1).
FPREM -Calculeaza restul efectuand o impartire modul.Valoarea ST este
impartita cu valoarea din ST(1).Restul inlocuieste ST.Valoarea
din ST(1) ramane neschimbata.
EXEMPLU: program assmb97;
{$N+}
uses WinCRT;
var a,b:double;
begin
a:=33.17;
asm
FLDPI
FLD a
FSQRT
FPREM
FST b
end;
writeln('Restul impartirii SQRT(33.17)/PI este: ',b:6:6);
end;
Sau pentru a extrage valoarea intreaga absoluta:
EXEMPLU: program assmb98;
{$N+}
uses WinCRT;
var a,b:double;
begin
a:=-357.12345;
asm
FLD a
FABS
FRNDINT
FST b
end;
writeln('Valoarea intreaga absoluta este: ',b:6:0);
end.
Incercati sa scrieti exercitiile sub forma de functii,care sa returneze
valoarea absoluta,valoarea intreaga si respectiv radacina patrata din
orice valoare introdusa de la tastatura.Daca aveti deja o biblioteca de
functii proprii,includeti si aceste functii.Da nu,incercati sa scrieti
cateva functii proprii (utile) si apoi incercati sa formati o unitate
sau o biblioteca DLL.Principalul avantaj oferit de invatarea acestui
limbaj il reprezinta tocmai aceasta abilitate de a formula functii si
proceduri noi,diferite de cele din unitatile standard.
-85-
8087 include si urmatoarele instructiuni transcendente:
F2XM1 -Calculeaza 2 la puterea x - 1 unde x este valoarea din varful
stivei ST(0),cuprinsa intre 0 si 0.5 (inclusiv).Rezultat in ST.
FYL2X -Calculeaza de y ori logaritm in baza 2 din x,unde x este in
ST iar y este valoarea din ST(1).Rezultratul in ST.Distruge
operanzii.
FYL2XP1 -Calculeaza de y ori log2 (x+1) unde x este in ST si y in ST(1).
Rezultatul in ST.
FPTAN -Calculeaza tangenta valorii din ST prin raportul y/x,unde y
este valoarea din ST iar x este valoarea din ST(1).Apoi impinge
Dostları ilə paylaş: |
|
|