Atenţie! Aceasta este o versiune veche a paginii, scrisă la 2008-03-15 18:21:31.
Revizia anterioară   Revizia următoare  

Coduri Gray

(Categoria Matematica, autor Cosmin Negruseri)

Introducere

Acest articol prezinta notiunea de Cod Gray si unele aplicatii ale lui in probleme de la concursurile de programare.
Un cod Gray de ordin n este un sir care contine toate numerele de la 0 la 2^{n-1}, astfel ca oricare doua numere consecutive din sir difera in reprezentarea binara prin exact un bit. Pentru n >= 2 exista mai multe coduri Gray distincte. Un cod mai des intalnit, numit in engleza binary reflected Gray code (in continuare cand vom vorbi despre codul Gray ne vom referi de fapt la acest cod). Modul de constructie al acestui cod este unul intuitiv: la fiecare pas adaugam numarul adaugat anterior, caruia ii modificam cel mai putin semnificativ bit, astfel ca numarul obtinut sa nu mai fi fost adaugat inainte la şir. De exemplu, dacă ordinul este doi si avem la inceput numarul 0 in sir, vom adauga 1, apoi 3, iar apoi 4.
In acest articol vom nota acest cod cu G_{n}. O alta metoda de constructie care obtine acelasi cod Gray este de a determina mai intai pe G_{n-1}, apoi daca notam cu G'_{n-1} sirul G_{n-1} inversat, atunci obtinem pe G_{n} daca punem cate un bit de 0 in fata fiecarui numar din G_{n-1}, iar acestea sunt urmate de numerele din G'_{n-1} carora le adaugam cate un bit de 1 ca bit semnificativ ( pe scurt G_{n} = 0G_{n-1},1G'_{n-1} (1) ). Observam ca acest cod este unul circular, adica ultimul numar si primul numar din cod difera prin exact un bit. Observam de asemenea ca fiecare cod de ordin n il contine pe cel de n-1 ca prefix, deci am putea nota prin G_{\infty} sirul numerelor naturale in care orice doua numere consecutive difera in reprezentarea binara prin exact un bit si pentru care sirul primelor 2^{n} elemente coincide cu G_{n}, oricare ar fi acest n un numar natural.
Fie g(x) al x-lea numar din G_{\infty} (prin g(x) notam codul Gray al numarului x) si g(y)-1 la ce pozitie apare numarul y in sirul G_{\infty}. Ne punem problema calcularii eficiente a celor doua functii. Se poate demonstra prin inductie ca daca avem un numar x cu reprezentarea binara (... a_{2} a_{1} a_{0})_{2} si codul lui Gray, cu reprezentarea binara (... b_{2} b_{1} b_{0})_{2}, atunci avem b_{i} = a_{i} ^ a_{i+1} (2). De exemplu, daca avem numarul 6 cu reprezentarea binara 110, atunci b_{0} = a_{0} ^ a_{1} = 0 ^ 1 = 1, b_{1} = a_{1} ^ a_{2} = 1 ^ 1 = 0, b_{2} = a_{2} ^ a_{3} = 1 ^ 0 = 1, deci g(110) = 101. Din aceasta relatie tragem concluzia ca g(i) = x ^ (x / 2) (unde prin / am notat impartire intreaga). Din (2) obtinem ca b_{i} ^ b_{i+1} ^ b_{i+2} ^ ... = (a_{i} ^ a_{i+1}) ^ (a_{i+1} ^ a_{i+2}) ^ (a_{i+2} ^ a_{i+3}) ^ ... = a_{i}. Aceasta suma este finita deoarece vom avea un b_{i} egal cu 0 si un a_{i} egal cu 0, daca i este indeajuns de mare. Astfel g-1(y) = y ^ y/2 ^ y/4 ^ ...
Din cele de mai sus obtinem urmatoarele metode:

int binToGray(int x) {
     return x ^ (x >> 1);
}
int  grayToBin(int y) {
     int ret = 0;
    while (y > 0) {
        ret ^= y;
        y >>= 1;
     }
     return ret;     
}

Sa vedem mai departe cateva probleme: