Programarea calculatoarelor 2 - Laborator 4

Obiective: Lucrul cu operatori pe biți; efectuarea de calcule matematice.
Se va rezolva câte o problemă din setul 1 și 2. Problemele (b) sunt ceva mai dificile, dar mai instructive.

Problema 1a Calculați rădăcina ecuației f(x) = 0 cu o precizie dată, prin metoda înjumătățirii intervalului, când f este o funcție continuă și monotonă pe un interval pe care schimbă semnul. Exemplu: f(x) = e^x + x^2 - 5 pe intervalul [1, 2], cu o precizie de 10^-5.
Indicație: dacă f(x1) < 0 și f(x2) > 0, calculați valoarea lui f în mijlocul intervalului [x1, x2] și continuați cu subintervalul pe care f schimbă semnul, până la precizia dorită. Se pot folosi funcțiile standard declarate în math.h, de exemplu exp.

Problema 1b În matematică, se dorește adesea aproximarea cât mai precisă a unui număr real cu unul rațional. Din antichitate se știa că pi ~= 22/7, cu o precizie de 1 la mie. O astfel de aproximare se poate face cu fracții continue: un număr 0 < x < 1 se poate aproxima succesiv cu 1 / a1, 1 / (a1 + 1 / a2), 1 / (a1 + 1 / (a2 + 1 / a3)), unde a1, a2, a3, ... sunt numere naturale. Dacă în aproximarea inițială, a1 este parte întreagă din 1/x, și se continuă folosind aceeași regulă (pentru partea fracționară a numitorului aproximat cu a1, etc.), se obține o secvență de numere raționale p0/q0, p1/q1, p2/q2 ... care și îl aproximează pe x din ce în ce mai bine, alternativ din ambele părți și satisfac următoarea recurență:
p_n+1 = a_n+1 * p_n + p_n-1 pentru n >= 0, cu p_-1 = 1, p_0 = 0
q_n+1 = a_n+1 * q_n + q_n-1 pentru n >= 0, cu q_-1 = 0, q_0 = 1
Să se scrie un program care, pentru un număr real între 0 și 1 calculează cea mai bună aproximație în fracție continuă pentru care numitorul nu depășește o valoare dată. Opțional, verificați că nici o fracție cu numitorul mai mic nu este o aproximație mai bună (o proprietate matematică cunoscută și demonstrată).
Indicații: La fiecare pas rămâne de aproximat sub forma 1 / a_n un nou număr fracționar între 0 și 1. Determinați întâi relația care leagă acest număr de valoarea anterioară. Pentru partea întreagă, puteți folosi funcțiile floor sau trunc declarate în math.h (pentru numere pozitive, ele dau același rezultat).

Problema 2a Scrieți un program care calculează o sumă de control pe 16 biți pentru o linie de text citită de la intrare, în felul următor: octetul inferior se obține prin SAU exclusiv din toate caracterele de pe poziții pare (începând cu 0), iar octetul superior prin SAU exclusiv din toate caracterele de pe poziții impare în text. Rezolvați problema prelucrând pe rând fiecare caracter, fără a folosi tablouri.

Problema 2b Scrieți un program care calculează o sumă de control CRC (cyclic redundancy check) pentru un text, conform standardului POSIX.
Fundamentul matematic este următorul: textul e asimilat unui șir de L biți, pentru care se calculează o sumă de control pe W biți. Orice șir de n biți poate fi asociat cu un polinom de grad < n, în care bitul k este coeficientul lui x la puterea k. Se ia textul, privit ca un astfel de polinom, și se calculează restul împărțirii la un polinom prestabilit de grad W, considerând toți coeficienții modulo 2. De exemplu, pentru textul pe L=8 biti 10011100, adică x^7 + x^4 + x^3 + x^2 și polinomul x^4 + x^3 + x^0 (11001, de grad W=4) obținem:
x^7 + x^4 + x^3 + x^2 = (x^3 + x^2 + x^1)*(x^4 + x^3 + x^0) + x^1 (mod 2)
deci restul x^1 interpretat pe W=4 biți este 0010. Împărțirea poate fi implementată prin algoritmul clasic cu deplasare și scădere succesivă. Exprimând totul în calcule pe biți, avem nevoie de o valoare pe W biți în care ținem minte restul curent. Scăderea pentru polinoame modulo 2 (identică cu adunarea) se face prin SAU exclusiv bit cu bit (nu există deplasare, fiecare bit corespunde unui coeficient separat). Dacă bitul superior (poziția W-1) este 1, atunci în iterația curentă, după deplasarea la stânga și aducerea următoarei cifre din deîmpărțit, bitul W va fi 1 și împărțitorul (de grad W) va "intra" în rest (poate fi "scăzut" prin XOR, coeficientul în cât este 1). Dacă nu, se continuă fără scădere cu următoarea iterație (cifra din cât este 0). Cum ne interesează doar restul, nu trebuie să reținem câtul; calculul se încheie când au fost consumați toți biții din deîmpărțit (textul dat).
În cazul particular al standardului POSIX, suma de control se calculează pe 32 de biți, iar polinomul de grad 32 folosit ca împărțitor are următorii biți pe 1 (coeficienți): 32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0. (Asemenea polinoame se aleg pentru proprietățile bune de detectare a erorilor). Șirul de biți codificat e format din caracterele textului, în ordine, fiecare începând cu bitul cel mai semnificativ; apoi lungimea textului, în caractere, pe numărul minim necesar de octeți, începând cu cel mai puțin semnificativ; apoi 32 de biți 0 (4 caractere nule). Suma de control e restul pe 32 de biți, negat bit cu bit (pentru că, adăugată la mesaj, permite verificarea faptului că același algoritm ar trebui să dea restul 0).
Indicații: Din descrierea algoritmului, rezultă că vom manipula un număr pe 32 de biți (restul curent), de exemplu un long. Testul valorii 1 pentru bitul cel mai semnificativ trebuie făcut înainte de deplasarea la stânga, care va provoca dispariția lui. Din același motiv, nu vom reprezenta bitul 32 al împărțitorului, calculele descrise ținând cont implicit că acesta e 1. Împărțirea poate fi făcută pas cu pas, pe măsură ce se citesc caractere din text, însă nu poate începe până când în deîmpărțitul inițial nu s-au acumulat 32 de biți (4 caractere), și e disponibil încă un caracter din care șă se "aducă" biții următori. La sfârșitul textului, se continuă algoritmul cu octeții reprezentând lungimea textului, și cei 4 octeți finali de zero (care ne asigură că deîmpărțitul va avea >= 32 de biți chiar dacă textul e mai scurt).
Textul poate fi citit la alegere, fie până la linie nouă, fie până la sfârșit de fișier, cu un ciclu de tipul

 while ((c = getchar()) != EOF) { /* prelucreazâ c */ }
unde c e declarat ca int. Rezultatul poate fi verificat prin comparație cu programul UNIX cksum.
Marius Minea
Last modified: Wed Oct 22 13:36:39 EEST 2003