Carry look-ahead adder

14 Febbraio, 2010

The main issue with understanding Carry look-ahead adders is that you have to take into consideration that to find the current Carry value you still need ALL the previous inputs. Therès no delay for this, since they are inputs, but therès a problem with the fan-in getting bigger and bigger.

To remember the current Carry value I just say that every Ci depends only on C0, and all previous inputs.

The fan-in problem happens because of this, because we need to reference ALL of the previous inputs, therefore gate calculations becomes expensive for all the inputs.

To solve this we sort of group every 4 inputs (usually it's 4), and calculate the Carry only for those 4 inputs at a time. Then we just pass the resulted carry to the next group by the means of ripple-carry (a delay applies here).

This is a mixed solution, but it works for real life behavior.

Poste.it sotto attacco

10 Ottobre, 2009

Le poste italiane sono state attaccate tramite un accesso non consentito sul loro server web.

Questo non suppone, ma nemmeno esclude il fatto che fossero riusciti ad accedere ad importanti informazioni bancarie.

L'hack è stato reso possibile tramite un baco nel sistema database che rendeva possibile l'SQL injection. Il problema era stato reso evidente da altra gente, e completamente trascurato dalle Poste Italiane.

Videogioco isometrico, con JavaScript ed il DOM

03 Agosto, 2009

Alcuni mesi fa, durante i periodi più freddi di Chicago (circa 30 gradi Celsius sotto lo zero), avevo deciso di implementare un semplice videogioco isometrico. Non avevo nessuna esperienza nello sviluppo di videogiochi e volevo sperimentare le mie abilità in un settore completamente nuovo.

Inizialmente avevo intenzione di creare qualcosa tramite qualche libreria grafica in C++ (vista l'incredibile quantità di documentazione del linguaggio in ambito videogiochi disponibile online), ma dopo qualche giorno ho deciso che non avrei avuto bisogno di imparare le API delle librerie dal momento che ero già a conoscenza di un'API che mi sarebbe giovata alla perfezione.

Naturalmente sto parlando dell'API messa a disposizione da un comune Web Browser. Tramite la manipolazione del DOM con JavaScript si ha la possibilità di creare elementi grafici 2d in modo estremamente semplice.

Ambiente isometrico

L'isometria rende possibile trasformare l'ambiente 2d in modo da dare una prospettiva migliore degli elementi visibili. Il mio obiettivo era quello di poter spostare diversi elementi tramite questo asse isometrico; dopo alcune ricerche sono riuscito a trovare una formula matematica che mi avrebbe permesso di identificiare la posizione di un tile nelle coordinate (x,y) del browser.

A questo punto il gioco era quasi fatto, l'implementazione dell'algoritmo A* Pathfinding era a mio avviso la cosa più complicata da fare, mentre invece si è rivelata la cosa più semplice.

Multiplayer tramite Ajax, Comet

Il gioco era divenuto migliore delle mie aspettative iniziali ed avevo intenzione di usufruire al massimo delle funzionalità presenti nel browser. Grazie alla presenza di Ajax, la possibilità di comunicare con un server senza il ricaricamento della pagina, mi è venuto naturale pensare a come usufruire di questa tecnologia per creare un'interfaccia multiplayer. Con l'aggiunta di Comet (in pratica è una semplice request HTTP che non termina, e ci permette di mandare dati al client - browser - se si verificano cambiamenti sul server) ho potuto creare un piccolo server in C che riuscisse ad elaborare i dati del "giocatore" e rimandarli presso il processo HTTP -> client appena richiesti.

Credo che l'ambiente Web + JavaScript sia maturo abbastanza da poter ospitare giochi di questo genere, con semplici attributi grafici, visto anche l'incredibile portabilità (basta un web-browser con javascript). Purtroppo io non ho molte qualità a livello grafico da poter fare qualcosa di interessante per questo progetto, come distribuirlo e/o creare una storia per il gioco, ma se siete interessati ed avete qualche esperienza nel settore videogiochi, non esitate a contattarmi.

Sviluppo guidato da test (test-driven development)

10 Luglio, 2009

Appena un programmatore novizio sente parlare di "test", si rende subito conto che sta per imbarcarsi in una faccenda oscura: ore sprecate nel cercare ogni piccolo baco, creazioni di funzioni inutili che non verranno mai utilizzate dal programma stesso, tempo che poteva essere utilizzato nello sviluppo di nuovi features del software. Il programmatore non riuscirà mai a lavorare a queste cose in maniera felice e producente, ritenendole solamente una interruzione nello sviluppo dell'applicazione. Questa è ovviamente la maniera sbagliata di intraprendere l'attività di testing.

La maniera più semplice, e logica, di scrivere test è scrivere i test prima del codice applicazione. Questo è l'elemento fondamentale del TDD (test-driven development); ci permette di sviluppare la struttura del programma durante la programmazione che, con un minimo di design iniziale, si intravede crescere tramite la scrittura dei test.

Supponiamo di creare un'applicazione per calcolare il punteggio di una partita di bowling. Potremmo cominciare a strutturare l'applicazione cercando di capire ogni singolo dettaglio del problema, e di risolverlo, prima ancora di scrivere codice. Oppure possiamo partire dagli elementi più semplici del problema, in questo caso, le azioni svolte durante una partita di bowling.

void test_partita_bowling()
{
partita_bowling_init();

/* lancia la palla 20 volte, e prendi 0 birilli ogni volta */
for(int i=0; i < 20; i++) {
partita_bowling_roll(0);
}

/* visto che abbiamo preso 0 birilli,
* controlliamo che il punteggio finale sia in effetti 0
*/
assert(partita_bowling_punteggio() == 0);
}

Oltre ad avere una struttura solida con cui iniziare, abbiamo anche scritto il nostro primo test, quindi per qualsiasi cambiamento dell'implementazione saremmo sempre certi del successo dei nostri test. Questo diventa un dato importantissimo una volta che le dimensioni del software cominciano a crescere.

La tecnica del TDD è sinonimo dell'igene della nostra applicazione. Nello stesso modo in cui i dottori si lavano le mani prima di operare, noi dobbiamo scrivere test prima del codice applicazione.

Il linguaggio C, Programmazione ad oggetti

14 Giugno, 2009

Credete che per usare la programmazione ad oggetti si debba avere un linguaggio orientato alla programmazione ad oggetti? Sbagliato. Lo stile ad oggetti è ormai divenuto uno standard per la maggior parte dei linguaggi moderni come il Java ed il C++; non significa che questo stile non si possa implementare in linguaggi imperativi come il C.

In C, la struttura dati per rappresentare un "oggetto" è lo struct. Non si possono definire funzioni in uno struct (oltre a puntatori di funzioni), ma possiamo semplicemente creare funzioni che applichino qualche funzionamento sui dati dello struct stesso. In questo modo possiamo rappresentare la stessa metodologia di Classi e metodi usata in linguaggi OO, per esempio:

struct oca {
int vola;
};
struct oca *oca_new()
{
struct oca *o = malloc(sizeof(struct oca));
memset(o, 0xda, sizeof(struct oca));
return o;
}
void oca_falla_volare(struct oca *o)
{
o->vola = 1;
}
int main()
{
struct oca *oca = oca_new();
oca_falla_volare(oca);
}

Incapsulamento

Uno degli elementi fondamentali dell'OOP è l'incapsulazione. Possiamo usufruire del fatto che, in C, se implementiamo una struttura dati nel file ".c" invece che nell'apposito ".h", la struttura dati diventa invisibile al di fuori dello scope del file ".c". Allora come facciamo ad accedere allo struct al di fuori di esso? Semplice, tramite typedef.

// gatto.h
typedef struct gatto_t gatto;
// a questo punto il compilatore non sa nulla a riguardo dello struct,
// ma possiamo comunque definirci un tipo
gatto *gatto_new();
int gatto_set_corri(gatto *, int);

// gatto.c
#include "gatto.h"

struct gatto_t {
int corri;
};

gatto *gatto_new()
{
gatto *o = malloc(sizeof(gatto));
o->corri = 1; // possiamo dereferenzare il puntatore, perchè il compilatore
// riesce a vedere lo struct gatto_t, visto che è
// nello stesso scope
return 0;
}

int gatto_set_corri(gatto *o, int v)
{
o->corri = v;
}

// main.c
#include "gatto.h"

int main()
{
gatto *g = gatto_new();

int a = g->corri; // questo darà errore, non possiamo dereferenzare il
// membro dello struct visto che non ne abbiamo traccia
// nella definizione

int b = gatto_set_corri(g, 5); // questo invece funziona perchè
// la funzione è implementata nello
// stesso scope dello struct
}

Quando usare la programmazione ad oggetti col C

Negli ultimi anni il linguaggio C++ è cresciuto e maturato moltissimo, quindi è da buon programmatore chiedersi come e quando implementare questo stile ad oggetti con il linguaggio C. Sono riuscito ad identificare (in modo personale) alcuni condizioni che confermano la competitività dell'OOC (Object Oriented C):

L'uso indegno di questo stile nei miei programmi C mi ha aiutato moltissimo a creare applicazioni di alto livello, con API solide. La comprensione della programmazione ad oggetti che ho ottenuto è aumentata vertiginosamente, aiutandomi anche con altri linguaggi disegnati apposta.

© 2009 Pseudo Codice