Sei sulla pagina 1di 48

Struttura Programmi

Algebra di Boole

1
Struttura di un programma C
parte dichiarativa globale

inclusione librerie / per poter invocare funzioni utili (i/o, ...) /


dichiarazione di variabili globali e funzioni
int main ( ) { parte dichiarativa locale
dichiarazione di variabili locali
istruzione 1; / tutti i tipi di operazioni, e cioè: /
istruzione 2; / istr. di assegnamento /
istruzione 3; / istr. di input / output /
istruzione 4; / istr. di controllo (condizionali, cicli) /
...
istruzione N; parte esecutiva
}

Ogni programma C deve contenere un modulo int main() {...}


2
Struttura di un programma C
• Parte dichiarativa: contiene le dichiarazioni degli
elementi del programma
– Dati, ed eventualmente funzioni (ma solo nella parte
globale)
• Parte esecutiva: contiene le istruzioni da eseguire,
che ricadono nelle categorie:
– Istruzioni di assegnamento ()
– Strutture di controllo:
• Condizionali (if-then-else e switch)
• Iterative, o cicli (while, do e for)
– Istruzioni di Input/Output (printf, scanf, ...)

3
Variabili globali e locali
• Le variabili globali sono dichiarate fuori dalle
funzioni
– per convenzione: all’inizio, dopo le #include
• Le variabili locali sono dichiarate internamente
alle funzioni, prima della parte esecutiva
• In caso di programmi monomodulo (cioè
contenenti una sola funzione, il main()), variabili
globali e locali sono equivalenti
– È pertanto indifferente il luogo in cui sono dichiarate
• La differenza si ha nei programmi multimodulo

4
Commenti
• Porzioni di testo racchiuse tra /* e */
– Se un commento si estende da un certo punto fino alla
fine di una sola riga si può anche usare //
/* Programma che non fa nulla ma mostra
i due modi per inserire commenti in C */
int main {
int valore; // Dich. inutile: variabile mai usata
return 0;
}
• I commenti sono ignorati dal compilatore
• Servono per aumentare la leggibilità e la facilità di
modifica di un programma
– A distanza di tempo, per persone diverse dall’autore, ...

5
Istruzioni semplici e composte
(simple and compound statements)
• Sequenze di istruzioni semplici
– Ogni istruzione semplice termina con ;
– ; è detto il “terminatore” dell’istruzione
• Si possono raggruppare più istruzioni in
sequenza tra { e } a costituire un blocco
– Il blocco costituisce una “super-istruzione”
• Non è necessario il ; dopo }, in quanto il
blocco è già una istruzione
– non necessita del terminatore per diventarla

6
Teorema di Böhm e Jacopini
• Tutti i programmi possono essere scritti in
termini di tre strutture di controllo:
– Sequenza: istruzioni eseguite in ordine
– Selezione: istruzioni che permettono di
prendere strade diverse in base a una condizione
(costrutto di tipo if-then-else)
– Iterazione: istruzioni che permettono di
eseguire ripetutamente un certo insieme di altre
istruzioni (costrutti di tipo while, do e for)

7
Sequenza
int main() {
int integer1, integer2, sum;
printf ("Enter first integer\n");
scanf ("%d", &integer1 );
printf ("Enter second integer\n");
scanf ("%d", &integer2);
sum = integer1 + integer2;
printf ("\nSum is %d\n\n", sum );
return 0;
}

