Campionatul national de tirnacop viteza

Posted in Codare cu premeditare, Premiul n00bel on May 11th, 2011 by jos8cal

Azi in Codexpertia a avut loc Campionatul National de Tirnacop Viteza. Bineinteles nu a lipsit de la eveniment multiplul medaliat la sol, Silviu Ardelean HD nominalizat acum la sectiunea “Eu propun”.

Cum nu de mult timp a devenit somer in JAVA, el a tinut sa explice motivele pentru care tirnacopul l-a ales pe el si nu invers. Medaliat la sectiunea Un Certain Retard pentru inovatia adusa metodei aflarii numarului de bytes dintr-un fisier, premiat la sectiunea Facepalm D’or cu simularea functiei atoi() in timp patrat, Silviu a deschis prelegerea cu problema numararii bitilor 1 dintr-un numar.

Cu Silviu in mina, tirnacopul s-a pus pe treaba. Dupa o lovitura bine aplicata lui Google s-a si intrezarit raspunsul la problema minerului in link-ul 2 (ca primul link l-a luat Marius Bancila care a si apucat sa ia cuvintul inaintea lui la dezbatere, futu-i). Asa ca a copiat repede codul prin metoda clasica a schimbarii numelor de variabile si si-a deschis prelegerea cu clasicul “Eu plagiezEu propun

Eu propun o varianta mai clasica.

int counter(int nr)
{
   int i = 0;  

   while (0 != nr)
   {
    i += (nr & 1);
    nr >>= 1;
   }  

  return i;
}

Desi este o metoda clasica, ea nu e functionala si tinem sa precizam ca operatorul >> a fost inventat intr-o perioada neo-nazista, de unde probabil si tenta mai nationalista de a opera cu numere pozitive.

Ceva amuzant s-a intimplat in pauza prelegerii. Cineva a pus o intrebare care l-a facut pe Silviu sa priveasca in jur, pentru a gasi pe cineva pe care sa-l aprobe. Intrebarea a fost asta:

Intrebarea este cum apelez functia sum fara sa modific clasa A.

class A
{
   private:
      A(){};
      ~A(){};

   public:
      int sum(int a, int b){return a + b;}
};

Primul care s-a aventurat a propus un:

#define private public

moment in care Silviu a simtit cum se scutura de certitudinile vietii. Nedorind sa creada ca aceste doua cuvinte, public si privat, nu sint de fapt magico-atomice asa cum a invatat el la Hidrocentrala pe vremea cind era pasionat de apa si peste, el a pus compilatorul capra si i-a virit acest #define pe git, sa vada daca si inghite, nu doar provoaca.

Ca dupa orice finalizare, oboseala incepe sa-si spuna cuvintul si uitind ca a lasat in cod acel #define, el ne propune rezolvarea:

O varianta mai curata dar nu imaculata:

class B : public A
{
public:
   B() {}
   ~B() {}

   int sumX(int a1, int b1) {
      return sum(a1,b1);
      }
};

int main()
{
   B z;
   z.sumX(2,3);
}

Deci daca vrei sa apelezi o metoda dintr-o clasa care nu poate fi instantiata, poti “propune” compilatorului sa-i dai o clasa derivata care sa apeleze metoda clasei de baza. Poate cineva de acolo din cartile pe care le citeste Silviu ne poate ajuta cu un

#pragma eupropun

in fata manevrelor de acest gen.

Mai mult decit atit, Silviu a declarat oficial ca a fost pacalit cind a propus rezolvarea sa, deoarece Zlatomir s-a grabit sa raspunda primul si a introdus subversiv in discutie acel #define private public obligindu-l efectiv sa-l aduca cu copy/paste in codul sau. Daca nu exista acest Butterfly Effect, codul lui Silviu era bun. De fapt stai, nu codul initial linie cu linie, ci codul pe care Silviu nu l-a scris dar l-a Gindit si din pacate un mirsav i-a ghicit gindul si i-a sugerat la noi pe site EXACT la ce s-a gindit el initial, dar nu a scris. Intelegeti voi.

PS. Multumim corespondentului Felics aflat in Codexpertia pe durata CNTV.

Tags: , , , , , , , , , , , ,

O noua propunere

Posted in Premiul n00bel on March 20th, 2011 by Mihnea

Zarva mare in comunitatea expertilor, caci 0ptr iar e pus pe sotii. Dupa ce s-a lamurit cu Regula 0 a codului portabil, a revenit cu o intrebare parca special facuta pentru a-l activa pe Silviu Virgula Ardelean: cum ati implementa atoi()?

Intrebarea asta e pentru miner ca un laser pointer pentru o pisica: irezistibila. Silviu traieste pentru momentele astea, cind cineva pune o intrebare banala si el crede ca stie raspunsul, pentru ca ii permit sa-si afirme si sa-si confirme statutul de connaisseur. Cu serotonina refulind prin nas si urechi, el a atins duios tastatura si a scris cuvintele ce-i sint atit de dragi: Eu propun urmatoarea implementare.

Propunerea nu dezamageste. Prin truda afunda, ortacul scoate din abataj o noua floare de mina desavirsita, un memento al zbuciumului ce-i cuprinde fiinta de fiecare data cind se vede pus in fata unei masini de scris automate. Dat fiind ca el n-are un compilator in cap, o sa fac eu pe compilatorul si voi incerca sa descifrez linie cu linie ce se petrece in mintea greu incercata a unui miner cu 9 ani de experienta in C++.

bool isNegative = (*pChar == '-') ? true : false;

