“IF … THEN IF è preferibile a IF … AND … THEN …”

(articolo dell’utente Davide Fichera)

 Pillole di BASIC #4

Probabilmente dal titolo non apparirà chiara l’ottimizzazione che andremo quest’oggi a trattare. Per la precisione quello che valuteremo sarà la differenza di prestazioni delle seguenti istruzioni:

(1) IF (expression #1) AND (expression #2) THEN …

e l’equivalente con gli IF annidati (IF dentro IF):

(2) IF (expression #1) THEN IF (expression #2) THEN …

Quale sarà la più veloce delle due? Per rispondere a questa domanda dobbiamo innanzitutto capire come l’interprete BASIC valuta le espressioni e quando decide di eseguire, o no, le istruzioni dopo il THEN.
Le espressioni presenti dopo l’istruzione IF sono generalmente delle condizioni ( A > B, A < 0, B > A+2 ) che possono restituire un valore 0 (che equivale a un false logico) oppure -1 (che equivale a un true logico). In realtà le espressioni dopo l’IF possono essere di qualsiasi tipo e comunque l’interprete distinguerà solo i casi 0 (false) e non-zero (true). Pertanto la sequenza di istruzioni:

IF 2 THEN PRINT”VERO”

sarà considerata valida, ed essendo 2 un valore non-nullo (non-zero) stamperà VERO sullo schermo.
L’istruzione:

IF A = B THEN PRINT”CIAO”

valuterà invece prima l’espressione A = B, restituendo 0 se false e -1 se true. Se le due variabili sono uguali il risultato dell’espressione A = B sarà -1 (non-zero) e quindi verrà stampata la scritta “CIAO” sullo schermo.
Ritornando alle due sequenze di istruzioni (1) e (2) all’inizio dell’articolo, ci chiediamo invece quali siano i tempi necessari a valutare le espressioni presenti (exp #1 ed exp #2) e se sia più efficiente l’esecuzione della prima o della seconda sequenza.
Cosa succede nella (1) quando la prima espressione risulta false (zero)? In un caso simile in un linguaggio moderno (C, Java, Python, …) viene applicato un meccanismo che prende il nome di “valutazione a corto circuito”, che è applicabile a quegli operatori booleani binari per cui il secondo operando viene valutato unicamente se il valore del primo operando non è sufficiente da solo a determinare il risultato dell’espressione. Nel caso di AND quindi se il primo operando è false, sicuramente il risultato dell’operazione sarà false.
Nel BASIC V2 purtroppo gli operatori booleani non sono “cortocircuitati” e quindi l’interprete valuta comunque la seconda condizione e successivamente svolge una operazione logica (AND) tra le due condizioni. Un altro difetto del Basic è quello di non essere capace di operare con l’algebra booleana, l’operazione di AND verrà eseguita infatti bit a bit (bitwise), e non utilizzando i connettivi logici matematici ˅ (vel, o) e ˄ (aut, e), che in molti linguaggi vengono resi con || e &&.
Tornado alla (1), come opererà l’interprete quindi? Esso dopo aver convertito le condizioni in numeri interi (0 = false, -1 = true) eseguirà un AND bitwise tra le sequenze di bit (i numeri saranno considerati interi signed a 16-bit), come nella tabella qui sotto.

DECIMAL BINARY LOGIC
0 AND 00000000 00000000 AND False AND
-1 = 11111111 11111111 = True =
-1 00000000 00000000 False

Facciamo adesso un’analisi delle prestazioni nel caso in cui la prima condizione (exp #1) sia false oppure true e scriviamo un piccolo programmino che calcoli il tempo necessario a eseguire un certo numero di volte le stesse istruzioni di IF – THEN, una volta utilizzando IF … AND … THEN e un’altra volta IF … THEN IF …
Come possiamo vedere da questi esempi (vedi immagini più sotto) la sequenza di istruzioni con gli IF annidati è sempre da preferire alla sequenza che utilizza l’operatore logico AND. Il guadagno prestazionale, come ci si poteva aspettare, è più marcato (circa la metà del tempo) nel caso in cui la prima espressione è false.

Have your say