8
Selezione
int main()
{
int n;
printf (“Inserisci un numero\n");
scanf ("%d", &n );
if ( n > 0 )
printf ("Un numero positivo ! \n");
else
condizione printf ("Un numero negativo o nullo\n");
printf ("Fine del programma\n");
return 0;
}

9
Iterazione
int main()
{
int n = 9;
printf ( " PRONTI...\n " );
while ( n > 0 ) {
printf (" ...meno %d ...\n", n);
n = n-1;
condizione
}
printf ( " ...VIA!!! \n " );
return 0;
}

10
Iterazione
int main()
{
int n = 9;
printf ( " PRONTI...\n " );
while ( n > 0 )
printf (" ...meno %d ...\n", n);
n = n-1;
condizione
printf ( " ...VIA!!! \n " );
return 0;
}

Che fa?

11
Iterazione
int main()
{
int n = 9;
printf ( " PRONTI...\n " );
while ( n > 0 ) ; {
printf (" ...meno %d ...\n", n);
n = n-1;
condizione
}
printf ( " ...VIA!!! \n " );
return 0;
}

Che fa?

12
Istruzioni condizionali
• L’esecuzione dipende da condizioni sul
valore di espressioni booleane, costruite
mediante operatori:
– Relazionali (predicano sulla relazione tra due valori)
==, !=, <, >, <=, >=
– Logici (predicano sul valore di verità di espressioni logiche)
! (NOT)
&& (AND)
|| (OR)

13
Algebra di Boole
ed
Elementi di Logica

14
Cenni all’algebra di Boole
• L’algebra di Boole (inventata da G. Boole,
britannico, seconda metà ’800), o algebra
della logica, si basa su operazioni logiche
• Le operazioni logiche sono applicabili a
operandi logici, cioè a operandi in grado di
assumere solo i valori vero e falso
• Si può rappresentare vero con il bit 1 e falso
con il bit 0 (convenzione di logica positiva)

15
Operazioni logiche fondamentali
• Operatori logici binari (con 2 operandi logici)
– Operatore OR, o somma logica
– Operatore AND, o prodotto logico
• Operatore logico unario (con 1 operando)
– Operatore NOT, o negazione, o inversione

• Poiché gli operandi logici ammettono due


soli valori, si può definire compiutamente
ogni operatore logico tramite una tabella di
associazione operandi-risultato

16
Operatori logici di base
e loro tabelle di verità
A B A or B A B A and B
0 0 0 0 0 0
0 1 1 0 1 0 A not A
1 0 1 1 0 0
1 1 1 1 1 1 0 1
(somma logica) (prodotto logico) 1 0
(negazione)

Le tabelle elencano tutte le possibili combinazioni in ingresso


e il risultato associato a ciascuna combinazione

17
Altri operatori logici
e loro tabelle di verità
A B A xor B A B A xnor B
0 0 0 0 0 1
0 1 1 0 1 0
1 0 1 1 0 0
1 1 0 1 1 1
(o uno o l’altro ma
non entrambi)

A xor B = ( A and ( not B ) ) or ( ( not A ) and B )

A xnor B = not((A and (not B)) or (B and (not A)))

18
Espressioni logiche (o Booleane)
• Come le espressioni algebriche, costruite con:
– Variabili logiche (letterali): p. es. A, B, C  0 oppure 1
– Operatori logici: and, or, not
• Esempi:
A or (B and C)
(A and (not B)) or (B and C)
• Precedenza: l’operatore “not” precede l’operatore “and”,
che a sua volta precede l’operatore “or”
A and not B or B and C  (A and (not B)) or (B and C)
• Per ricordarlo, si pensi OR come “” (più), AND come “”
(per) e NOT come “” (cambia segno)

19
Tabelle di verità delle espressioni logiche

A B NOT ( ( A OR B) AND ( NOT A ) )


0 0 1
0 1 0
1 0 1
1 1 1

Specificano i valori di verità


per tutti i possibili valori
delle variabili

20
Tabella di verità
di un’espressione logica
A and B or not C
ABC X = A and B Y = not C X or Y
000 0 and 0 = 0 not 0 = 1 0 or 1 =1
001 0 and 0 = 0 not 1 = 0 0 or 0 =0
010 0 and 1 = 0 not 0 = 1 0 or 1 =1
011 0 and 1 = 0 not 1 = 0 0 or 0 =0
100 1 and 0 = 0 not 0 = 1 0 or 1 =1
101 1 and 0 = 0 not 1 = 0 0 or 0 =0
110 1 and 1 = 1 not 0 = 1 1 or 1 =1
111 1 and 1 = 1 not 1 = 0 1 or 0 =1

21
Due esercizi
A B NOT ( ( A OR B) AND ( NOT A ) )
0 0 1 0 0 0 0 1 0
0 1 0 0 1 1 1 1 0
1 0 1 1 1 0 0 0 1
1 1 1 1 1 1 0 0 1
A B C ( B OR NOT C ) AND ( A OR NOT C )
0 0 0 0 1 1 0 1 0 1 1 0
0 0 1 0 0 0 1 0 0 0 0 1
0 1 0 1 1 1 0 1 0 1 1 0
0 1 1 1 1 0 1 0 0 0 0 1
1 0 0 0 1 1 0 1 1 1 1 0
1 0 1 0 0 0 1 0 1 1 0 1
1 1 0 1 1 1 0 1 1 1 1 0
1 1 1 1 1 0 1 1 1 1 0 1

22
A che cosa servono le espressioni logiche?
• A modellare alcune (non tutte) forme di ragionamento
– A  è vero che 1 è maggiore di 2 ? (sì o no, qui è no)  0
– B  è vero che 2 più 2 fa 4 ? (sì o no, qui è sì)  1
– A and B  è vero che 1 sia maggiore di 2 e che 2 più 2 faccia 4 ?
Si ha che A and B  0 and 1  0, dunque no
– A or B  è vero che 1 sia maggiore di 2 o che 2 più 2 faccia 4 ?
Si ha che A or B  0 or 1  1, dunque sì
• OR, AND e NOT vengono anche chiamati connettivi logici,
perché funzionano come le congiunzioni coordinanti “o” ed “e”,
e come la negazione “non”, del linguaggio naturale
• Si modellano ragionamenti (o deduzioni) basati solo sull’uso di
“o”, “e” e “non” (non è molto, ma è utile)

23
Che cosa non si può modellare
tramite espressioni logiche?
• Le espressioni logiche (booleane) non modellano:
– Domande esistenziali: “c’è almeno un numero reale x tale
che il suo quadrato valga 1 ?” (si sa bene che non c’è)
x | x2  1 è falso
– Domande universali: “ogni numero naturale è la somma di
quattro quadrati di numeri naturali ?” (si è dimostrato di sì)
x | x  a2b2c2d2 è vero (“teorema dei 4 quadrati”)
Più esattamente andrebbe scritto: x a,b,c,d | x  a2b2c2d2
•  e  sono chiamati “operatori di quantificazione”, e
sono ben diversi da or, and e not
• La parte della logica che tratta solo degli operatori or,
and e not si chiama calcolo proposizionale
• Aggiungendo gli operatori di quantificazione, si ha il
calcolo dei predicati (che è molto più complesso)

24
Tautologie e Contraddizioni
• Tautologia
– Una espressione logica che è sempre vera, per
qualunque combinazione di valori delle variabili
• Esempio: principio del “terzo escluso”: A or not A
(tertium non datur, non si dà un terzo caso tra l’evento A
e la sua negazione)
• Contraddizione
– Una espressione logica che è sempre falsa, per
qualunque combinazione di valori delle variabili
• Esempio: principio di “non contraddizione”: A and not A
(l’evento A e la sua negazione non possono essere
entrambi veri)

25
Equivalenza tra espressioni
• Due espressioni logiche si dicono equivalenti (e si
indica con ) se hanno la medesima tabella di
verità. La verifica è algoritmica. Per esempio:
AB not A and not B  not (A or B)
00 1 and 1 = 1 not 0 = 1
01 1 and 0 = 0 not 1 = 0
10 0 and 1 = 0 not 1 = 0
11 0 and 0 = 0 not 1 = 0

• Espressioni logiche equivalenti modellano gli stessi


stati di verità a fronte delle medesime variabili

26
Equivalenza tra espressioni
not ( A and not B or not A and B ) or C and not C
• “C and not C” non contribuisce alla verità dell’espressione con
cui è in disgiunzione.
• Non dipendendo da C, l’espressione si può semplificare ed
esprimere in funzione delle due variabili A e B.
• Risulta essere quindi la definizione dello xnor
( A xnor B = not ( A xor B ) = not( A and not B or B and not A )

A B A xnor B
0 0 1
0 1 0
1 0 0
1 1 1
27
Proprietà dell’algebra di Boole
• L’algebra di Boole gode di svariate proprietà,
formulabili sotto specie di identità
– (cioè formulabili come equivalenze tra espressioni
logiche, valide per qualunque combinazione di
valori delle variabili)
• Esempio celebre: le “Leggi di De Morgan”
not (A and B)  not A or not B (1a legge)
not (A or B) not A and not B (2a legge)

28
Ancora sulle proprietà
• Alcune proprietà somigliano a quelle
dell’algebra numerica tradizionale:
– Proprietà associativa: A or (B or C)  (A or B) or C (idem per
AND)
– Proprietà commutativa: A or B  B or A (idem per AND)
– Proprietà distributiva di AND rispetto a OR:
A and (B or C)  A and B or A and C
– … e altre ancora
• Ma parecchie altre sono alquanto insolite…
– Proprietà distributiva di OR rispetto a AND:
A or B and C  (A or B) and (A or C)
– Proprietà di assorbimento (A assorbe B):
A or A and B  A
– Legge dell’elemento 1: not A or A  1
– … e altre ancora

29
Uso delle proprietà
• Trasformare un’espressione logica in un’altra, differente
per aspetto ma equivalente:
not A and B or A  (assorbimento)
= not A and B or (A or A and B)  (togli le parentesi)
= not A and B or A or A and B  (commutativa)
= not A and B or A and B or A  (distributiva)
= (not A or A) and B or A  (legge dell’elemento 1)
= true and B or A  (vero and B  B)
= B or A è più semplice dell’espressione originale !
• Si verifichi l’equivalenza con le tabelle di verità!
• Occorre conoscere un’ampia lista di proprietà e si deve
riuscire a “vederle” nell’espressione (qui è il difficile)

30
Istruzioni condizionali
• L’esecuzione dipende da condizioni sul
valore di espressioni booleane, costruite
mediante operatori:
– Relazionali (predicano sulla relazione tra due valori)
==, !=, <, >, <=, >=
– Logici (predicano sul valore di verità di espressioni logiche)
! (NOT)
&& (AND)
|| (OR)

31
Condizioni: esempi
X == 0
X > 0 && A != 3
!( (x+5)*10 >= ALFA3 / (Beta_Due+1) )

Esistono regole di precedenza


! a || b && c
prima !, poi &&, poi ||
( (!a) || ( b && c ) )
in caso di dubbio, usare le parentesi ( tonde )

32
Dettagli
• && e || si valutano da sinistra a destra
• La valutazione di una espressione logica
procede finché necessario per dedurne la
verità o falsità, e si arresta appena è definita:

( x != 0 ) && ( (100 / x) == 0 )

Se x vale zero l’espressione risulta falsa e


non si verifica alcun errore (di divisione per
zero), perché è inutile procedere a valutare
oltre && (ovviamente è inutile solo se x vale zero)

33
Vero/falso in C
• Una condizione (espressione relazionale o
logica) assume il valore
0 se risulta FALSA
1 se risulta VERA
• Ogni valore “non zero” è considerato vero
if ( 3 ) ...
if ( -1 ) ...
while (1) ... /* continua PER SEMPRE !! */
if ( a – a ) ... /* sarà sempre FALSO,
indipendentemente dal valore di a */

34
Assegnamento (=) e uguaglianza (==)
• L’istruzione di assegnamento
int a = 0, b = 4;
a = b;
printf( "%d", a );

• Il predicato di confronto
int a = 0, b = 4;
if ( a == b )
printf( "uguali" );
else
printf( "diversi" );

35
Istruzioni condizionali (if-then-else)
• Costrutto a selezione singola:
if ( espressione ) ramo
then
istruzione
oppure a selezione doppia: ramo
if ( espressione ) then
istruzione1 ramo
else else
istruzione2
• I rami possono contenere istruzioni composte:
if ( espressione )
{ seq.1 di istruzioni } sequenze di più
else istruzioni
{ seq.2 di istruzioni }
• Gli if possono essere annidati

36
Istruzione condizionale semplice
if (x < 0) x = -x; else x = x + 10;
Per maggior leggibilità, è bene usare
regole di incolonnamento (indentazione)
if (x < 0)
x = -x;
else è una questione di stile
x = x + 10; ma è molto importante

37
Esempi
if (x < 0)
x = - x; /* trasforma x nel suo valore assoluto */

if ( a > b ) { /* indica il massimo tra due valori */


max = a;
printf("massimo: %d", max); if ( a > b )
} max = a;
else
else { max = b;
max = b; printf("massimo: %d", max);
printf("massimo: %d", max);
}

38
Istruzioni condizionali
(selezione singola)

#include <stdio.h> /* Calcolo del valore assoluto */


int main ( ) { /* programma principale */
int numero, valass; /* dichiarazione delle variabili
*/
printf ("Calcolo Valore Assoluto.\n\n");
printf ("Inserisci Numero Intero:");
scanf ("%d", &numero); /* acquisizione valore */
condizione
if (numero < 0)
ramo
valass = - numero;
then
if (numero >= 0)
valass = numero;
printf ("Numero: %d\n", numero); /* output */
printf ("Valore assoluto: %d\n", valass); /* output */
return 0;
}

39
Istruzioni condizionali
(variante con selezione doppia)

#include <stdio.h> /* Calcolo del valore assoluto */


int main ( ) { /* programma principale */
int numero, valass; /* dichiarazione delle variabili */
printf ("Calcolo Valore Assoluto.\n\n");
printf ("Inserisci Numero Intero:");
scanf ("%d", &numero); /* acquisizione valore */
if (numero < 0) condizione
valass = - numero; ramo
else then ramo
valass = numero; else
printf ("Numero: %d\n", numero); /* output */
printf ("Valore assoluto: %d\n", valass); /* output */
return 0;
}

40
1 /* Uso delle strutture condizionali,
2 degli operatori relazionali e
3 di uguaglianza */
4 #include <stdio.h>
5
6 int main()
7 {
8 int num1, num2;
9
10 printf ("Enter two integers, and I will tell you\n");
11 printf ("the relationships they satisfy: ");
12 scanf ("%d%d", &num1, &num2); /* lettura di due numeri interi */
13
14 if (num1 == num2)
15 printf ("%d is equal to %d\n", num1, num2);
16
17 if (num1 != num2)
18 printf ("%d is not equal to %d\n", num1, num2);
19
20 if (num1 < num2)
21 printf ("%d is less than %d\n", num1, num2);
22
23 if (num1 > num2)
24 printf ("%d is greater than %d\n", num1, num2);
25
26 if (num1 <= num2)
27 printf ("%d is less than or equal to %d\n",
28 num1, num2);
41
29
30 if (num1 >= num2)
31 printf ("%d is greater than or equal to %d\n",
32 num1, num2);
33
34 return 0; /* il programma è terminato con successo */
35 }

> Enter two integers, and I will tell you


> the relationships they satisfy: 3 7
> 3 is not equal to 7
> 3 is less than 7
> 3 is less than or equal to 7

> Enter two integers, and I will tell you


> the relationships they satisfy: 22 12
> 22 is not equal to 12
> 22 is greater than 12
> 22 is greater than or equal to 12

42
if-then-else annidati
if (i < 100)
if (i > 0)
printf ("Minore di 100 e maggiore di zero\n");
else
if (i == 0)
printf("Uguale a zero\n");
else
printf("Minore di zero\n");
else
if (i == 100)
printf( "Uguale a 100\n");
else
printf ("Maggiore di 100\n");

43
Annidamento, blocchi, indentazione
if (n > 0)
Potenziale ambiguità: if (a>b)
z = a;
if (n > 0) if (a>b) z = a; else z = b; else
z = b;
ogni else si associa
all’if più vicino if (n > 0) {
if (a>b)
l'indentazione lo rende evidente
z = a;
se incerti, usare le parentesi }
if (n > 0) { if (a>b) z = a; } else z = b; else
z = b;

44
Sequenze di if
• Spesso accade di voler scrivere molti
if annidati (alternative multiple):
if (...)
fai qualcosa1;
else
if (…)
fai qualcosa2;
else
if(…)

45
if (n % 2 == 0)
Esempio
printf("%d è pari", n);
else
if (n % 3 == 0)
printf("%d è multiplo di 3", n);
else
if (n % 5 == 0)
printf("%d è multiplo di 5", n);
else
if (n % 7 == 0)
printf("%d è multiplo di 7", n);
else
if (n % 11 == 0)
printf("%d è multiplo di 11", n);
else
if (n % 13 == 0)
printf("%d è multiplo di 13", n);
else
printf ("il numero %d non ha divisori primi < 15",
n);

46
Una rappresentazione più leggibile
/* Se un numero n ha divisori primi <15, stampa il minimo,
altrimenti stampa un messaggio che lo segnala */
if (n % 2 == 0)
printf("%d è pari", n);
else if (n % 3 == 0)
printf("%d è multiplo di 3", n);
else if (n % 5 == 0)
printf("%d è multiplo di 5", n);
else if (n % 7 == 0)
printf("%d è multiplo di 7", n);
else if (n % 11 == 0)
printf("%d è multiplo di 11", n);
else if (n % 13 == 0)
printf("%d è multiplo di 13", n);
else printf ("il numero %d non ha divisori primi < 15", n);

47
Cosa cambia?
if (n % 2 == 0) if (n % 2 == 0)
printf("%d è pari", n); printf("%d è pari", n);
else if (n % 3 == 0) if (n % 3 == 0)
printf("%d è multiplo di 3", n); printf("%d è multiplo di 3", n);
else if (n % 5 == 0) if (n % 5 == 0)
printf("%d è multiplo di 5", n); printf("%d è multiplo di 5", n);
else if (n % 7 == 0) if (n % 7 == 0)
printf("%d è multiplo di 7", n); printf("%d è multiplo di 7", n);
else if (n % 11 == 0) if (n % 11 == 0)
printf("%d è multiplo di 11", n); printf("%d è multiplo di 11", n);
else if (n % 13 == 0) if (n % 13 == 0)
printf("%d è multiplo di 13", n); printf("%d è multiplo di 13", n);

48