Ostilitatile incep in forta. Silviu nu are incredere in compilatoare si alte “tool-uri automate”, asa ca foloseste operatorul ? pentru a converti true la true si false la false. Asta e doar pasul 1 din planul lui. Cind va implini 10 ani de experienta in C++, isi va autoimpune sa transeze definitiv problema bool-ului prin urmatoarele tipuri de constructii:

bool a = true ? true : false;
bool b = false ? true : false;
if( ((true == a ? true : false) || (false == b ? true : false)) ? true : false)
    a = b ? true : false;

Urmeaza o prima trecere prin string, cu scopul de a verifica daca instructiunile de branch ale procesorului functioneaza corect sub stres:

while (*pChar != '\0')
{
   if ((isNegative && length == 1 && (*pChar != '-') && (*pChar < '0' || *pChar > '9')) ||
      (length > 0 && (*pChar < '0' || *pChar > '9')))
         break;

   length++;
      pChar += sizeof(char);
}

If-ul asta e reprezentativ pentru miner. In opinia lui, “loop-ul ala e un ‘strlen()’ mai special”. Da, special ca aia care baga cubul in gaura rotunda. Pe Silviu nu l-a dus capul sa incrementeze pointerul ala nenorocit daca string-ul incepe cu minus, dar el e puternic, asa ca a impins cit a putut de tare cubul si pina la urma a intrat in gaura. De asemenea, observam citeva reguli de stil bine conturate: ultima linie din bucla se indenteaza suplimentar, si se pun paranteze doar in jurul expresiilor care implica operatorul !=. length == 1 nu are nevoie de paranteze, dar *pChar != ‘-‘ are.

E important de observat si cum aduna Silviu sizeof(char) la pointer. Minerul a facut asta crezind ca e “best practice” sa fii explicit, ca nu stii cind treci la Unicode si trebuie sa aduni sizeof(wchar_t). Da, el habar n-are ce-i ala pointer arithmetic si chiar crede ca daca pChar era pointer la wchar_t, acolo trebuia sa adune mai mult de 1.

Ajungem, insa, la partea cu adevarat epica din cod, pe care o reproduc integral:

while (length > 0)
{
  decimal = 1;
  if (isNegative)
  {
     if (!isFirst)
     {
        length--;
        if (0 == length)
           break;
     }

     isFirst = true;
  }

  for (int i = 1; i < length; i++)
     decimal *= 10;

  ret_val +=   decimal * (int(*(pChar - length) - '0') % 10);
  length--;
}

Stiti cind ziceam ca ifdef-ul ala cu WIN32 e chintesenta incompetentei lui Silviu? Ei bine, bucla asta nu e la fel de concisa, dar tot e un imn al prostiei de o frumusete rar intilnita. Te astepti de la Silviu sa nu fie in stare sa faca atoi() intr-o singura trecere prin string, dar nici in cele mai umede vise nu speram sa ne ofere un asemenea festin al retardarii. Intii si intii, observam revenirea unui design pattern intilnit si in prima bucla: si asta verifica la fiecare iteratie daca a inceput. Ortacul nu e in stare sa scoata muia aia cu semnul in afara buclei, asa ca tot verifica daca bucla lui face ce fac buclele, si anume daca a reusit sa treaca la a doua iteratie.

Partea misto incepe insa dupa confirmarea abilitatii procesorului de a incrementa numere. Minerul a reusit sa faca atoi() in timp patratic. Dupa cum a mai demonstrat, el e un om simplu, deci prin definitie nu se preocupa de complexitate, dar ma surprinde iar in mod nespus de placut calculind exponentul ala in fiecare ciclu. Incercati sa va imaginati cum ar trebui sa decurga procesul deductiv prin care ajungi sa faci asa ceva. Eu n-am reusit. Voi va dati seama ca asta asa programeaza zilnic, la job? Si ca cineva ii da bani pentru ca sa scrie cod d-asta?

Ca sa incheie apoteotic, intii si-ntii mai arunca o sfidare in ochii compilatorului punind un cast explicit la int, spunindu-i parca “uite ba, iar fac eu treaba ta pentru tine”, dupa care baga un mod ca un chef care pune delicat cireasa in virful celui mai frumos tort pe care l-a facut pina acum. Pai de ce sa beneficieze doar partea booleana de verificari cu operatoru’ intrebare, si aia aritmetica nu? Ortacii programeaza defensiv, ca nu stii cind 9 se face brusc mai mare ca 10 si trebuie sa iei atitudine. De acum incolo, codul lui Silviu va fi de 3 ori mai sigur si mai conform cu standardele MISRA (despre care minerul a auzit linga automatul de cafea cind lucra la xerox la Siemens), caci aritmetica se va face in felul urmator:

pChar += sizeof(char) % 2;
int bytes = mb * (1024 % 1025);
int bits = bytes * (8 % 10);
int doi = 2 % 3;
int unu = 1 % doi;
for(int i = 0; i < size % (size + 1); ++i)

Ortacul si-a pregatit deja apararea: “nu are nimeni pretentia variantei perfecte”. Sa inceapa corecturile, deci.

LE: minerul a si dat prima replica: si-a editat al doilea post din thread si a scris ca patrujdoi sint eu, intr-o noua iesire de Poirot. Simt ca toata munca de reeducare pe care am dus-o aici tocmai s-a dus pe pula. A ajuns din nou sa creada ca eu sint jos8cal, 0ptr, patrujdoi si toti ceilalti care i-au aratat vreodata ca-i prost. Silviu se simte ca-n Matrix, el singur incojurat de o armata de eu. Pentru a doua oara intr-o singura zi s-a inundat de serotonina cind a putut face niste corecturi in codul lui patrujdoi, crezind ca ma corecteaza pe mine. Va dati seama ca a avut orgasm crezind ca m-a prins in sfirsit cu o greseala.

 

Tags: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,