You are on page 1of 146

Sommario

Capitolo Primo: Introduzione .................................................................................................6


1.1. Gli strumenti MATLAB e Octave ...........................................................................6
1.2. Il linguaggio di programmazione di MATLAB: caratteristiche generali .................7
1.2.1. Linguaggi interpretati e linguaggi compilati ....................................................8
1.2.2. Linguaggi con tipi dinamici ..............................................................................9
1.3. Interfaccia utente degli ambienti MATLAB e Octave ...........................................11
1.4. Esempi di comandi in MATLAB ..........................................................................11
1.5. Script files..............................................................................................................17
1.5.1. Creare uno script .............................................................................................17
1.5.2. Eseguire uno script .........................................................................................17
1.5.3. Struttura di uno script .....................................................................................18
1.6. Linee guida iniziali per la programmazione in MATLAB ....................................19
1.6.1. Un esempio di cinematica ...............................................................................20
1.7. Materiale per approfondimenti ..............................................................................21
1.8. Bibliografia ............................................................................................................21
Capitolo Secondo: Variabili e tipi di dati .............................................................................22
2.1. Variabili .................................................................................................................22
2.1.1. Tipi double e char ...........................................................................................23
2.1.2. Linee guida per la definizione dei nomi di variabili .......................................23
2.1.3. Creazione e inizializzazione di una variabile .................................................24
2.1.3.1. Assegnamento ..........................................................................................25
2.1.3.2. Assegnamento mediante luso di funzioni predefinite .............................26
2.1.3.3. Inizializzazione mediante lettura dati da tastiera .....................................27
2.1.3.4. Inizializzazione mediante lettura dati da file ...........................................27
2.1.4. Variabili predefinite (costanti) ........................................................................28
2.2. Scalari ....................................................................................................................29
2.3. Array......................................................................................................................29
2.3.1. Operazioni principali per vettori e matrici ......................................................30
2.3.2. Altre funzioni utili ..........................................................................................32
2.3.3. Array multidimensionali .................................................................................32
2.3.4. Subarray..........................................................................................................33
2.4. Tipi di dato logici ..................................................................................................34
2.4.1. Espressioni logiche .........................................................................................34
2.4.1.1. Operatori relazionali ................................................................................35
2.4.1.2. Operatori logici ........................................................................................37
2.4.2. Funzioni logiche .............................................................................................40
2.5. Strutture .................................................................................................................41
2.5.1. Definizioni ......................................................................................................41
2.5.2. Creare una struttura ........................................................................................42
2.5.2.1. Creare una struttura mediante assegnamenti............................................42
2.5.2.2. La funzione struct ....................................................................................43
2.5.3. Array di strutture ............................................................................................44
2.5.3.1. Aggiungere un campo in un array di strutture .........................................45
2.5.3.2. Rimuovere un campo in un array di strutture ..........................................45
2.5.3.3. Accedere ai dati in un array di strutture ...................................................46

2.5.4. Strutture innestate ...........................................................................................47


2.5.5. Esempio riassuntivo ........................................................................................48
Capitolo Terzo: Strutture di Controllo .................................................................................50
3.1. Selezione ...............................................................................................................50
3.1.1. Il costrutto if ...................................................................................................50
3.1.2. Il costrutto switch ...........................................................................................54
3.2. Cicli .......................................................................................................................56
3.2.1. Il ciclo while ...................................................................................................56
3.2.2. Il ciclo for .......................................................................................................58
3.2.2.1. Regole di buona programmazione ...........................................................61
3.2.2.2. Vettorizzazione ........................................................................................61
3.2.3. Break e Continue ............................................................................................62
3.3. Array Logici ..........................................................................................................63
Capitolo Quarto: Sottoprogrammi definiti dallutente: le funzioni ......................................66
4.1. Definizione e uso delle funzioni ............................................................................67
4.1.1. La compatibilit tra parametri formali e attuali ..............................................70
4.1.2. Dove si scrive una funzione? ..........................................................................71
4.1.3. La documentazione delle funzioni ..................................................................71
4.2. Esecuzione delle funzioni e passaggio dei parametri ............................................72
4.2.1. Funzioni che chiamano funzioni .....................................................................74
4.2.2. Confronto tra funzioni e script ........................................................................75
4.3. Esempi di funzioni con vari tipi di parametro .......................................................77
4.3.1. Parametri di tipo array ....................................................................................77
3.2.
Parametri di tipo matrice ................................................................................78
4.3.3. Parametri di tipo struct ...................................................................................78
4.4. Istruzione return e suo uso nelle funzioni .........................................................81
4.5. Introduzione alla programmazione ricorsiva .........................................................82
4.5.1. Induzione e ricorsione ....................................................................................82
4.5.2. Programmazione delle funzioni ricorsive .......................................................83
4.5.3. Gestione a pila degli ambienti locali nelle funzioni ricorsive .........................84
4.5.4. La terminazione delle funzioni ricorsive ........................................................86
4.5.5. Ricorsione multipla ........................................................................................87
4.5.6. Un problema interessante con una semplice soluzione ricorsiva ....................88
4.6. Variabili di tipo funzione e riferimenti a funzioni .................................................90
Capitolo Quinto: Input/Output .............................................................................................92
5.1. I/O attraverso il terminale ......................................................................................92
5.1.1. Acquisizione dati da tastiera ...........................................................................92
5.1.2. Output su video...............................................................................................93
5.1.3. La funzione fprintf ..........................................................................................93
5.2. I/O su file ...............................................................................................................94
5.2.1. Istruzioni load e save ......................................................................................95
5.2.2. Funzione textread ...........................................................................................96
5.2.3. Funzione xlsread .............................................................................................96
5.3. Gestione avanzata dei file ......................................................................................97
5.3.1. Apertura e chiusura di un file .........................................................................98
5.3.2. Lettura e scrittura di dati in modalit binaria ..................................................99
5.3.3. Lettura e scrittura formattata su file ................................................................99
5.3.4. Altre funzioni................................................................................................100

5.3.4.1. Funzione exist ........................................................................................100


5.3.4.2. Funzione feof .........................................................................................100
5.3.4.3. Funzione fseek .......................................................................................100
5.4. Diagrammi ...........................................................................................................101
5.4.1. Diagrammi a due dimensioni ........................................................................101
5.4.1.1. Colori e stili per linee e marcatori .........................................................101
5.4.1.2. Scala logaritmica ...................................................................................102
5.4.1.3. Diagrammi in coordinate polari .............................................................102
5.4.1.4. Esportazione di un grafico come immagine...........................................103
5.4.2. Diagrammi a tre dimensioni .........................................................................104
5.4.2.1. Diagrammi lineari a tre dimensioni .......................................................104
5.4.2.2. Diagrammi tridimensionali a superficie ................................................104
5.4.3. Esempi Riassuntivi .......................................................................................107
Capitolo Sesto: Esercizi .....................................................................................................109
6.1. Equazioni di secondo grado .................................................................................109
6.2. Sistemi di equazioni lineari .................................................................................110
6.3. Sequenze palindrome ...........................................................................................111
6.4. Confronti .............................................................................................................112
6.5. Rotazione matrice ................................................................................................113
6.6. Matrici .................................................................................................................114
6.7. Tariffe telefoniche ...............................................................................................114
6.8. Vettori logici e ordinamenti .................................................................................115
6.9. Matrici logiche misteriose ...................................................................................116
6.10. I caff del dipartimento - matrici logiche ..........................................................118
6.11. Pagella dei film preferiti - dati strutturati ..........................................................120
6.12. Crivello di Eratostene ........................................................................................121
6.13. Elemento pi ripetuto ........................................................................................122
6.14. Costruzione matrici ...........................................................................................122
6.15. Agenzia viaggi - accesso ai file .........................................................................123
6.16. Funzione misteriosa ..........................................................................................124
6.17. Matrice trasposta ...............................................................................................125
6.18. Matrici ...............................................................................................................125
6.19. Ricerca di sequenze in matrici ..........................................................................126
6.20. Immagini in matrici...........................................................................................127
6.21. Scomposizione in fattori ...................................................................................128
6.22. Serie di Fibonacci ..............................................................................................129
6.23. Massimo Comun Divisore .................................................................................130
6.24. Funzione ricorsiva misteriosa............................................................................131
6.25. Funzione ricorsiva misteriosa ...........................................................................133
6.26. Funzione ricorsiva misteriosa............................................................................133
6.27. Funzione di aggregazione generica ...................................................................135
6.28. Calcolo dello zero di una funzione ....................................................................136
6.29. Statistiche meteorologiche ................................................................................137
6.30. Funzione misteriosa di ordine superiore ...........................................................138
6.31. Funzioni di ordine superiore .............................................................................139
6.32. Statistiche esami ................................................................................................140

6.33.
6.34.

Roulette truccata ...............................................................................................142


Paraboloide iperbolico ......................................................................................145

Prefazione
MATLAB (abbreviazione di MATrix LABoratory) uno strumento che nel corso degli
anni ha esteso le sue funzionalit dal calcolo matriciale alle pi generali elaborazioni
numeriche in campo scientifico e tecnico. Esso fornisce comandi, funzionalit predefinite e
un linguaggio di programmazione che ne fa un ambiente per lo sviluppo di applicazioni.
Il linguaggio di programmazione offerto da MATLAB deve il suo successo alla sua
specializzazione nellambito del calcolo numerico. Avendo un obiettivo pi specifico di
altri linguaggi, pu offrire come costrutti del linguaggio stesso operazioni molto potenti (ad
esempio operazioni su intere matrici).
I programmi di MATLAB vengono eseguiti mediante interpretazione: lutente interagisce
con linterfaccia dellinterprete, cui pu far valutare espressioni o eseguire istruzioni e
script; ci permette di evitare la tradizionale sequenza di operazioni tipica dei linguaggi
compilati: scrittura, analisi sintattica e semantica, traduzione, collegamento ed esecuzione;
ci favorisce un approccio esplorativo che permette di passare velocemente dallidea di una
soluzione alla sua implementazione e convalida.
I programmi MATLAB vengono quindi tradotti, allatto esecuzione, in un codice
intermedio interpretato, diverso dal codice macchina direttamente eseguibile dallhardware.
Ci permette di rendere i programmi MATLAB indipendenti dalla piattaforma e quindi
portabili in tutti gli ambienti per i quali MATLAB disponibile (attualmente questi
includono Windows, Linux, Unix, Macintosh).
Daltra parte esiste anche la possibilit di compilare i programmi MATLAB, il che
permette di superare eventuali rallentamenti nellesecuzione dovuti allinterpretazione del
codice intermedio, e di generare applicazioni eseguibili in modo efficiente su una variet di
piattaforme, a prescindere dalla presenza di uninstallazione di MATLAB sulla macchina
che ospita lapplicazione.
Unulteriore importante caratteristica la presenza di semplici e generali funzionalit per
visualizzare grafici e immagini e per creare interfacce grafiche: il programmatore pu cos
ottenere risultati di qualit professionale con uno sforzo assai limitato.
La presente dispensa si focalizza sugli aspetti di programmazione di MATLAB e si rivolge
agli studenti dei corsi di base di informatica nelle facolt tecniche e scientifiche; stata
scritta dal gruppo dei docenti che insegnano informatica nei corsi della Facolt di
Ingegneria Industriale del Politecnico di Milano.
La dispensa offre unintroduzione al linguaggio di programmazione di MATLAB e si
focalizza in particolare su una trattazione dei tipi di dati e delle strutture per gestire il
controllo dellesecuzione dei programmi, della programmazione mediante funzioni, della
gestione dellinput/output (anche su file) e della generazione di diagrammi e grafici. Essa
propone anche un buon numero di esercizi risolti.
Il materiale presentato del tutto autocontenuto; al lettore sono richieste limitate
conoscenze di base in campo informatico. In particolare, la comprensione della parte sulla
gestione del controllo pu essere facilitata da una (pur non indispensabile) familiarit con la
programmazione strutturata in un qualsiasi linguaggio di programmazione ad alto livello.

Capitolo Primo: Introduzione

1.1.

Gli strumenti MATLAB e Octave

MATLAB sta per MATrix LABoratory ed uno strumento specializzato per lesecuzione
di calcoli ingegneristici e scientifici. stato sviluppato allinizio degli anni 80 dalla societ
The MathWorks Inc., fondata dal matematico Cleve Moler insieme a Jack Little, un
ingegnere specializzato in teoria del controllo. Lo scopo di MATLAB era quello di fornire
un ambiente di programmazione di facile utilizzo per lesecuzione di calcoli complessi,
focalizzati, in particolare, sullelaborazione di matrici di dati. Negli anni, lambiente si
evoluto, e al momento offre strumenti per la soluzione di quasi ogni problema tecnico.
MATLAB in grado di eseguire programmi scritti nel linguaggio di programmazione
chiamato con lo stesso nome, ed corredato da un ampio numero di librerie di funzioni
predefinite che semplificano il lavoro di programmazione e migliorano lefficienza del
risultato. Per esempio, il seguente programma:
x = [0:pi/100:pi/2]';
y=sin(x);
[x y]
plot(x,y);

consente in poche linee di codice di:


calcolare e visualizzare sullo schermo la tabella che contiene sulla prima colonna
valori per x che variano tra 0 e /2 e sulla seconda colonna i valori corrispondenti
al seno di x;
visualizzare landamento del seno di x al variare di x come mostrato in Figura 1.
Riprenderemo nella Sezione 1.4 del presente capitolo questo esempio presentandone i
dettagli sintattici. Per il momento ci basti sapere che per svolgere operazioni analoghe in un
linguaggio di programmazione tradizionale quale il C dovremmo utilizzare una complessa
combinazione di istruzioni assai pi elementari e il programma risulterebbe sicuramente pi
lungo e meno leggibile.
Lo strumento MATLAB acquistabile dalla MathWorks Inc (http://www.mathworks.it/).
Esistono vari tipi di licenze. Tra le altre, la Student Version viene offerta agli studenti a un
prezzo ridotto.
A tuttoggi esistono buoni strumenti alternativi a MATLAB che vengono distribuiti come
software libero (pi comunemente chiamato open source) e che possono quindi essere
utilizzati ed estesi gratuitamente. Tra gli altri, citiamo Octave, che stato sviluppato a
partire dallinizio degli anni 90 da John W. Eaton (www.octave.org). Octave in grado di
eseguire programmi scritti nel linguaggio di MATLAB. Inoltre, offre un proprio linguaggio

che presenta piccole differenze sintattiche rispetto a MATLAB. Per semplicit nel seguito
faremo sempre riferimento al linguaggio di MATLAB, ma i programmi che useremo come
esempi potranno essere eseguiti anche con Octave.

Figura 1. Andamento di sin(x) per x che varia da 0 a /2.

1.2. Il linguaggio di programmazione di MATLAB:


caratteristiche generali
MATLAB mette a disposizione un vero e proprio linguaggio di programmazione che
permette di creare, trasformare, visualizzare, e immagazzinare dati complessi. In questo
testo ci focalizziamo sulla presentazione dei principali costrutti di questo linguaggio di
programmazione e sul loro uso per costruire programmi complessi.
MATLAB un linguaggio simile al C nel senso che, come il C, offre la possibilit di creare
dati strutturati, costrutti per modificare il flusso di controllo di un programma (istruzioni di
selezione e cicli), meccanismi di modularizzazione dei programmi (funzioni).
A differenza del C, MATLAB offre anche meccanismi tipici dei linguaggi orientati agli
oggetti che per noi non consideremo (si veda [Register 2007] per una trattazione di questo
aspetto). Altre tre differenze importanti rispetto al C riguardano i seguenti aspetti:
Un programma in MATLAB non deve essere trasformato in codice eseguibile dal
calcolatore. Esso invece viene interpretato direttamente dallambiente MATLAB
(o Octave). Maggiori dettagli sulla differenza e sui vantaggi e svantaggi
dellapproccio interpretato rispetto a quello compilato sono forniti nella Sezione
1.2.1.

In un programma MATLAB non occorre dichiarare le variabili. Esse risultano


definite nel punto in cui vengono utilizzate per la prima volta. Inoltre, il loro tipo
dinamico, nel senso che esso pu cambiare durante lesecuzione del programma
per effetto di assegnamenti di valori che appartengono a tipi diversi. Maggiori
dettagli sui linguaggi dinamici vengono forniti in Sezione 1.2.2.
Mentre il C un linguaggio definito per trattare generici problemi di
programmazione, MATLAB focalizzato sulla trattazione di problemi di natura
numerica e offre meccanismi molto semplici da usare e, al tempo stesso, sofisticati
ed efficienti per il trattamento di array di dati con varie dimensioni.

1.2.1. Linguaggi interpretati e linguaggi compilati


I primi programmi per calcolatori elettronici sono stati scritti direttamente in codice
macchina, nella forma di sequenze di bit riconoscibili dal calcolatore come istruzioni, ma
molto rapidamente i programmatori e i ricercatori hanno riconosciuto lesigenza di definire
linguaggi di programmazione pi facili da capire e da utilizzare da parte degli umani. Le
istruzioni numeriche sono state quindi sostituite da istruzioni scritte in modo pi vicino al
linguaggio naturale e sono stati introdotti costrutti come i cicli (che permettono, tra le altre
cose, di esprimere situazioni del tipo esegui questa istruzione per 10 volte) e le istruzioni
di selezione (che permettono di esprimere situazioni del tipo: se questa condizione vera,
esegui questa istruzioni, altrimenti esegui questaltra istruzione) che sono invece assenti
nel linguaggio macchina.
Chiaramente, tali linguaggi non sono immediatamente comprensibili dal calcolatore che
quindi non in grado di eseguirne direttamente le istruzioni. Per superare questo problema,
sono state ideate due soluzioni alternative.
La prima soluzione quella di trasformare i programmi in codice comprensibile dal
calcolatore prima di tentarne lesecuzione. Questo processo di trasformazione si chiama
compilazione e viene effettuato con lausilio di un programma che si chiama compilatore.
La seconda soluzione invece consiste nellistallare sul calcolatore un programma, chiamato
interprete, che in grado di eseguire direttamente le istruzioni dei programmi scritti nel
linguaggio di programmazione di alto livello attuando, per ogni tipo di costrutto del
linguaggio interpretato, le azioni appropriate.
La compilazione e linterpretazione presentano entrambe vantaggi e svantaggi e, per questo
motivo, non possibile stabilire a priori quale delle due soluzioni sia da preferire. Di solito,
lesecuzione previsa compilazione consente di ottenere programmi che vengono eseguiti
pi velocemente rispetto allinterpretazione perch non richiedono lintermediazione
dellinterprete. Inoltre, lapproccio basato sulla compilazione consente di ottenere un
programma eseguibile che pu essere istallato ed eseguito su un calcolatore
indipendentemente dalla presenza dellinterprete, purch tale programma eseguibile sia
compatibile con il linguaggio macchina del calcolatore in questione.
Lapproccio interpretato invece ha come vantaggio fondamentale una maggiore semplicit
e velocit nella scrittura dei programmi. possibile infatti per il programmatore provare
incrementalmente il programma durante la sua scrittura in modo da verificarne
immediatamente il comportamento. Anche grazie a questa caratteristica, MATLAB viene
ritenuto dai suoi utenti generalmente pi semplice e potente di altri linguaggi classici quali
il C.
Per maggiori dettagli si veda [Ghezzi-Jazayeri 1997].

1.2.2. Linguaggi con tipi dinamici


In generale, si dice che un linguaggio di programmazione supporta un sistema di tipi
dinamico quando la maggior parte dei controlli di coerenza e consistenza sui tipi dei valori
coinvolti nelle espressioni vengono effettuati durante lesecuzione dei programmi (per
maggiori dettagli si veda [Ghezzi-Jazayeri 1997]).
In questo caso, il tipo non viene associato alle variabili (come accade in linguaggi quali il
C) ma ai valori che queste possono assumere. Questo significa che una variabile pu
cambiare tipo nel tempo. Per esempio, in MATLAB possiamo scrivere un programma che
contiene le seguenti istruzioni:
a
b
a
a

=
=
+
=

10;
20.5;
b
stringa;

Dopo le prime due istruzioni sia a che b sono variabili numeriche, che contengono
rispettivamente i valori 10 e 20.5. Si noti che il tipo di a e di b viene determinato da tali
valori. Di conseguenza, il risultato delloperazione a+b sar pari a 30.5. Con lultima
istruzione, a cambia tipo diventando un array (cio una sequenza ordinata) di caratteri.
Questo a causa del fatto che ad a assegnamo il valore stringa. Tale assegnamento, che
non sarebbe legale in C, viene tranquillamente consentito e gestito in MATLAB. Lo spazio
di memoria associato ad a viene dinamicamente modificato per consentire
limmagazzinamento dellarray di caratteri che avr una dimensione di 7 byte (uno per ogni
carattere dellarray) contro gli 8 byte precedentemente occupati dal valore numerico
definito di tipo double.
Nota: la terza istruzione del nostro programma, a differenza delle altre, non stata
terminata con il carattere ;. Non si tratta di un errore, ma di una scelta voluta che ha come
effetto la stampa sullo schermo del risultato del calcolo ( a + b in questo caso).
Ritorneremo su questo aspetto pi avanti, nella Sezione 1.6 di questo capitolo.

Mostra le variabili nel workspace

Contenuto della
directory corrente

Finestra dei comandi

Storia dei comandi


Lancia i tool di MATLAB ed altro

Figura 2. Interfaccia utente di MATLAB.

Figura 3. Interfaccia utente di Octave.

10

1.3.

Interfaccia utente degli ambienti MATLAB e Octave

La Figura 2 e la Figura 3 mostrano rispettivamente le interfacce utente di MATLAB e


Octave. In entrambi i casi, lelemento essenziale la finestra dei comandi che consente di
scrivere ed eseguire i programmi. Oltre a questa finestra, MATLAB fornisce una serie di
finestre e men accessori che consentono di conoscere lo stato di ciascuna variabile, il
contenuto della directory di lavoro, la storia dei comandi eseguiti fino al momento corrente.
Octave non offre direttamente tali finestre, ma, attraverso luso di opportuni comandi,
consente al programmatore di ottenere esattamente le stesse informazioni.
Scrivere programmi direttamente nella finestra dei comandi non comodo soprattutto
perch al termine dellesecuzione dellambiente non si tiene memoria dei comandi digitati.
Per questo motivo, sia MATLAB che Octave offrono un editor, in tutto simile a quello di
un qualsiasi ambiente di programmazione tradizionale, in cui possibile scrivere
programmi (chiamati script) e memorizzarli su file (si vedano le Sezioni 1.4 e 1.6 di questo
capitolo per maggiori dettagli su questo punto). Tali editor possono comunque essere
sostituiti con un qualsiasi altro editor in grado di salvare i programmi in formato testuale.

1.4.

Esempi di comandi in MATLAB

Nei capitoli seguenti di questo testo esamineremo in dettaglio i vari meccanismi di


programmazione offerti dal linguaggio MATLAB. In questa sezione forniamo una
panoramica su alcune istruzioni del linguaggio. Esse ci consentiranno di scrivere i nostri
primi programmi e di prendere confidenza con gli ambienti di programmazione e di
esecuzione che abbiamo a disposizione.
La Errore. L'autoriferimento non valido per un segnalibro. sintetizza alcuni comandi
applicati a valori scalari. Come abbiamo gi accennato, in MATLAB un array rappresenta
lunit fondamentale di dato. Un array una collezione ordinata di valori.
Gli array si distinguono in vettori e matrici. I vettori, come in matematica, sono
monodimensionali. Essi possono essere caratterizzati da una sola colonna oppure da una
sola riga, in cui sono inclusi i valori che li costituiscono. Le matrici possono avere due o
pi dimensioni. Gli scalari sono un tipo particolare di vettori costituiti da una sola riga e
una sola colonna.
Ogni valore numerico in MATLAB viene considerato come un numero reale. Per questo
motivo, a differenza del C, la divisione 1234/6 (si veda la prima riga della Errore.
L'autoriferimento non valido per un segnalibro.) non fornisce come risultato un valore
intero.
Si noti anche che poich il risultato della divisione non viene assegnato esplicitamente ad
alcuna variabile, esso viene automaticamente assegnato da MATLAB alla variabile
predefinita ans. Ci non succede nel caso del comando sulla seconda riga della tabella
perch in questo caso c un assegnamento esplicito alla variabile a. La terza riga mostra
un caso di divisione per zero e la risposta dellinterprete. Esso assegna alla variabile ans il
valore speciale Inf che denota, appunto, linfinito. Si noti luso della variabile predefinita
j nella sesta riga. Essa, insieme alla variabile i, assume il valore

per individuare la parte immaginaria di un numero complesso.

11

1 e viene utilizzata

Comando

Risultato

Commento

1234/6

ans = 205.67

calcolo di un valore scalare

a=1234/6

a = 205.67

assegnamento alla variabile a del risultato


dellespressione 1234/6

5/0

ans = Inf

divisione per zero

5^2

ans = 25

elevamento a potenza

Eps

eps =

variabile predefinita: il pi piccolo valore


possibile

real(4+5j)

ans = 4

real una funzione predefinita che


restituisce la parte reale di un numero
complesso.

1+1==2
1+1~=2

ans = 1
ans = 0

1 = vero, 0 = falso,
== uguale, ~= diverso

2.2204e-16

Tabella 1. Esempi di comandi applicati a valori numerici scalari.


La Tabella 2 mostra alcuni esempi di comandi in cui si utilizzano vettori e matrici. Vettori e
matrici vengono delimitati da una coppia di parentesi quadre (si veda lesempio sulla prima
riga). Le righe vengono separate da ;.
Un aspetto interessante in MATLAB e non presente in molti linguaggi tradizionali con
sistema di tipi statico la possibilit di modificare dinamicamente la dimensione di matrici
e vettori (si veda lesempio sulla quarta riga). Un altro aspetto interessante il gran numero
di operazioni per il calcolo matriciale che MATLAB mette a disposizione. Sulle righe
quinta e settima viene mostrato luso delloperatore che consente di ottenere la matrice
trasposta. Sulla riga sesta c un esempio di uso delloperatore di somma tra matrici. Le
righe ottava, nona e decima mostrano la costruzione di vettori mediante luso delloperatore
:. Oltre ai due valori estremi (riga 8) possibile specificare un passo che pu essere un
qualsiasi valore numerico positivo o negativo. Nel caso il passo non venga specificato,
linterprete lo considera pari a 1. Infine, le righe undicesima e dodicesima mostrano due
diverse operazioni per lelevamento a potenza. La prima unoperazione che coinvolge
lintera matrice. La seconda coinvolge invece i suoi elementi interni ciascuno dei quali,
nellesempio, viene elevato al quadrato. Le due operazioni si differenziano sintatticamente
per la presenza del . che nel secondo caso precede loperatore di elevamento a potenza.

12

Input

Output

a=[1 2; 3 4]

a =
1
3

Commento
a una matrice 2x2, ;
separa le righe

2
4

x=[-1.3 sqrt(3)
(1+2)/5]

x =
-1.30000 1.73205

x(3)=abs(x(1))

x =
-1.30000 1.73205 1.30000

x(5)=4

x =
-1.30000 1.73205 1.30000
0.00000 4.00000

b=a

b =
1
2

3
4

c =
2
5

5
8

c=a+b

x=[-1 0 2]; y=x'

y =
-1
0
2

x=1:5

x =
1

y=0:pi/4:pi

y =
0.00000
2.35619

0.60000

gli elementi di un array


possono essere calcolati
a partire da espressioni;
sqrt calcola la radice
quadrata
x il vettore definito
alla riga precedente;
x(3) permette di
accedere al terzo
elemento del vettore; a
questo si assegna il
valore assoluto (abs) del
primo elemento dello
stesso vettore
il vettore x viene esteso
per includere nuovi
elementi
a la matrice definita
nella prima riga della
tabella; a b viene
assegnata la matrice
trasposta di a
(scambiate righe e
colonne)
a e b sono le matrici
definite precedentemente nella tabella; a c si
assegna la somma di
matrici
il ; blocca loutput,
ma non impedisce
lesecuzione del
comando

operatore : per
produrre vettori di
numeri

0.78540
3.14159

13

1.57080

operatore : con passo


di incremento a valori
non interi (pi
corrisponde a )

v=10:-4:-3

v =
10

-2

valori negativi del passo


(-4) e dellestremo
inferiore (-3)

vuoto=[]

a = [](0x0)

consente di creare un
array di tipo double che
non contiene elementi

a = [1 2; 3 4];
a^2

ans =
7 10
15 22

a = [1 2; 3 4];
a.^2

ans =
1
9

elevamento a potenza
tra matrici;
corrisponde a scrivere
a * a, dove * indica il
prodotto righe per
colonne tra matrici
elevamento a potenza
dei singoli valori della
matrice

4
16

Tabella 2. Esempi di comandi applicati a vettori e matrici.


Un aspetto importante in MATLAB la possibilit di visualizzare landamento di funzioni
mediante grafici o diagrammi. Introduciamo qui i diagrammi a due dimensioni. Una
trattazione pi completa dei diagrammi viene rimandata al Capitolo 5.
Un diagramma un insieme di punti tipicamente congiunti da una linea che serve per dare
continuit al grafico. Ciascun punto in un diagramma bidimensionale caratterizzato da
una coppia di valori che rappresentano le proiezioni del punto sui due assi (ascissa e
ordinata) del diagramma. In MATLAB, si usano due vettori per contenere tutte queste
proiezioni. Tali vettori vengono poi utilizzati dalla funzione predefinita plot che disegna il
diagramma corrispondente.
Esempio: il seguente programma visualizza landamento della funzione x3 per valori di x
che variano tra -10 e 10:
x = -10:0.1:10;
y=x.^3;
plot(x,y);
xlabel('ascisse');
ylabel('ordinate');
title('cubica');

Il grafico ottenuto mostrato in Figura 4. Si noti luso delle funzioni xlabel, ylabel e
title per etichettare lasse delle ascisse (x), delle ordinate (y) e il diagramma stesso.
Unaltra possibilit interessante consiste nel visualizzare sullo stesso grafico pi di una
curva. Per fare questo si utilizzano i comandi hold on e hold off. Il comando hold on
permette di bloccare la visualizzazione dei dati correnti mentre si eseguono altri comandi
sul grafico. Il comando hold off sblocca la visualizzazione.

14

Esempio: Riprendendo lesempio precedente, possiamo complicarlo in modo da


visualizzare sul grafico anche landamento di x2:
x = -10:0.1:10;
y=x.^3;
z=x.^2;
plot(x,y);
hold on
plot(x,z);
hold off
xlabel('ascisse');
ylabel('ordinate');
title('cubica & quadratica');

Si ottiene come risultato il grafico in Figura 5.

Figura 4. Andamento di x3.

15

Figura 5. Visualizzazione nello stesso grafico di x3 e x2.


Avendo introdotto alcuni comandi di MATLAB, possiamo discutere in maggior dettaglio
lesempio riportato nella Sezione 1.1 di questo capitolo. Lo riportiamo qui di seguito per
comodit
x = [0:pi/100:pi/2]';
y=sin(x);
[x y]
plot(x,y);

La prima istruzione crea un vettore colonna che viene assegnato a x. Questo vettore
contiene i valori compresi tra 0 e /2 ottenuti applicando a ciascun valore un incremento
pari a /100. Si noti luso della variabile predefinita pi che rappresenta il e delloperatore
trasposta che, applicato a un vettore riga ci permette di ottenere il vettore colonna
corrispondente.
La seconda istruzione ci permette di ottenere un nuovo vettore colonna che viene assegnato
a y e che contiene i valori di sin(xi) dove gli xi rappresentano i valori contenuti nel vettore
x.
La terza istruzione ci permette di visualizzare sullo schermo una matrice a due colonne in
cui la prima colonna contiene tutti i valori di x e la seconda tutti i valori di y. Da questo
esempio possiamo inferire che per lassegnamento di valori a una matrice possibile
utilizzare non solo valori scalari (come negli esempi in Tabella 2), ma anche vettori.
La quarta istruzione ci permette di ottenere landamento di sin(x) mostrato in Figura 1.

16

1.5.

Script files

Come abbiamo gi accennato, ci sono due modi per scrivere un programma in MATLAB.
Il primo quello di scrivere le istruzioni direttamente nellinteprete comandi dello
strumento utilizzato. Il secondo quello di memorizzare tali istruzioni in un file ottenendo
cos uno script. Nel seguito di questa sezione vedremo come si crea uno script file e come
si utilizza.

1.5.1. Creare uno script


Uno script un semplice file di testo puro, cio senza alcuna forma di formattazione.
pertanto possibile creare uno script file usando qualsiasi editor di testo a disposizione. Le
uniche accortezze per ottenere un risultato corretto sono:
poter salvare il lavoro in modalit testo senza alcuna formattazione
salvare il file con estensione .m
Il primo requisito necessario affinch lo script possa essere correttamente letto e
interpretato da MATLAB. Il secondo requisito invece importante affinch il file venga
automaticamente riconosciuto da MATLAB come uno script, rendendo pi semplice il suo
utilizzo.
Lambiente integrato di MATLAB offre comunque un editor di testo adatto alla creazione e
alla modifica degli script. possibile invocare leditor integrato in MATLAB anche
direttamente dallinterprete, utilizzando il comando edit che ha la seguenti sintassi:
edit nomefile

dove nomefile il nome dello script da editare: se esiste gi verr caricato nelleditor per
poterlo modificare, se invece non esiste verr creato un nuove file e caricato nelleditor per
poterlo editare. Nella scelta del nome da attribuire a uno script importante evitare di
utilizzare dei nomi di funzioni, comandi, variabili, etc., gi presenti in MATLAB. Per
verificare che un nome non sia gi stato usato per una funzione o variabile, si pu utilizzare
la funzione exist:
ris = exist nome

dove nome il nome di cui si vuole verificare la disponibilit, ris il risultato della
ricerca: se il nome non gi in uso, il valore restituito sar zero.
Lesempio seguente mostra lutilizzo della funzione exist.
>> esiste = (exist('abs')~=0)
esiste = 1
>> esiste = (exist('val_assoluto')~=0)
esiste = 0

Nella prima invocazione di exist, il valore restituito diverso da 0 poich si tratta di una
funzione gi esistente in MATLAB. La seconda invocazione invece restituisce un valore
pari a 0, perci il nome non gi in uso.

1.5.2. Eseguire uno script


Uno script pu essere eseguito semplicemente invocandone il nome (senza specificare
lestensione .m) tramite linterprete dei comandi MATLAB. Nel caso il nome dello script
non avesse estensione .m, dovr essere invocato specificando il nome del file per intero.

17

Inoltre, per poter essere eseguito dallinterprete, lo script dovr necessariamente trovarsi in
uno dei seguenti posti:
la directory corrente;
in una delle directory di sistema in cui linterprete cerca gli script che vengono
1
invocati .

1.5.3. Struttura di uno script


Sebbene non vi sia alcun vincolo riguardo la struttura che uno script deve avere,
comunque buona norma seguire alcune linee guida. In particolare, uno script ben strutturato
dovr avere la seguente struttura:
i.
Commento di intestazione
ii.
Sezione di input
iii.
Sezione di calcolo
iv. Sezione di output
Commento di intestazione. Il commento di intestazione ha lo scopo di fornire quante pi
informazioni possibili sullo script, per facilitarne luso senza la necessit di analizzarne in
dettaglio il contenuto. Generalmente, vengono fornite alcune informazioni riguardo lo
script: informazioni sugli autori, data, nome dello script e breve descrizione dello script
stesso. Infine, occorre specificare con attenzione quali sono le variabili di input e output
nello spazio di lavoro (qualora siano presenti). Limportanza di un buon commento iniziale
2
risiede anche nel fatto che esso viene stampato quando si utilizza il comando help per
ottenere informazione su uno script.
Sezione di input. Questa sezione ha come scopo quello di predisporre i dati che verranno
usati nelle elaborazioni successive. La fase di acquisizione dati pu avvenire in molti modi:
tramite linserimento di informazioni da tastiera, tramite lettura di un file oppure attraverso
laccesso a una o pi variabili nello spazio di lavoro.
Sezione di calcolo. Questa sezione il cuore dello script, dove avviene la vera e propria
elaborazione dei dati: questa sezione contiene le istruzioni che lo script deve svolgere per
ottenere il risultato desiderato.
Sezione di output. Questa sezione ha come scopo quello di memorizzare o visualizzare i
risultati dello script. Come per il caso dellacquisizione di informazione in ingresso, anche
in questo caso la fase di salvataggio pu avvenire in diversi modi: tramite la stampa di
informazioni a video, tramite la scrittura di un file oppure attraverso la scrittura di una o pi
variabili nello spazio di lavoro.

Nella configurazione dellambiente integrato possibile specificare in quali directory


linterprete dovr cercare gli script, in modo da facilitarne larchiviazione.
2
Il comando help seguito dal nome di uno script file mostra a video il commento di
intestazione contenuto nello script stesso. Perci opportuno utilizzare tale spazio per
descrivere il funzionamento dello script.

18

1.6.

Linee guida iniziali per la programmazione in MATLAB

La breve presentazione di alcuni comandi MATLAB di uso comune dovrebbe aver messo
in evidenza la potenza e lespressivit del linguaggio. Nonostante il programmatore abbia a
disposizione diverse possibilit per svolgere uno stesso compito, noi forniamo i seguenti
suggerimenti che hanno come scopo quello di aiutare nella costruzione di programmi facili
da capire, da modificare e da riutilizzare in contesti diversi:
Preferiamo la scrittura di programmi in opportuni script invece che direttamente nella
finestra dellinterprete comandi. Essendo MATLAB un linguaggio interpretato, ci stimola
allutilizzo di un approccio di programmazione che viene chiamato in Inglese trial and
error. Tendiamo cio a procedere per tentativi sperimentando luso dei vari comandi man
mano che si rendono necessari. Questa tendenza ci porta a scrivere un programma per
frammenti che riportiamo direttamente nella finestra dellinterprete comandi. Eseguire
questi tentativi sicuramente utile, ma bene ricordare che i comandi che abbiamo digitato
vengono persi nel momento in cui terminiamo lesecuzione dellinterprete. quindi
opportuno, una volta compreso come utilizzare le istruzioni che sono necessarie,
consolidare il programma nella sua struttura e dare una forma definitiva alle sue istruzioni
scrivendole in uno script che potr essere usato pi e pi volte.
Commentiamo i nostri programmi soprattutto per quello che riguarda 1) lo scopo del
programma e 2) il modo con cui si intende utilizzare le sue principali variabili. Come
qualsiasi altro linguaggio di programmazione, MATLAB consente linserimento di
commenti allinterno dei programmi. I commenti non vengono interpretati durante
lesecuzione del programma e sono a esclusivo beneficio dei programmatori. Dal punto di
vista sintattico un commento inizia dal simbolo % e termina alla fine della riga corrente. Nel
caso in cui il commento occupi pi linee, ciascuna linea deve iniziare con il simbolo % Il
simbolo % pu essere messo in qualsiasi punto della linea, per esempio:
% Questo e` un commento
x = 2+3 % Questo e` un altro commento

Listruzione x = 2+3 sulla seconda riga viene eseguita normalmente, mentre quanto segue
il simbolo % viene ignorato in fase di esecuzione.
Usiamo il simbolo ; al termine di ciascuna istruzione a meno che non vogliamo
visualizzare sullo schermo loutput dellistruzione. Come abbiamo gi detto, le istruzioni in
MATLAB possono essere seguite da ; ma questo non obbligatorio. Il ; blocca la
visualizzazione delloutput dellistruzione e determina una maggiore velocit di esecuzione
del programma (in tutti i linguaggi di programmazione luso di una periferica per procedere
alla visualizzazione di un risultato unattivit dispendiosa rispetto allesecuzione di
semplici istruzioni di trasformazione dei dati). Per questo motivo buona regola terminare
ogni istruzione con un ;.
Evitiamo di abusare della dinamicit del linguaggio. Abbiamo visto che MATLAB un
linguaggio a tipizzazione dinamica. Questo in pratica significa che in un programma
possiamo riutilizzare la stessa variabile assegnando a essa valori di tipi diversi. Spesso, il
cambiamento di tipo di una variabile corrisponde a un suo cambiamento di uso. Per
esempio, la variabile che prima veniva usata per contenere i valori delle ascisse di un
grafico pu essere successivamente utilizzata per contenere uno scalare che rappresenta il
massimo tra tali valori. Questo, se da un lato fornisce una notevole flessibilit, dallaltro
pu essere fonte di errori e sicuramente rende il nostro programma difficile da capire e
quindi anche da correggere. Cerchiamo quindi di non riutilizzare la stessa variabile per

19

scopi diversi o, se dobbiamo riutilizzarla, per esempio, perch abbiamo necessit di


risparmiare risorse di memoria, assicuriamoci di inserire commenti chiari e inequivocabili
che ci permettano di ricordare il motivo di questa scelta anche nel futuro.
Usiamo lhelp per ottenere informazioni sui comandi e le funzioni utilizzabili. MATLAB
un linguaggio ricco di comandi e funzioni che possiamo utilizzare per gli scopi dei nostri
programmi. Il comando help seguito da un nome di istruzione o di funzione fornisce in
risposta indicazioni sullo scopo e sullutilizzo della funzione/istruzione in questione. Luso
dellhelp pu essere coadiuvato dalluso del comando lookfor che permette di individuare
quelle istruzioni o funzioni che contengono nel loro nome o nella loro descrizione una certa
stringa. Per esempio, digitando nella finestra dellinterprete comandi lookfor str, si
ottengono i nomi di un gran numero di operazioni relative alla trasformazione e
visualizzazione di sequenze di caratteri.

1.6.1. Un esempio di cinematica


Per sintetizzare quanto abbiamo presentato in questo capitolo consideriamo il seguente
problema.
Due treni partono da due stazioni adiacenti, che distano 15 km, viaggiando rispettivamente
a una velocit di 50 m/s e 30 m/s in direzione opposta. Si costruisca il grafico che mostra il
loro movimento, fino a quando il pi veloce raggiunge la propria destinazione.
Per ottenere la soluzione consideriamo che il treno pi veloce impiega 300 s per
raggiungere la sua destinazione (15000/50=300s). La distanza che esso ha percorso
allistante t calcolabile nel modo seguente:
distanzaTreno1=50t

Allo stesso istante t, la distanza percorsa dal secondo treno nella direzione opposta (dalla
stazione che si trova a 15 km verso la stazione di origine del primo treno) sar:
distanzaTreno2=15000-30t;

Il grafico che rappresenta il movimento dei treni potr quindi essere visualizzato ponendo
sulle ascisse il tempo t che varia tra 0 e 300 s (tempo necessario perch il primo treno arrivi
alla sua destinazione) e sulle ordinate la distanza percorsa che varia tra 0 e 15000 m.
Sviluppiamo il programma come uno script che memorizziamo in un file chiamato
treni.m.
%t e` un vettore che contiene i valori delle ascisse
t=0:1:300;
% distanzaTreno1 e` un vettore che contiene i valori
% delle ordinate per il movimento del primo treno
distanzaTreno1=50 * t;
% distanzaTreno2 e` un vettore che contiene i valori
% delle ordinate per il movimento del secondo treno
distanzaTreno2=15000-30* t;
plot(t,distanzaTreno1);
hold on
plot(t,distanzaTreno2)
hold off

20

Eseguendo lo script otteniamo il grafico in Figura 6.

Figura 6. Andamento del movimento dei due treni nel tempo.

1.7.

Materiale per approfondimenti

Su MATLAB stato pubblicato materiale in varie forme (articoli, libri, tutorial). Molto di
questo materiale si focalizza sugli aspetti matematici e di calcolo numerico del linguaggio
(si vedano per esempio, [Moler 2004] e [Moler 2008], entrambi disponibili anche in
formato elettronico su Internet:
http://www.mathworks.com/moler/?s_cid=0808_dmlg_moler_395268)
In [Chapman 2009] invece MATLAB viene presentato come un linguaggio per la
programmazione. Il testo [Chapman 2009] pu essere utilizzato per approfondire vari
aspetti della programmazione che noi in questo libro accenneremo soltanto o non
tratteremo.
Altre fonti di informazione possono essere trovate sul sito web della MathWorks e su
quello di Octave.

1.8.

Bibliografia

[Chapman 2009] Stephen J. Chapman. MATLAB Programming for Engineers (Fourth


Edition). Thomson 2009.
[Ghezzi-Jazayeri 1997] Carlo Ghezzi and Mehdi Jazayeri. Programming Language
Concepts (Third Edition). Wiley & Sons. 1997.
[Moler 2008] Cleve Moler. Experiments with MATLAB. The MathWorks. 2008.
[Moler 2004] Cleve Moler. Numerical Computing with MATLAB. SIAM. 2004.
[Register 2007] Andy H. Register. A guide to MATLAB Object-Oriented Programming.
Taylor & Francis Ltd 2007.

21

Capitolo Secondo: Variabili e tipi di dati

Le variabili rappresentano i dati su cui lavora un programma. Esse sono denotate mediante
un nome, comunemente chiamato identificatore. Le variabili corrispondono a locazioni di
memoria e ciascuna, oltre a un identificatore, ha un tipo, cio l'insieme dei valori e delle
operazioni ammissibili, una dimensione, un indirizzo e un valore. In questo capitolo
approfondiremo il concetto di variabile e analizzaremo alcuni tipi di variabili utilizzabili in
MATLAB.

2.1.

Variabili

Una variabile un elemento di memoria che contiene valori che possono cambiare durante
lesecuzione del programma. Nei linguaggi a tipizzazione forte come il C, le variabili
devono essere dichiarate prima del loro utilizzo. Nella fase della dichiarazione, deve inoltre
essere indicato in modo esplicito il tipo dei dati che esse conterranno.
In MATLAB una variabile, durante la vita del programma, pu contenere dati di tipo
diverso. Si dice che il suo tipo pu variare dinamicamente. Lesistenza della variabile viene
riconosciuta dallinterprete del linguaggio nel momento del suo primo utilizzo. Non si
distingue quindi tra la fase di dichiarazione e la fase di uso della variabile stessa.
Ogni variabile ha un nome definito dal programmatore. Tale nome deve iniziare con una
lettera seguita da qualsiasi sequenza di lettere, numeri e caratteri underscore _. Si possono
utilizzare fino a 63 caratteri per il nome di una variabile. Eventuali altri caratteri vengono
ignorati.
Una variabile contiene un array che rappresenta lunit fondamentale di dato in MATLAB.
Un array una collezione ordinata di valori. Gli array si distinguono in vettori e matrici. I
vettori sono monodimensionali. Essi possono essere caratterizzati da una sola colonna
oppure da una sola riga che contiene i valori che la costituiscono. Le matrici possono avere
due o pi dimensioni. La Tabella 3 mostra alcuni esempi di variabili. In particolare, le
istruzioni nella prima colonna servono tutte per assegnare un array a una variabile.
Istruzione MATLAB
x = [4,-9,25]

Spiegazione
x un vettore riga contenente tre valori

y = [1, 2; 3, 4; 5, 6]

y una matrice composta da tre righe e due colonne

z = [1.2; 4; 3.2; 5]

z un vettore colonna contenente 4 valori

k = 12

k una matrice con una riga e una colonna (uno


scalare)

Tabella 3. Esempi di variabili.

22

Il comando whos permette di conoscere le informazioni principali su una variabile. Per


esempio, se dopo aver eseguito i comandi presenti in Tabella 3 si esegue il comando whos
z, si ottiene il risultato mostrato qui di seguito:
>> whos z
Name

Size

4x1

Bytes
32

Class

Attributes

double

In questo caso la risposta ci permette di stabilire che z un vettore colonna (un array di 4
righe e 1 colonna) di 32 byte con elementi di tipo double, ognuno dei quali occupa 8 byte.

2.1.1. Tipi double e char


I tipi pi comuni per una variabile sono double e char.
Una variabile di tipo double contiene uno scalare o un array di numeri espressi in 64 bit
con doppia precisione. Questi numeri possono essere reali, immaginari o complessi. Le
parti reali e immaginarie possono essere positive o negative nellintervallo [10 -308, 10308],
con accuratezza di 15-16 cifre decimali. La Tabella 4 mostra alcuni esempi. In tutti i casi
mostrati il comando whos ci informer che il tipo dei dati double.
Istruzione

Nota
scalare reale

var1 = -10.7;
var2 = 4i; var3 = 4j;

due scalari immaginari. Si noti luso indifferente di i e j


per indicare lo stesso valore (radice quadrata di -1)

var3 = 10.3 + 10i;

scalare complesso

x = [-1.3

3.1+5.3j

0]

vettore contenente valori reali e complessi

Tabella 4. Esempi di variabili scalari e array di tipo double.


Una variabile di tipo char contiene uno scalare o un array di valori a 16 bit, ciascuno dei
quali rappresenta un carattere. Tale array viene chiamato anche stringa. Per esempio,
lesecuzione delle seguenti istruzioni:
commento = 'questa e` una stringa';
whos commento;

genera il seguente risultato:


Name
commento

Size
1x21

Bytes Class Attributes


42
char

poich in questo caso commento una stringa di 21 caratteri. Si noti come nella fase di
assegnamento sia necessario racchiudere la sequenza di caratteri tra apici semplici.

2.1.2. Linee guida per la definizione dei nomi di variabili


Come abbiamo gi detto, i nomi delle variabili vengono definiti dal programmatore e
possono contenere sequenze di lettere, numeri e caratteri underscore.
In generale, sempre opportuno usare nomi di variabili che siano significativi. Questo
consente anche ad altri programmatori di capire il ruolo di una certa variabile nel
programma e quindi migliora la leggibilit e la modificabilit dello stesso programma. Per

23

esempio, se una variabile rappresenta il peso specifico del piombo, sar opportuno
chiamarla pesoSpecificoPb invece che semplicemente x.
altrettanto importante ricordare che nomi di variabili troppo lunghi possono provocare
seri problemi: se i nomi di due variabili che intendiamo essere distinte hanno tutti i primi
63 caratteri uguali, essi saranno considerati corrispondenti alla stessa variabile.
MATLAB, come anche altri linguaggi quali il C, distingue tra lettere maiuscole e
minuscole (si dice che case sensitive). Questo significa che i nomi pesoSpecificoPb e
PesoSpecificoPb vengono considerati due nomi diversi appartenenti quindi a variabili
distinte tra loro. Per evitare di compiere errori, opportuno definire e utilizzare opportune
convenzioni. Per esempio, una convenzione molto utilizzata in linguaggi quali Java e C
quella di iniziare tutti i nomi di variabili con una lettera minuscola e di separare le parole di
cui composto il nome mediante lettere maiuscole (come in pesoSpecificoPb). Unaltra
convenzione molto comune consiste nellutilizzare il carattere _ come separatore tra le
varie parole (per esempio, peso_specifico_pb). Ovviamente, lo svantaggio di
questultima convenzione sta nel fatto che necessario introdurre nel nome della variabile
un numero maggiore di caratteri rispetto al caso della prima convenzione. Qualsiasi sia la
convenzione che si decide di utilizzare, sempre opportuno usarla in modo coerente allo
scopo di evitare errori banali ma spesso di difficile identificazione.
Sappiamo gi che in MATLAB non necessario dichiarare le variabili utilizzate in un
programma. Se da un lato questo rende il linguaggio molto flessibile, dallaltro rende i
programmi di pi difficile interpretazione da parte dei programmatori. Per questo motivo
opportuno definire per le variabili principali un dizionario da inserire allinizio del
programma. Questo dizionario viene inserito come un commento e non viene quindi
utilizzato dallinterprete del programma, ma pensato per far capire ai programmatori
quale sia il significato delle variabili utilizzate.

2.1.3. Creazione e inizializzazione di una variabile


Le variabili sono create al momento dellinizializzazione. La loro dimensione in memoria
pu crescere nel tempo. Anche il loro tipo, come abbiamo gi detto, pu variare nel tempo.
Esempio
>> a = [1 2 3 4];
>> whos a
Name
Size
a
1x4
>> a(5) = 5;
>> whos a
Name
Size
a
1x5
>> a = 3;
>> whos a
Name
Size
a
1x1
>> a = 'c';
>> whos a
Name
Size
a
1x1

Bytes
32

Class
double

Attributes

Bytes
40

Class
double

Attributes

Bytes
8

Class
double

Attributes

Bytes
2

Class
char

Attributes

24

Lesempio mostra levoluzione della variabile a. Il primo assegnamento la crea come una
variabile vettore di tipo double di quattro posizioni. Il secondo ne determina la crescita in
termini di numero di posizioni. Il terzo la trasforma in uno scalare di tipo double. Il quarto
cambia il tipo della variabile che diventa uno scalare di tipo char. Si noti che mentre in
MATLAB un char occupa 2 byte in Octave occupa 1 byte.
Una variabile pu essere inizializzata in quattro modi: assegnamento, uso di funzioni
predefinite, lettura dati da tastier, lettura da file

2.1.3.1. Assegnamento
La sintassi per lassegnamento la seguente: variabile = espressione
Lespressione pu coinvolgere scalari, array, altre variabili, costanti, simboli matematici,
funzioni. Abbiamo gi visto alcuni esempi di assegnamento. In Tabella 5 ne mostriamo altri
che consentono di mettere in rilievo alcune peculiarit nel trattamento degli array.
Esempi di
assegnamento

Risultato

Note

a = [0 7+1];

[0 8]

Gli operatori matematici


utilizzati negli assegnamenti

b = [a(2) 5 a];

[8 5 0 8]

Lutilizzo dellarray a (definito nella riga 1)


nellassegnamento di b ha un impatto sulla
dimensione di b oltre che sui suoi valori

g = b;

[8
5
0
8]

Loperatore consente di ottenere la trasposta di


un array. In questo esempio b il vettore
definito alla riga 2

x = 1:2:10;

[1 3 5 7 9]

Loperatore : consente di costruire in modo


sintetico un array di valori crescenti o
decrescenti

m = [x x];

1
3
5
7
9
3
3
3
3

1
3
5
7
9
3
3
3
3

Matrice 5 x 2 ottenuta da due vettori 5 x 1. In


questo esempio x il vettore definito alla riga 4

3
3
3
3

n(1:2, 2:3) =
4;

3
3
3
3

4
4
3
3

4
4
3
3

c(2, 3) = 5

0
0

0
0

0
5

n(1:4, 1:3) =
3;

possono

essere

A sinistra dellassegnamento viene specificata la


forma dellarray, in questo caso una matrice con
4 righe e 3 colonne. Il valore a destra
assegnato a tutti gli elementi dellarray.
Lassegnamento si applica anche a porzioni di
array (sottoarray). n larray definito alla riga
precedente. Si assegna il valore 4 al sottoarray
che include le prime 2 righe e le colonne 2 e 3.
Gli elementi non specificati alla creazione
dellarray assumono il valore 0.

Tabella 5. Esempi di assegnamento.

25

2.1.3.2. Assegnamento mediante luso di funzioni predefinite


MATLAB offre una serie di funzioni predefinite che consentono di creare array speciali.
Un esempio la funzione zeros di cui si mostrano alcuni esempi di uso:
Funzione

Risultato

Commento

a = zeros(2);

0 0
0 0

zeros con un solo parametro crea una

b = zeros(2,3);

0 0 0
0 0 0

Il primo parametro il numero delle righe, il


secondo il numero delle colonne

c = [1 2; 3 4; 5 6];

1 2
3 4
5 6

size restituisce la dimensione di un array.

d = zeros(size(c));

0 0
0 0
0 0

matrice quadrata della dimensione specificata

Tale funzione pu essere usata per creare un


array di 0 della stessa dimensione dellarray a
cui si applica size. size(c) consente di
ottenere il numero di righe e colonne di c.
Tali valori vengono assegnati a zeros che
genera la matrice 3x2 assegnata a d

Nella Tabella 6 includiamo una sintesi di funzioni predefinite utili per la creazione di array.
Funzione

Significato

zeros (n)

Genera una matrice nxn di zeri

zeros (m,n)

Genera una matrice mxn di zeri

zeros (size(arr))

Genera una matrice di zeri della stessa dimensione di arr

ones(n)

Genera una matrice nxn di uno

ones(m,n)

Genera una matrice mxn di uno

ones(size(arr))

Genera una matrice di uno della stessa dimensione di arr

eye(n)

Genera la matrice identit nxn

eye(m,n)

Genera la matrice identit mxn

length(arr)

Restituisce la dimensione pi lunga.

size(arr)

Restituisce due valori: il numero di righe e colonne dellarray

Tabella 6. Funzioni per la creazione di array.

26

2.1.3.3. Inizializzazione mediante lettura dati da tastiera


La lettura di dati da tastiera pu avvenire in modo semplice mediante la funzione input. Se
per esempio scriviamo il seguente comando:
valore = input('inserisci un valore');

MATLAB stampa a video la stringa inserisci un valore e aspetta di ricevere un dato. Tale
dato pu essere: un valore scalare, un array racchiuso tra parentesi quadre [], una stringa
racchiusa tra apici semplici .
Il dato inserito da tastera viene memorizzato nella variabile valore. Nel caso in cui
lutente inserisca semplicemente il carattere di invio (carriage return), valore verr
inizializzato con un array vuoto, un array cio di tipo double ma di dimensioni 0x0, che
occupa 0 byte.
Input pu anche ricevere due parametri come nel seguente esempio:
valore2 = input('inserisci un valore', 's');

In questo caso, qualsiasi valore venga inserito dallutente via tastiera viene considerato
come una stringa. Se per esempio lutente inserisce la sequenza di caratteri 1234, valore2
diventer un array di caratteri che contiene la stringa 1234. Si noti che nel caso lutente
scriva la sequenza 'prova', in questo caso, gli apici andranno a fare parte dellinsieme di
caratteri che vengono memorizzati in valore2. Di conseguenza, il comportamento delle
due istruzioni:
valore = input('inserisci un valore');
valore2 = input('inserisci un valore', 's');

diverso. Nel caso della prima istruzione, se lutente vuole fare in modo che venga
acquisita la stringa prova deve scrivere 'prova'. Nel caso della seconda istruzione,
invece, egli deve limitarsi a scrivere esclusivamente prova.

2.1.3.4. Inizializzazione mediante lettura dati da file


Ci sono vari modi per caricare nelle variabili di MATLAB i dati che si trovano su file. Per
una trattazione pi completa su questo argomento si rimanda al Capitolo 5, Sezione 2. Qui
diciamo solo che MATLAB distingue tra file scritti nel suo formato proprietario (essi
hanno lestensione .mat), file di testo e file in altri formati generati da applicazioni quali ad
esempio i fogli elettronici. Il comando pi semplice per caricare dati da file si chiama load.
Esso pu essere applicato a file che seguono il formato specifico di MATLAB oppure a file
di testo. Nel primo caso, pu essere usato nei modi seguenti:
load 'nomefile' carica nello spazio di lavoro tutte le variabili i cui valori si
trovano nel file chiamato nomefile.mat.
load 'nomefile' <lista nomi di variabili> carica nello spazio di

lavoro solo le variabili il cui nome appare nella lista, se queste si trovano nel file
chiamato nomefile.mat.
Nel caso di file di testo, il comando load 'nomefile.estensione': crea una variabile
di nome nomefile che conterr i dati in nomefile.estensione. Il file deve contenere
dati separati da virgole o spazi. Lestensione pu essere qualsiasi, ma suggeriamo di
utilizzare sempre la stessa convenzione (per esempio, lestensione .dat oppure .txt) per
evitare confusioni.

27

2.1.4. Variabili predefinite (costanti)


MATLAB definisce un insieme di variabili il cui valore predefinito. Un esempio la
variabile pi che corrisponde al numero irrazionale . Queste variabili spesso rappresentano
concettualmente delle costanti. importante notare per che MATLAB, considerandole
come variabili, ne consente la modifica. Se per esempio si scrive il seguente frammento di
codice:
pi = 6;
circonferenza=2*pi*10;

il valore di circonferenza non corrisponder pi alla reale circonferenza del cerchio di


raggio 10, ma al valore 120.
Di conseguenza, fortemente sconsigliato modificare il valore di una variabile
predefinita.
La Tabella 7 include le variabili predefinite principali.
Variabile

Scopo

pi

contiene 15 cifre significative di

i, j

contiene il valore ( -1)

inf (o Inf)

rappresenta linfinito (ottenuto di solito come risultato di una


divisione per 0)

nan

not-a-number il risultato di una operazione matematica non


definita, es 0/0

clock

contiene la data e lorario corrente. E` un vettore di sei elementi


(anno, mese, giorno, ora, minuti, secondi)

date

contiene la data corrente sotto forma di stringa

eps

la pi piccola differenza rappresentabile tra due numeri


(epsilon)

ans

contiene il risultato della valutazione di unespressione dalla


linea di comando quando questo non viene assegnato ad alcuna
variabile, e.g.: >>3*2 fa s che ans=6

Tabella 7. Variabili predefinite.

28

2.2.

Scalari

Abbiamo detto che in MATLAB ogni variabile contiene un array. Uno scalare un tipo
particolare di array costituito da un unico elemento. Abbiamo anche detto che listruzione
variabile = espressione

consente di assegnare a variabile il risultato del calcolo dellespressione a destra


dellassegnamento.
Fra le operazioni definite per gli scalari vi sono le operazioni aritmetiche. Esse includono
laddizione (simbolo +), la sottrazione (simbolo -), la moltiplicazione (simbolo *), la
divisione (simbolo /), lelevamento a potenza (simbolo ^).
Per esempio, le istruzioni:
a = 10;
x = (a + 3*a)^2;

assegnano a x il valore 1600.

2.3.

Array

Gli array in MATLAB possono avere una o pi dimensioni. Laccesso ai singoli elementi
di un array x avviene indicando tra parentesi tonde il numero o i numeri che corrispondono
alla posizione desiderata nellarray.

Esempio: Si considerino i seguenti array,


a1 = [1 2 3 4];
a2 = [1 2 3 4; 3 4 5 6];

Il primo un vettore riga composto da quattro elementi, mentre il secondo una matrice di
2 righe per 4 colonne. Date queste due definizioni, possibile svolgere le seguenti
operazioni:
Operazione

Risultato

Commento

a1(1) = a1(3);

a1 = [3 2 3 4]

il valore dellelemento in terza posizione in


a1 viene assegnato alla posizione 1 dello
stesso array

a1(2) = a2(2,3);

a1 = [3 5 3 4]

il valore dellelemento di riga 2 e colonna 3


in a2 viene assegnato alla posizione 2 di a1

a1(3) = a2(6);

a1 = [3 5 5 4]

uso della forma linearizzata di a2 (vedi la


spiegazione nel testo)

Mentre nella seconda operazione si identifica lelemento della matrice a2 attraverso i suoi
indici di riga e colonna, nella terza operazione si utilizza un unico indice. In questultimo
caso, si accede alla matrice nella sua forma linearizzata. La matrice viene cio vista come
un vettore. In genere, data una matrice matr di dimensioni n x m, i primi n elementi della
sua rappresentazione linearizzata corrisponderanno agli elementi posizionati nella prima
colonna della matrice (gli elementi matr(k, 1), con k variabile tra 1 e n), i successivi n

29

elementi corrisponderanno agli elementi posizionati nella seconda colonna (gli elementi
matr(k, 2), con k variabile tra 1 e n), e cosi via fino allultima colonna. In base a quanto
detto, il sesto elemento della forma linearizzata di a2 corrisponde allelemento di riga 2 e
colonna 3. Si noti che ogni matrice viene immagazzinata nella memoria del calcolatore
nella sua forma linearizzata. Nella programmazione in MATLAB (come anche in altri
linguaggi di programmazione) possibile usare indifferentemente la forma linearizzata e
quella classica.
Nella definizione di un array gli elementi appartenenti a una certa riga possono essere
separati da spazi (come abbiamo visto negli esempi precedenti) oppure da virgole. Per
esempio, le seguenti definizioni sono tra loro equivalenti:
matrice = [1 2 3; 5 6 7; 8 7 6];
matrice = [1, 2, 3; 5, 6, 7; 8, 7, 6];

2.3.1. Operazioni principali per vettori e matrici


Le operazioni tra array in MATLAB si dividono in due categorie, quelle chiamate array
operations e quelle chiamate matrix operations.
Le array operation vengono eseguite sugli elementi degli array coinvolti che si trovano
nelle stesse posizioni. Le array operation sono applicabili solo ad array con lo stesso
numero di righe e colonne. Per esempio, avendo definito le variabili a e b nel modo
seguente:
a = [1 2; 3 4];
b = [2 3; 5 7];

possibile sommarle ottenendo il seguente risultato:


c = a+b
c =
3
8

5
11

e moltiplicarne gli elementi a coppie ottenendo il seguente risultato:


d = a.*b
d =
2
15

6
28

Le matrix operation seguono le regole dellalgebra lineare. Per esempio, la moltiplicazione


tra due matrici a, di dimensioni H x K, e b, di dimensioni K x M, risulta in una matrice,
chiamiamola e, di dimensioni H x M i cui elementi vengono calcolati secondo la formula:
e[h][m] =(a[h][k]*b[k][m]), con k = 1, ..., K

Se a e b sono le matrici definite nellesempio precedente, lapplicazione della matrix


operation di moltiplicazione ci permette di ottenere il risultato mostrato qui sotto:
e = a*b
e =
12
26

17
37

Si noti la differenza sintattica tra le array e matrix operation di moltiplicazione. In generale,


nei casi in cui sono definiti entrambi i tipi di operazioni, nellarray operation loperatore
viene preceduto da un punto. La Tabella 8 mostra le array e matrix operation pi tipiche.

30

Operazione

Sintassi
MATLAB

Commenti

Array addition

a + b

Array e matrix addition sono identiche

Array subtraction

a b

Array e matrix subtraction sono identiche

Array multiplication

a .* b

Ciascun elemento del risultato pari al


prodotto degli elementi corrispondenti
nei due operandi

Matrix multiplication

a * b

Prodotto di matrici

Array right division

a ./ b

risultato(i,j)=a(i,j)/b(i,j)

Array left division

a .\ b

risultato(i,j)=b(i,j)/a(i,j)

Matrix right division

a / b

a*inversa(b)

Matrix left division

a \ b

inversa(a)*b

Array exponentiation

a .^ b

risultato(i,j)=a(i,j)^b(i,j)

Tabella 8. Array e matrix operation.


Analizzando la Tabella 8 notiamo uninteressante operazione, la matrix left division.
Questa operazione serve per risolvere sistemi di equazioni lineari. Si consideri il sistema:
a11x1+a12x2+a13x3=b1
a21x1+a22x2+a23x3=b2
a31x1+a32x2+a33x3=b3

Esso pu essere espresso come:


Ax=B

dove A la matrice che contiene tutti i coefficienti alm del sistema, x il vettore colonna
che contiene le tre incognite xk, e B il vettore colonna che contiene i coefficienti bk.
Risolvendo, abbiamo
x = A-1B = inversa(A)*B = A\B.
In altre parole, dalla conoscenza degli array A e B in MATLAB possibile risolvere il
sistema di equazioni utilizzando come unica operazione la matrix left division.

31

2.3.2. Altre funzioni utili


Oltre alle operazioni aritmetiche e algebriche che abbiamo visto nelle sezioni precedenti,
MATLAB offre molte funzioni aggiuntive che consentono di operare sugli scalari e sugli
array. La Tabella 9 ne mostra alcune che utilizzeremo pi avanti negli esempi.
Funzione

Scopo

ceil(x)

Ceiling = soffitto. Approssima x allintero immediatamente


maggiore cio al pi piccolo intero x. Se x un array, tale
approssimazione viene effettuata per ciascuno degli elementi di x.

floor(x)

Floor = pavimento. Approssima x allintero immediatamente


minore cio al pi grande intero x. Se x un array, tale
approssimazione viene effettuata per ciascuno degli elementi di x.

fix(x)

Approssima x allintero pi vicino verso lo zero. Se x un array,


tale approssimazione viene effettuata per ciascuno degli elementi
di x.

round(x)

Approssima x allintero pi vicino. Se x un array, tale


approssimazione viene effettuata per ciascuno degli elementi di x.

max(x)

Restituisce il valore massimo nel vettore x e, opzionalmente, la


collocazione di questo valore in x.

min(x)

Restituisce il valore minimo nel vettore x e, opzionalmente, la


collocazione di questo valore nel vettore .

mod(x,y)

Restituisce il modulo di x e y che viene definito come x - y .*


floor (x ./ y) per y ~= 0 .

rand(N)

Genera una matrice di NxN numeri casuali compresi tra 0 e 1.

Tabella 9. Alcune funzioni interessanti che operano su array.


2.3.3. Array multidimensionali
Per completezza, anche se non useremo questo meccanismo nel seguito, vediamo come
definire un array con pi di due dimensioni. Il meccanismo si basa sul fatto che ogni
dimensione identificata da un indice (chiamato subscript). Per esempio, le istruzioni:
c(:, :, 1) = [15 -23 4; 0 9 -21];
c(:, :, 2) = [1 1 1; 2 3 4];

determinano la creazione in c di un array a tre dimensioni. In corrispondenza di un indice


della terza dimensione pari a 1 larray contiene la matrice [15 -23 4; 0 9 -21]. In
corrispondenza dellindice 2 per la terza dimensione larray contiene la matrice [1 1 1; 2
3 4]. Complessivamente, larray tridimensionale c ha 2 righe, 3 colonne e due elementi
sulla terza dimensione e quindi contiene complessivamente 12 elementi. Data questa
definizione di c, i suoi singoli elementi possono essere identificati tramite tre indici. Per
esempio, Lespressione c(1, 2, 1) identifica lelemento di valore -23.

32

2.3.4. Subarray
Il meccanismo dei subarray (sottoarray) consente di utilizzare porzioni di array in modo
indipendente dallarray di cui fanno parte. In generale, un sottoarray viene identificato
inserendo a fianco del nome dellarray, tra le parentesi tonde, lindicazione degli indici dei
valori nellarray di partenza che fanno parte del sottoarray.
Per esempio, dato il seguente vettore:
vettore = [11 12 13 14 15];

listruzione vettore(2) consente di ottenere il sottoarray costituito solo dal secondo


elemento. Listruzione vettore([1 4]) consente di ottenere il sottoarray che contiene i
valori delle posizioni 1 e 4 di vettore, cio [11 14]. Infine, listruzione
vettore(2:4) consente di ottenere il sottoarray che contiene i valori di tutte le posizioni
comprese tra 2 e 4 di vettore ([12 13 14]).
Il meccanismo dei sottoarray si applica in generale ad array di qualsiasi dimensione. Per
esempio, data la seguente matrice:
matrice =
9
8
6
5
3
2
0
11
0
0

7
4
1
12
0

con listruzione matrice([1 4], [2 3]) si identifica la porzione di matrice costituita


dai quattro elementi: matrice(1, 2), matrice(1, 3), matrice(4, 2), matrice(4,
3), e cio la porzione contenente i valori [8 7; 11 12].
In una matrice a due dimensioni il simbolo : pu essere usato al posto dellindice di riga
o di colonna per indicare che quellindice varia tra 1 e la sua dimensione massima.
Per esempio, listruzione matrice(1:2:5, :) indica il fatto che si vuole fare riferimento
al sottoarray contenente le righe di matrice di indice tra 1 e 5 con passo di incremento 2, e
le colonne di indice tra 1 e il numero di colonne della matrice. Questa istruzione quindi
identifica la porzione di matrice che comprende le righe 1, 3 e 5 e, per queste righe, tutte
le colonne disponibili. Il risultato ottenuto in questo caso quindi il sottoarray che contiene
i seguenti valori: [9 8 7; 3 2 1; 0 0 0].
I sottoarray possono essere utilizzati sia a destra sia a sinistra delloperatore di
assegnamento. Nel caso in cui si utilizzino a sinistra dellassegnamento, leffetto che si
ottiene quello di attribuire nuovi valori agli elementi dellarray che sono parte del
sottoarray. Per esempio, scrivendo:
matrice(2:2:4, :) = [-1 -2 -3; -4 -5 -6];

si ottiene che gli elementi del sottoarray di matrice che include le righe 2 e 4 e, per queste,
tutte le colonne, diventano pari ai valori specificati a destra dellassegnamento. In altri
termini, matrice diventa pari a:
matrice =
9
8
-1
-2
3
2
-4
-5
0
0

7
-3
1
-6
0

33

2.4.

Tipi di dato logici

Il tipo di dato logico pu assumere solo due valori: true e false.


Questi valori possono essere prodotti in diversi modi, tramite le funzioni speciali true e
false, gli operatori relazionali e gli operatori logici.
Per creare una variabile di tipo logico basta assegnare a una variabile un valore logico; ad
esempio:
var_logica=false;

In questo caso abbiamo creato una variabile di tipo logico di nome var_logica, che
assume il valore false.
Le variabili di tipo logico occupano solo un byte di memoria. Quindi, se si analizza la
variabile var_logica con l'usuale comando whos, otteniamo:
Name
var_logica

Size
1x1

Bytes
1

Class
Attributes
logical array

Si possono creare anche array, di qualunque dimensione, i cui elementi sono di tipo logico.
Ad esempio:
vett_logico=[true false false];

crea un vettore riga di nome vett_logico, i cui elementi sono di tipo logico e con il
comando whos otterremo:
Name
Size
Bytes
Class
Attributes
vett_logico

1x3

logical array

Una variabile logica pu essere creata anche assegnandole il valore di un'espressione o di


una funzione logica, che introdurremo nelle sezioni successive.
MATLAB permette di usare le variabili logiche insieme alle variabili numeriche,
compiendo internamente le seguenti conversioni:
Se una variabile logica usata al posto di una variabile numerica, il valore true
convertito nel valore 1, mentre il valore false nel valore 0;
Se una variabile numerica usata al posto di una variabile logica, il valore
numerico 0 convertito in false, mentre tutti i valori diversi da 0 vengono
convertiti in true.
anche possibile effettuare conversioni tra valori numerici e logici in modo esplicito
utilizzando la funzione predefinita logical, che converte variabili numeriche in variabili
logiche.

2.4.1. Espressioni logiche


Esistono espressioni logiche basate su operatori relazionali ed espressioni logiche basate su
operatori logici. Entrambe offrono come risultato un valore logico, ma mentre le prime
utilizzano operatori relazionali per confrontare due operandi che possono essere numerici
(scalari o array), caratteri o stringhe, le seconde utilizzano come operandi valori logici.

34

2.4.1.1. Operatori relazionali


Gli operatori relazionali sono:
==
Uguale a3
~=

Diverso da

>

Maggiore di

>=

Maggiore o uguale a

<

Minore di

<=

Minore o uguale a
Attraverso tali operatori si possono costruire espressioni logiche della seguente forma:
operando1 op operando2

dove operando1 e operando2 possono essere valori numerici (scalari o array), caratteri o
stringhe, mentre op un operatore relazionale. A seconda che la condizione espressa
dall'operatore op sia o non sia rispettata dagli operandi, l'espressione assume il valore true
(1) o false (0), rispettivamente.
Si noti che i valori numerici possono essere dati da costanti, variabili o espressioni
aritmetiche. Gli operatori aritmetici hanno precedenza rispetto agli operatori relazionali.
Esempio: Dati var1=6 e var2=5, vediamo alcuni esempi di espressioni logiche e la loro
valutazione:
1>2
1==1
3>=3
'B'<'A'
var1<=var2
var1==var2+1

false (0)
true (1)
true (1)
false (0)
false (0)
true (1)

Si noti che nella valutazione comparativa di caratteri si utilizza l'ordine alfabetico.


Quando si usano gli operatori == e ~= per confrontare valori numerici, bisogna fare
attenzione alle approssimazioni effettuate dall'interprete MATLAB. Ad esempio, se
verifichiamo le seguenti uguaglianze:
sin(0) == 0;
sin(pi) == 0;

ci aspetteremmo di ottenere la valutazione true in entrambi i casi. Invece, MATLAB


valuta (correttamente) la prima espressione come true, mentre valuta (in modo scorretto)
la seconda come false, in quanto, a causa dell'approssimazione su pi, assegna a
-16
sin(pi) il valore 1.2246x10 . In questi casi quindi pi opportuno utilizzare il seguente
test:
abs(sin(pi)) <= eps

L'operatore relazione ==, che confronta i due operandi, non deve essere confuso
con l'operatore di assegnamento =, che assegna alla variabile a sinistra dell'uguale il valore
a destra dell'uguale.

35

dove eps, come gi detto nel Capitolo 1, una variabile predefinita di valore
sufficientemente piccolo da essere usata a questo scopo.
Gli operatori relazionali possono essere utilizzati anche per confrontare una array con uno
scalare, due array tra di loro o due stringhe tra di loro.
Quando si confronta un array con uno scalare si ottiene come valutazione dell'espressione
logica un array delle stesse dimensioni di quello utilizzato nel confronto. Tale array
contiene in ciascuna posizione il risultato del confronto tra l'elemento nella posizione
corrispondente dell'array usato nell'espressione e lo scalare.
Esempio: Se a = [2 4; 1 3] e b=2, l'espressione a>b corrisponde a eseguire le
seguenti valutazioni [2>2 4>2; 1>2 3>2] che portano quindi al seguente risultato
a>b =
false
false

true
true

Quando si confrontano due array, essi devono avere le stesse dimensioni e l'espressione
viene valutata come un array delle stesse dimensioni, in cui ogni posizione contiene il
risultato del confronto tra gli elementi in posizione corrispondente dei due array che si
vogliono confrontare.
Esempio: Se a = [2 4; 1 3] e c = [1 5; 1 3] l'espressione a==c corrisponde a
eseguire le seguenti valutazioni [2==1 4==5; 1==1 3==4] che porta al risultato
a==c =
false
true

false
true

Anche per il confronto tra due stringhe va rispettato il vincolo che le stringhe abbiano la
stessa lunghezza. Ad esempio, ciao e cura possono essere tra di loro confrontate
utilizzando operatori relazionali, mentre ciao e salve, avendo lunghezze diverse, no.
Il confronto tra due stringhe porta a un array logico che contiene tanti elementi quanti sono
i caratteri delle due stringhe, in cui ciascun elemento corrisponde al valore ottenuto
confrontando i caratteri in posizioni corrispondenti Se, ad esempio, confrontiamo le due
stringhe ciao e cura con l'operatore ==, otterremo il vettore riga di 4 elementi
[true false false false].
Esistono per funzioni predefinite di MATLAB che permettono di confrontare stringhe di
lunghezza diversa. Le pi significative sono:
strcmp, che applicato a due stringhe, restituisce true se le due stringhe sono identiche,
false altrimenti.
strcmpi, che applicato a due stringhe, restituisce true se le due stringhe contengono gli

stessi caratteri in posizioni corrispondenti, indipendentemente dal fatto che siano minuscoli
o maiuscoli, false altrimenti.
strncmp, che presi come parametri due stringhe e un intero n, restituisce true se le due
stringhe hanno i primi n caratteri uguali, false altrimenti.

36

Esempio: Vediamo alcuni esempi di utilizzo delle funzioni appena introdotte.


Consideriamo le seguenti stringhe:
stringa1=Ciao;
stringa2=ciao;
stringa3=civetta;

La funzione strcmp(stringa1, stringa2) restituir il valore false in quanto, pur


contenendo gli stessi caratteri nelle stesse posizioni, il primo carattere di stringa1 'C',
mentre il primo di stringa2 'c' e questo rende le due stringhe non identiche. Se
utilizziamo invece stricmp sulle stesse stringhe, strcmpi(stringa1, stringa2)
restituir il valore true, in quanto la funzione verifica solo che le due stringhe abbiano gli
stessi caratteri in posizioni corrispondenti, ignorando se tali caratteri sono maiuscoli o
minuscoli. Entrambe le funzioni, strcmp e strcmpi, possono essere applicate anche a
stringhe di lunghezza diversa, restituendo false, in quanto stringhe di lunghezza diversa
non contengono gli stessi caratteri in tutte le posizioni.
La funzione strncmp, invece confronta solo i primi n caratteri di due stringhe, con n
specificato come parametro. Ad esempio, avremo che strncmp(stringa2, stringa3,
2) restituir true, in quanto i primi due caratteri delle due stringhe sono uguali, mentre
strncmp(stringa2, stringa3, 3) restituir false.

2.4.1.2. Operatori logici


Gli operatori logici sono operatori unari o binari che, valutati sui propri operandi, portano a
un valore logico. Ci sono tre operatori binari: AND, OR e OR esclusivo (XOR) e un operatore
unario, NOT.
Le espressioni costruite attraverso gli operatori logici assumono le seguenti forme:
val_logico1 op val_logico2

op val_logico

a seconda che op sia un operatore binario o unario rispettivamente. In queste espressioni


val_logico1, val_logico2 e val_logico sono valori logici, ottenibili tramite costanti,
variabili, espressioni o funzioni logiche.
I valori assunti dalle espressioni costruite attraverso gli operatori logici, a seconda dei
valori assunti dagli operandi logici A e B, sono i seguenti:
A

A AND B

A OR B

A XOR B

NOT A

true

true

true

true

false

false

true

false

false

true

true

false

false

true

false

true

true

true

false

false

false

false

false

true

Brevemente, quindi, il risultato dell'operatore AND vero solo quando entrambi gli operandi
sono veri, il risultato dell'operatore OR falso solo quando entrambi gli operandi sono falsi,
il risultato dell'operatore XOR vero quando solo uno dei due operandi vero e il risultato
dell'operatore NOT l'opposto rispetto al valore dell'operando a cui viene applicato.

37

In MATLAB tali operatori vengono rappresentati nel seguente modo:


A AND B si rappresenta come A&&B o A&B;
A OR B si rappresenta come A||B o A|B;
A XOR B si rappresenta come xor(A,B);
NOT A si rappresenta come ~A.

Si noti che esistono due operatori logici AND e due operatori logici OR.
&& effettua una valutazione parziale: nel caso in cui si valuti l'espressione A&&B, se A fosse
falso linterprete restituirebbe il valore falso per lintera espressione, senza valutare B.
Viceversa, nel caso si utilizzi loperatore & nella medesima espressione, entrambi i termini,
A e B, verrebbero comunque valutati. Discorso analogo vale per gli operatori || (per il

quale se il primo termine vero linterprete restituisce direttamente il valore vero senza
procedere alla valutazione del secondo) e | (per il quale vengono sempre valutati
entrambi).
&&(||) pu essere applicato solo con operandi scalari, mentre &(|) funziona sia con

operandi scalari sia con array, a condizione che le dimensioni degli array coinvolti siano
compatibili.
In generale con valori scalari l'uso di &&(||) o &(|) equivalente. Esistono per alcune
eccezioni. Si supponga di voler assegnare a una variabile logica il valore ottenuto da un
confronto effettuato con operatori relazionali, ad esempio:
val_logico=a/b > 1

dove a e b sono variabili scalari numeriche. In questo caso sarebbe opportuno, verificare
precedentemente che b sia diverso da 0 aggiungendo in AND la condizione b~=0. In questo
caso vogliamo che la divisione a/b venga effettuata solo se b soddisfa la prima condizione,
per cui opportuno utilizzare la valutazione parziale dell'AND, nel seguente modo:
val_logico=b~=0 && a/b > 1

Vediamo ora alcuni esempi di espressioni logiche.


Esempio: L'espressione logica per esprimere la condizione Ha pi di 30 anni si esprime
come eta>30. Se, ad esempio, eta=29 l'espressione logica vale false, mentre, se
eta=45, vale true.

Esempio: L'espressione logica per esprimere la condizione Ha tra i 25 e i 30 anni si


esprime come (eta>=25) & (eta<=30). Se, ad esempio, eta=29 l'espressione logica
vale true, mentre, se eta=45, vale false.
Visto che esiste una corrispondenza tra i tipi di dati logici e i valori numerici, possibile
utilizzare valori numerici al posto di operandi logici quando si usano operatori logici. In
questo caso MATLAB convertir i valori diversi da 0 in true e i valori pari a 0 in false.
Ad esempio se a=7 e b=5, l'espressione a<10 & b verr valutata come true, in quanto 7
minore di 10 e b, essendo 5, verr valutato come true, mentre a<10 & ~b verr valutata
come false in quanto ~5 equivalente a dire ~true, cio false.

38

Analogamente a quanto accade per gli operatori relazionali, gli operatori logici possono
essere applicati avendo come operandi un array e uno scalare o due array della stessa
dimensione. Nel primo caso si otterr un array logico della stessa dimensione dell'array
usato nell'espressione, in cui in ogni posizione ci sar la valutazione dell'operatore logico
applicato all'elemento corrispondente dell'array usato nell'espressione e allo scalare.
Esempio: se a = [true false; false true] e b = true, l'espressione a | (~b)
verr valutata come una matrice 2x2 (le dimensioni di a) che conterr i valori
true
false

false
true

Nel caso in cui si confrontino due array di identiche dimensioni si ottiene un array di
analoghe dimensioni, in cui ogni elemento corrisponde alla valutazione dell'operatore
logico fatta sui due elementi in posizioni corrispondenti negli array usati nell'espressione.
Esempio: se x=[true true false] e y=[false true true], l'espressione x & y
verr valutata come [false true false].
Vediamo ora un esempio pi complesso, che include operatori relazionali e logici.
Esempio: Si consideri la condizione I voti del I appello sono compresi tra il 22 e il 27. Se
i voti dell'appello sono contenuti in un vettore voti, tale condizione si esprime con
l'espressione logica (voti>=22) & (voti<=27).
Se, ad esempio:
voti=[15 21 24 18 27 15 30 25 23],
l'espressione comparativa (voti>=22) vale
[false false true false true false true true true],

mentre (voti<=27)vale
[true true true true true true false true true].
L'espressione logica vale quindi [false false true false true false false
true true].
Visto che i valori logici possono essere visti come numeri possibile contare quanti voti
sono nel range richiesto applicando la funzione predefinita sum all'espressione logica.
Facendo quindi sum((voti>=22) & (voti<=27)) si otterr 4, cio il numero di true
nel vettore ottenuto dal confronto.
Nellesempio precedente abbiamo fatto uso di parentesi tonde, in modo da precisare
l'ordine con cui applicare gli operatori logici e relazionali. In assenza di parentesi esiste un
ordine fissato di precedenze con cui applicarli, che il seguente:
Operatori aritmetici, utilizzando le consuete precedenze;
Operatori relazionali, procedendo da sinistra a destra;
Negazione (~), procedendo da sinistra a destra;

39

Congiunzione (& e &&), procedendo da sinistra a destra;


Disgiunzione (| e ||) e XOR (xor), procedendo da sinistra a destra.
Esempio: se a=7, b=10, c=21, e d=0, l'espressione
a + b >c & c a > b | ~d

verr valutata come false. Infatti prima verranno eseguite le operazioni aritmetiche,
ottenendo
17 > c & 14 > b | ~d;
poi verranno valutati gli operatori relazionali da sinistra a destra ottenendo
false & false | ~d

e poi verr valutato l'operatore ~ ottenendo


false & false | true.
Tra & e | ha precedenza &, quindi otterremo false | true, da cui otteniamo la
valutazione dell'intera formula che true. Se avessimo voluto applicare prima | e poi &,
avremmo dovuto precisare l'ordine di applicazione con l'aiuto delle parentesi:
a + b > c & (c a > b | ~d).
In tal caso la formula sarebbe stata valutata come false.

2.4.2. Funzioni logiche


MATLAB offre un certo numero di funzioni che restituiscono un valore logico, che vero
o falso a seconda che la condizione che controllano sia verificata o no. Alcuni esempi di tali
funzioni sono:
all che, applicata a un array x, restituisce un vettore riga con lo stesso numero di colonne
di x, che contiene true, se la corrispondente colonna di x contiene tutti elementi pari a
true, false altrimenti.
any che, applicata a un array x, restituisce un vettore riga con lo stesso numero di colonne
di x, che contiene true , se la corrispondente colonna di x contiene almeno un elemento
pari a true, false altrimenti.
isinf che, applicata a un array x, restituisce un array delle stesse dimensioni di x con
true in corrispondenza degli elementi di x che sono inf, false altrove.
isempty che, applicata a una variabile, restituisce true se x vuota, false altrimenti.
isnan che, applicata a un array x, restituisce un array delle stesse dimensioni di x con
true in corrispondenza degli elementi di x che sono NaN, false negli altri posti.
finite che, applicata a un array x, restituisce un array delle stesse dimensioni di x con
true in corrispondenza degli elementi di x finiti, false negli altri posti.
ischar che, applicata a una variabile x, restituisce true se x di tipo char, false

altrimenti.
isnumeric che, applicata a una variabile x, restituisce true se x di tipo double,
false altrimenti.

40

2.5.

Strutture

Spesso in un programma necessario elaborare o memorizzare delle informazioni


strutturate, cio costituite da un aggregato di informazioni elementari (e.g., valori numerici,
caratteri) e spesso eterogenee. Ad esempio, si supponga di dover memorizzare le
informazioni riguardanti un libro:

Autori: A. Morzenti
Titolo: Programmare in Modula-2
Anno di Pubblicazione: 1991
Numero di Pagine: 250
I tipi di dato visti finora consentono di memorizzare queste informazioni attraverso pi
variabili fra loro separate. Tuttavia questo tipo di rappresentazione non molto
conveniente, poich non rende in alcun modo esplicita la relazione fra le diverse variabili.
Per rappresentare in modo compatto ed efficace informazioni strutturate, in MATLAB
possibile ricorrere alle strutture. Le strutture, come gli array, consentono di associare pi
elementi a una singola entit (ovvero a una singola variabile), tuttavia si differenziano da
questi principalmente per due aspetti:
Gli elementi di una struttura sono identificati da un nome, mentre gli elementi di
un array sono identificati da un indice.
Gli elementi di una struttura possono appartenere a diversi tipi di dato, mentre gli
elementi di un array devono essere dello stesso tipo di dato.

2.5.1. Definizioni
Illustreremo ora attraverso il precedente esempio del libro le principali caratteristiche di una
struttura. Abbiamo visto che unentit libro caratterizzata da quattro diversi elementi: gli
autori del libro, il titolo, lanno di pubblicazione e il numero di pagine. Perci la struttura
sar cos formata:
libro

autori
A

M o

titolo
g

anno
1991

pagine

250

Come illustrato dallesempio, una struttura un tipo di dato formato da pi elementi, detti
campi. Ciascun campo identificato da un nome e pu essere un qualsiasi tipo di dato
MATLAB. Nel nostro esempio, libro una struttura che contiene quattro campi che si
chiamano rispettivamente autori, titolo, anno e pagine. I primi due, autori e

41

titolo sono degli array di caratteri. Invece, gli ultimi due, anno e pagine, sono due

scalari di tipo double.


MATLAB consente di memorizzare tutte le informazioni in una singola variabile struttura
attraverso la quale sar poi possibile accedere a tutti i campi in essa contenuti. Per accedere
ai campi di una struttura si utilizza la notazione puntata: occorre specificare il nome della
variabile struttura, seguito da un punto e infine dal nome del campo a cui si vuole accedere
nel seguente modo,
nome_struttura.nome_campo

Per esempio, il seguente frammento di codice mostra come accedere al campo anno della
variabile libro descritta in precedenza:
>> libro.anno
ans = 1991

bene sottolineare come sia assolutamente necessario specificare la variabile struttura in


cui il campo contenuto per poter accedere a esso: il nome del campo da solo non indica
nessuna variabile ed perci un simbolo sconosciuto per linterprete MATLAB, come
mostra il seguente esempio.
>> anno
error: 'anno' undefined near line 3 column 1

Invece, il nome della variabile struttura un nome di variabile valido e pu essere


utilizzato, senza specificare alcun campo tramite la notazione puntata, per riferirsi allintera
struttura, come mostrato nel seguente esempio.
>> libro
ans =
autori:
titolo:
anno:
pagine:

'A. Morzenti'
'Programmare in Modula-2'
1991
250

2.5.2. Creare una struttura


Per creare una struttura possibile seguire due diversi approcci:
creare un campo della struttura alla volta, mediante una serie di assegnamenti
creare e inizializzare tutti i campi della struttura con una sola istruzione, mediante
la funzione struct

2.5.2.1. Creare una struttura mediante assegnamenti


Come avviene per tutti i tipi di variabile in MATLAB, anche i campi di una struttura
possono essere creati mediante una semplice istruzione di assegnamento: assegnando un
valore a un campo di una variabile struttura questo viene automaticamente creato.
Esempio: per illustrare meglio la creazione di una variabile struttura, mostriamo di seguito
quali istruzioni sono necessarie per creare la struttura libro mostrata nel nostro
precedente esempio.
>>
>>
>>
>>
>>

libro.autori
libro.titolo
libro.anno =
libro.pagine
libro

= 'A. Morzenti';
= 'Programmare in Modula-2';
1991;
= 250;

42

ans =
autori:
titolo:
anno:
pagine:

'A. Morzenti'
'Programmare in Modula-2'
1991
250

Vale la pena di osservare che, nellesempio appena mostrato, la prima istruzione di


assegnamento ha una duplice funzione: essa dice allinterprete MATLAB di creare una
variabile libro di tipo struttura e di creare una campo in tale struttura di nome autori
avente come tipo un array di 11 caratteri e contenente il valore 'A. Morzenti'. Dopo la
prima istruzione, a ogni assegnamento successivo, linterprete MATLAB cerca allinterno
della struttura libro se il campo specificato gi presente. In caso positivo ne modifica il
valore, in caso negativo (come accade nel nostro esempio) il campo viene creato e poi gli
viene assegnato il valore specificato.

2.5.2.2. La funzione struct


La funzione struct consente di creare una struttura specificando i nomi dei campi
desiderati e il loro valore. La sintassi per utilizzare la funzione struct la seguente:
nome_variabile = struct(nome1, val1, nome2, val2, )

dove nome_variabile il nome della variabile struttura che si desidera creare, mentre gli
argomenti della funzione sono coppie <nome, valore> che specificano rispettivamente il
nome di ciascun campo e il valore da assegnare a esso.
Esempio: luso della funzione struct illustrato chiaramente dal seguente esempio.
>> libro = struct ('autori', 'A. Morzenti', 'titolo',
'Programmare in Modula-2', 'anno',1991, 'pagine',250);
>> libro
ans =
autori:
titolo:
anno:
pagine:

'A. Morzenti'
'Programmare in Modula-2'
1991
250

Come mostrato dallesempio, la funzione struct consente di creare e di inizializzare una


variabile struttura con una sola istruzione. La sequenza di parametri mostrata nellesempio
va interpretata secondo la sintassi della funzione struct: si tratta di una sequenza di
quattro coppie di parametri che caratterizzano i campi della struct libro. Si noti che i nomi
dei campi devono essere forniti alla funzione struct come stringhe, ovvero array di caratteri,
4
mentre il loro valore pu appartenere a qualsiasi tipo di dato .

Il lettore non si lasci confondere dal fatto che nellesempio riportato i primi quattro
parametri della chiamata a struct sono di tipo stringa. Infatti mentre il primo ( autore)
e il terzo (titolo) sono i nomi dei campi, il secondo e quarto sono il valore da
assegnare a questi campi che sono anchessi di tipo stringa.

43

2.5.3. Array di strutture


Supponiamo ora di dover memorizzare le informazioni di pi libri, anzich di uno soltanto
come ipotizzato finora. Come per tutti gli altri tipi di dato, anche le strutture, possono
essere utilizzate allinterno di array.
Per accedere a un elemento di un array di strutture si utilizza la notazione standard di
MATLAB per gli array: dopo il nome dellarray occorre indicare tra parentesi tonde
lindice dellelemento a cui si vuole accedere. Nel caso si debba accedere a un campo della
struttura, si continuer a usare la notazione puntata facendo seguire il punto allindice
dellelemento fra parentesi tonde:
nome_array(indice).nome_campo

Linterprete di MATLAB crea larray in maniera automatica non appena esso incontra
unistruzione di assegnamento che lo coinvolge. Quando un nuovo elemento di un array di
strutture viene creato, anche tutti i campi della struttura verranno creati per quellelemento.
I campi dellelemento appena creato che non sono stati ancora inizializzati conterranno un
vettore vuoto, che potr poi essere inizializzato successivamente dallutente.
Esempio: per comprendere meglio i concetti appena introdotti, illustriamo la creazione e
luso di un array di strutture mediante il seguente esempio in cui si suppone di aver gi
creato la struttura libro usata nei precedenti esempi.
>> libro(2).titolo = 'Da Definire'
libro =
1x2 struct array with fields:
autori
titolo
anno
pagine
>> libro(2)
ans =
autori:
titolo:
anno:
pagine:
>>
>>
>>
>>

[]
'Da Definire'
[]
[]

libro(2).pagine=100;
libro(2).autori='Sconosciuti';
libro(2).anno=2009;
libro(2)

ans =
autori:
titolo:
anno:
pagine:

'Sconosciuti'
'Da Definire'
2009
100

44

Inizialmente, libro conteneva gi un elemento (le informazioni relative al libro


Programmare in Modula-2). Il risultato della prima istruzione di questo esempio ha
come effetto quello di creare un nuovo elemento di libro, che diventa perci un array di
due elementi, come mostrato dalloutput dellinterprete. Andando a guardare il contenuto
del secondo elemento dellarray libro, si osserva che il campo titolo contiene il valore
assegnatogli, mentre gli altri campi non inizializzati contengono un array vuoto. Le
istruzioni successive, infine, consentono di inizializzare anche gli altri campi.

2.5.3.1. Aggiungere un campo in un array di strutture


Laggiunta di un campo in un array di strutture avviene mediante assegnamento, come nel
caso di una variabile struttura scalare. importante sottolineare che laggiunta di un campo
in un singolo elemento di un array di strutture ha come risultato laggiunta di quel campo
anche in tutti gli altri elementi dellarray di strutture. I nuovi campi creati e non
inizializzati conterranno un array vuoto.
Esempio: aggiunta di un campo allarray di strutture libro.
>> libro(1).costo = 15.2;
>> libro(1)
ans =
autori:
titolo:
anno:
pagine:
costo:

'A. Morzenti'
'Programmare in Modula-2'
1991
250
15.2000

>> libro(2)
ans =
autori:
titolo:
anno:
pagine:
costo:

'Sconosciuti'
'Da Definire'
2009
100
[]

2.5.3.2. Rimuovere un campo in un array di strutture


Per rimuovere un campo da un array di strutture necessario utilizzare la funzione
rmfield, che ha la seguente sintassi:
ris = rmfield(nome_array,nome_campo)

dove nome_array il nome dellarray di strutture da cui si desidera rimuovere un


campo, nome_campo il nome del campo che si desidera rimuovere, e ris il nome
della variabile in cui verr memorizzato il risultato, cio larray struttura da cui stato
rimosso il campo nome_campo.

45

Esempio: il funzionamento di rmfield mostrato in pratica nel seguente esempio.


>> libroSenzaPagine = rmfield(libro,'pagine');
>> libroSenzaPagine(1)
ans =
autori:
titolo:
anno:
costo:

'A. Morzenti'
'Programmare in Modula-2'
1991
15.2000

>> libroSenzaPagine(2)
ans =
autori:
titolo:
anno:
costo:

'Sconosciuti'
'Da Definire'
2009
[]

>> libro(2)
ans =
autori:
titolo:
anno:
pagine:
costo:

'Sconosciuti'
'Da Definire'
2009
100
[]

2.5.3.3. Accedere ai dati in un array di strutture


Abbiamo mostrato come sia possibile accedere ai singoli campi degli elementi di un array
di strutture indicando lindice dellelemento a cui accedere e, utilizzando la notazione
puntata, il nome del campo desiderato. Una volta specificato correttamente lelemento
dellarray e il campo a cui si desidera accedere, possibile utilizzare tale valore in
qualunque espressione valida per il tipo di dato del campo. Tuttavia in molti casi pu essere
utile accedere al contenuto di uno specifico campo di tutti gli elementi un array di strutture.
A tale scopo possibile utilizzare la seguente notazione:
[nome_array.nome_campo]

dove nome_array il nome dellarray di strutture e nome_campo il campo di cui si


desiderano estrarre tutti i valori. opportuno sottolineare che questa notazione pu essere
utilizzata solo per accedere ai dati in lettura e quindi non pu essere utilizzata per
modificare i valori dei campi.
Per capire meglio lutilizzo di questa notazione, lesempio successivo mostra come
calcolare il numero medio di pagine degli elementi contenuti nellarray di strutture libro.
>> [libro.pagine]

46

ans =
250

100

>> mean([libro.pagine])
ans =
175

2.5.4. Strutture innestate


Secondo la definizione di struttura data in precedenza, i campi di una struttura possono
essere di qualsiasi tipo di dato valido in MATLAB. Perci il campo di una struttura pu
essere a sua volta un array di strutture.
Esempio: per esempio, se volessimo ampliare la struttura libro con le informazioni
riguardanti le ristampe potremmo utilizzare le seguenti istruzioni.
>>
>>
>>
>>
>>
>>

libro(1).ristampa(1).anno=1992;
libro(1).ristampa(1).mese='Settembre';
libro(1).ristampa(1).tiratura=1000;
libro(1).ristampa(2).anno = 1993;
libro(1).ristampa(2).mese = 'Agosto';
libro(1)

ans =
autori:
titolo:
anno:
pagine:
costo:
ristampa:

'A. Morzenti'
'Programmare in Modula-2'
1991
250
15.2000
[1x2 struct]

>> libro(1).ristampa(1)
ans =
anno: 1992
mese: 'Settembre'
tiratura: 1000
>> libro(1).ristampa(2)
ans =
anno: 1993
mese: 'Agosto'
tiratura: []

Come mostrato dallesempio, la creazione di una struttura innestata segue le medesime


regole viste in precedenza, con lunica differenza che in questo caso larray di strutture
ristampa a sua volta un campo di un array di strutture.

47

Le istruzioni mostrate nellesempio precedente hanno come risultato quello di creare un


nuovo campo ristampa che a sua volta un array di strutture. importante sottolineare
che laggiunta di un campo ristampa al primo elemento di libro, si riflette anche sul
secondo elemento di libro. Infatti, anche al secondo elemento di libro verr aggiunto il
campo ristampa, il cui contenuto sar tuttavia un array vuoto dal momento che non
stato ancora inizializzato. Come mostra loutput dellistruzione riportata nel seguente
frammento.
>> libro(2)
ans =
autori:
titolo:
anno:
pagine:
costo:
ristampa:

'Sconosciuti'
'Da Definire'
2009
100
[]
[]

Infine, nel breve esempio seguente viene mostrato come memorizzare in un array gli anni
in cui sono state pubblicate le ristampe del primo elemento di libro.
>> anni_ristampe = [libro(1).ristampa.anno]
anni_ristampe =
1992

1993

2.5.5. Esempio riassuntivo


Esempio: si consideri il problema di rappresentare lorario dei treni di una stazione
ferroviaria. Cominciamo a predisporre una struttura dati adeguata per rappresentare la
stazione.
stazione.nome = Rogoredo;
stazione.citta = Milano;

A questo punto definiamo una struttura per rappresentare le informazioni sui treni:
treno(1).numero = 20642;
treno(1).binario = 2;
treno(1).ritardo = 4;

treno(5).numero = 2134;
treno(5).binario = 5;
treno(5).ritardo = 0;

Supponiamo che i primi 2 treni memorizzati allinterno della struttura treno siano treni in
partenza dalla stazione, mentre gli ultimi 3 siano in arrivo. Possiamo perci inserire queste
informazioni allinterno della struttura dati che rappresenta la stazione nel modo seguente.
stazione.inArrivo = [treno(3) treno(4) treno(5)];
stazione.inPartenza = [treno(1) treno(2)];

48

Infine se volessimo sapere se c almeno un treno in arrivo sul secondo binario, sarebbe
sufficiente utilizzare la seguente istruzione:
any([stazione.inArrivo.binario]==2)

in cui stato utilizzata la funzione logica any vista nella precedente sezione, il cui risultato
(in questo caso) sar 1 se almeno un treno fra quelli memorizzati nel campo inArrivo ha
valore 2 nel campo binario.

49

Capitolo Terzo: Strutture di Controllo

Le strutture di controllo sono costrutti sintattici offerti da un linguaggio di programmazione


che consentono di modificare lordine di esecuzione delle istruzione.
Gli esempi visti fino a questo momento contengono istruzioni semplici, come ad esempio
assegnamenti o uso di funzioni predefinite, scritte una sotto l'altra, che vengono eseguite
una dopo l'altra nell'ordine in cui appaiono nel codice. Questo tipo di flusso di esecuzione
rappresenta il caso pi semplice di struttura di controllo fornita da un linguaggio di
programmazione, la sequenza, e consiste in una lista ordinata di istruzioni.
Oltre alle sequenze, esistono altri due schemi di controllo:
Selezione: costrutti che permettono, tramite il valore di una condizione, di
scegliere quali istruzioni eseguire;
Ciclo: schema che permette di ripetere pi volte una o pi istruzioni.
In questo capitolo affronteremo in dettaglio le strutture di controllo, analizzando per
ciascuno dei due schemi le alternative sintattiche offerte da MATLAB.

3.1.

Selezione

I costrutti di selezione permettono di scegliere tra una o pi sequenze di istruzioni quella da


eseguire, a seconda del valore di una o pi condizioni rappresentate da espressioni logiche.
Esistono diversi costrutti sintattici in MATLAB per esprimere la selezione e in questa
sezione li analizzeremo.

3.1.1. Il costrutto if
Il costrutto if ha la seguente forma:
if espressione1
istruzione1
istruzione2
...
elseif espressione2
istruzione1
istruzione2
...
...
else
istruzione1
istruzione2
...
end

blocco1

blocco2

bloccoK

dove espressione1, espressione2, ... sono espressioni logiche e instruzione1,


istruzione2,... sono istruzioni qualsiasi.

50

Tale costrutto pu essere spiegato attraverso il seguente diagramma di flusso (o diagramma


a blocchi):

Questo significa che prima verr verificato il valore di verit di espressione1, se tale
espressione vera, verr eseguita la sequenza di istruzioni appartenenti al blocco1, in
caso contrario verr analizzato il valore di verit di espressione2. Analogamente al caso
precedente, qualora questa condizione sia verificata, verr eseguito blocco2,
alternativamente si passa alla condizione successiva. Se e quando si arriva a valutare
l'ultima espressione e anche questa falsa, si passa ad eseguire bloccoK. Si noti che si
passa alla valutazione della successiva condizione se e soltanto se la condizione
precedentemente valutata risulta falsa. La parola chiave end chiude il costrutto if.
In un costrutto if ci possono essere un numero arbitrario di elseif (anche zero), ma ci
pu essere al pi un ramo else. Nel caso pi semplice, quindi, il costrutto if risulter
essere:
if espressione1
istruzione1
istruzione2
...
end

blocco1

In questo caso verr valutata espressione1 e, in caso risulti vera, verr eseguito
blocco1, per poi passare a eseguire le istruzioni successive alla parola chiave end; in caso
espressione1 sia falsa si passer direttamente ad eseguire le istruzioni dopo la parola
chiave end.
Esempio: Un frammento di codice che valuta se uno scalare numerico x negativo e in
caso lo sia lo trasforma nel corrispondente numero positivo, il seguente:
if x<0
x=abs(x);

%se x negativo
%allora x assume il valore assoluto di x

end

51

Se supponiamo che x=7, la condizione dell'if viene valutata come false e quindi le
istruzioni all'interno del costrutto non vengono eseguite. Linterprete MATLAB passa
dunque a eseguire direttamente la prima istruzione dopo la parola chiave end. Se invece
x=-2, la condizione dell'if viene valutata come true e quindi viene eseguita l'istruzione
x=abs(x), per cui x assumer il valore 2.

Esempio: Un frammento di codice che assegna a uno scalare z il massimo tra gli scalari x e
y il seguente:
if x>=y
z=x;
else
z=y;
end

%se x maggiore o uguale a y


%allora z assume il valore di x
%altrimenti (se y maggiore di x)
%z assume il valore di y

Se x=7 e y=10 la condizione dell'if viene valutata come false e quindi linterprete passa
a eseguire le istruzioni all'interno del ramo else del costrutto. In particolare viene eseguita
l'istruzione z=y per cui z assumer il valore 10.

Esempio: Supponiamo di essere interessati a contare il numero di voti compresi tra 22 e 25


in un vettore riga voti e di assegnare a una variabile z il valore 1, se tale numero
maggiore di 5, il valore 2, se compreso tra 2 e 5, il valore 0, altrimenti. Il frammento di
codice per risolvere questo problema il seguente:
n=sum(voti>=22 & voti<=25) %n il numero di voti tra 22 e 25
if n>5
%se n maggiore di 5
z=1;
%allora z assume il valore 1
elseif n>=2 & n<=5
%altrimenti, se n compreso tra 2 e 5
z=2;
%allora z assume il valore 2
else
%altrimenti
z=0;
%z assume il valore 0
end

Se voti=[15 21 24 18 27 15 30 25 23], l'espressione logica (voti>=22 &


voti<=25) vale [false false true false false false false true true],
per cui n=3. La condizione dell'if viene quindi valutata come false e si passa a
verificare la condizione dell' elseif. Tale condizione risulta vera per cui si eseguono le
istruzioni all'interno del ramo elseif. In particolare l'istruzione z=2.
Senza introdurre una nuova variabile possibile calcolare il numero di voti compresi tra 22
e 25 direttamente nella condizione dell'if, ottenendo il seguente codice:
if sum(voti>=22 & voti<=25)>5
z=1;
elseif sum(voti>=22 & voti<=25)>=2 & sum(voti>=22 & voti<=25)<=5
z=2;
else
z=0;

52

Dal momento che, come anticipato nell'introduzione, una sequenza di istruzioni pu


contenere sia istruzioni semplici, come ad esempio assegnamenti, sia istruzioni complesse,
come ad esempio strutture di controllo, possibile trovarsi ad avere costrutti if annidati.
Se, ad esempio, in
if espressione1
istruzione1
istruzione2
...
end

%blocco1

istruzione2 fosse a sua volta un costrutto if ci troveremmo ad avere


if espressione1
istruzione1
%blocco1
if espressione2
istruzione1
%blocco2 interno a blocco1
istruzione2
...
...
end

Questo significa che verr prima valutata espressione1 e qualora questa fosse verificata,
si andr a eseguire blocco1, cio istruzione1 e il costrutto if contenuto in esso,
utilizzando l'usuale semantica del costrutto. Si noti che quindi le istruzioni contenute in
blocco2 verranno eseguite solamente se sia espressione1 sia espressione2 risultano
vere.
Esempio: Si supponga di voler contare il numero di voti compresi tra 22 e 25 in un vettore
riga voti. Se tale numero maggiore di 5, si vuole assegnare a una variabile z il valore 1
e se, oltre a questa condizione il numero di voti maggiori di 27 maggiore di 3, si vuole
assegnare alla variabile x il valore 1. Il frammento di codice per risolvere il problema il
seguente:
if sum(voti>=22 & voti<=25)>5
z=1;
if sum(voti>=27)>3
x=1;

%se il numero di voti compreso tra


%22 e 25
%maggiore di 5
%allora z vale 1
%e se il numero di voti maggiori di
%27 maggiore di 3
%allora x=1

end
end

Se voti=[29 22 24 22 28 22 30 25 23], l'espressione logica (voti>=22 &


voti<=25) vale [false true true true false true false true true], per cui
la condizione sum(voti>=22 & voti<=25)>5 vera. Si eseguono quindi le istruzioni
all'interno dell'if, in particolare l'istruzione z=1 e il costrutto if interno. La condizione
sum(voti>=27)>3 vera, per cui verr eseguita anche l'istruzione x=1.

53

3.1.2. Il costrutto switch


Un altro modo per esprimere la selezione il costrutto switch, che permette di scegliere
fra diverse alternative a seconda dei valori di un singolo intero, carattere o espressione
logica. Il costrutto ha la seguente forma sintattica:
switch (espressione_switch)
case caso1
istruzione1
istruzione2
...
case caso2
istruzione1
istruzione2
...
...
otherwise
istruzione1
istruzione2
...
end

dove espressione_switch pu rappresentare sia valori numerici che stringhe.


L'esecuzione di un costrutto switch sar la seguente. Inizialmente verr valutato se
espressione_switch uguale a caso1; se questo il caso verr eseguito blocco1,
altrimenti, si passer a valutare se espressione_switch uguale a caso2 e cos via.
Qualora espressione_switch non risulti uguale a nessun caso e sia presente il ramo
otherwise, allora verr eseguito il blocco corrispondente a tale ramo. La parola chiave
end termina il costrutto.
Graficamente tale costrutto pu essere rappresentato dal seguente diagramma a blocchi:

54

Esempio: Un frammento di codice che, a seconda del valore dello scalare di tipo char
giorno, stampa a video il giorno corrispondente della settimana il seguente:
switch (giorno)
case 'l'
%se giorno il carattere 'l'
disp('Lunedi');
%stampa 'Lunedi'
case 'm'
disp('Martedi o Mercoledi');
case 'g'
disp('Giovedi');
case 'v'
disp('Venerdi');
case 's'
disp('Sabato');
case 'd'
disp('Domenica');
otherwise
%se giorno diverso da tutti i
%casi precedenti
disp('Errore!');
%stampa 'Errore!'
end

un caso (un ramo case) dovesse corrispondere a pi valori di


espressione_switch questi verranno elencati tra parentesi graffe e separati da virgola:
switch (espressione_switch)
case {caso1, caso2,...,casoK}
istruzione1
...
...
otherwise
istruzione1
...
end
Qualora

Si noti che, se espressione_switch risultasse uguale a pi di uno dei casi proposti, verr
eseguito solo il blocco di istruzioni corrispondente al primo caso trovato sequenzialmente
per poi passare direttamente alla prima istruzione dopo la parola chiave end.
Esempio: Un frammento di codice che, a seconda del valore dello scalare di tipo char
giorno, stampa a video se il giorno della settimana corrispondente lavorativo o no
riportato in seguito. Si considerano lavorativi i giorni da luned a venerd.
switch (giorno)
case {'l','m','g','v'}

%se giorno uguale al carattere


%'l', 'm', 'g' o 'v'
disp('Giorno lavorativo');
%stampa 'Giorno lavorativo'
case {'s','d'%se giorno uguale al carattere
%'s' o 'd'
disp('Giorno feriale'); %stampa 'Giorno feriale'
otherwise
%se giorno diverso da tutti i casi precedenti
disp('Errore!');
%stampa 'Errore!'
end

55

O in alternativa
switch (giorno)
case {'lun','mar','mer','gio','ven',}
disp('Giorno lavorativo');
case {'sab','dom'
disp('Giorno feriale');
otherwise
disp('Errore!');
%stampa 'Errore!'

3.2.

Cicli

I cicli sono una struttura di controllo che permette di ripetere la stessa sequenza di
istruzioni, elementari o complesse, pi volte, a seconda della valutazione di una data
condizione. In MATLAB esistono tre tipi di cicli che verranno analizzati in dettaglio in
questa sezione.

3.2.1. Il ciclo while


Un ciclo while una porzione di codice che permette di eseguire pi volte la stessa
sequenza di istruzioni e si presenta sintatticamente nel seguente modo:
while espressione
istruzione1
istruzione2
...
end

%blocco

Quando tale porzione di codice viene eseguita, viene prima di tutto valutato il valore di
verit di espressione. Qualora questo risulti vero, vengono eseguite le istruzioni
contenute in blocco. Una volta eseguita l'ultima istruzione, invece che passare a eseguire
la prima istruzione eseguibile dopo la parola chiave end si torna ad analizzare il valore di
verit di espressione e, qualora risulti ancora vero, si procede nuovamente a eseguire le
istruzioni di blocco. Si continua in questo modo finch espressione non assume il
valore false. In quel caso si passa direttamente alla fine della struttura e viene eseguita la
prima istruzione eseguibile dopo la parola chiave end. Graficamente, tale costrutto si pu
rappresentare attraverso il seguente diagramma a blocchi:

56

Si noti che, in generale, non possibile sapere quante volte verr ripetuto il blocco di
istruzioni contento in un costrutto while, ma che tale numero dipende dall'espressione di
controllo e da come le variabili contenute in tale espressione variano all'interno del blocco.
Esempio: Un frammento di codice che calcola la media di una sequenza numerica letta da
tastiera riportato in seguito.
Nel frammento la lettura da tastiera della sequenza si interrompe appena viene inserito un
valore non positivo.
n=0;
%numero di elementi letti
sum=0;
%somma dei valori letti
x=input('Inserisci un numero:'); %lettura del primo numero
while x>0
%se il numero letto positivo
n=n+1;
%incremento il numero di elementi
%letti
sum=sum+x;
%aggiungo x alla somma dei numeri
%letti
x=input('Inserisci un numero:');
%leggo un nuovo numero
%torno a valutare la condizione
end
if n>0
%se ho letto almeno un numero
%positivo
media=sum/n;
%calcolo la media
else
%altrimenti
media=0;
%la media 0
end

Se, ad esempio, inizialmente viene inserito il valore 4, avremo x=4, per cui la condizione
del while risulta vera. Si passa quindi a incrementare il valore di n, che diventa 1 e a
sommare a sum il valore di x, ottenendo sum=4.
A questo punto si legge un nuovo numero da tastiera. Se tale valore , ad esempio 2,
avremo x=2.
Per tale valore la condizione del while risulta vera. Si passa quindi a incrementare il
valore di n, che diventa 2 e a sommare a sum il valore di x, ottenendo sum=6, passando
nuovamente a leggere un nuovo numero da tastiera. Se tale valore , ad esempio -3,
avremo x=-3, che non rispetta la condizione del while. Si passa quindi alla prima
istruzione eseguibile dopo il ciclo while, cio la valutazione della condizione del costrutto
if. La variabile n pari a 2, per cui la condizione dell' if risulta vera e media risulta essere
sum/n, cio 3.
Si noti che il costrutto if potrebbe essere sostituito dalle istruzioni:
media = 0;
media = n>0 && sum/n;

infatti media assume il valore 0 e cambia il suo valore in sum/n solo se n positivo, cio se
ho letto almeno un numero positivo.

57

3.2.2. Il ciclo for


Un altro modo per ripetere pi volte la stessa sequenza di istruzioni attraverso l'uso del
ciclo for. A differenza che nel ciclo while, nel ciclo for generalmente possibile
conoscere a priori il numero di volte per cui tale ciclo verr ripetuto. La sintassi del ciclo
for la seguente:
for indice=espressione
istruzione1
...
end

dove indice una variabile, chiamata indice del ciclo, e espressione l'espressione di
controllo del ciclo, che viene valutata come un array.
Generalmente espressione ha la forma:
primo:incremento:ultimo

che corrisponde alla notazione abbreviata per l' array:


[primo primo+incremento ... ultimo-incremento ultimo].

Quando l'incremento 1, l'espressione pu assumere la forma:


primo:ultimo

che corrisponde all'array:


[primo primo+1 ... ultimo-1 ultimo].

L'esecuzione di un ciclo for avviene nel seguente modo: all'inizio del ciclo, MATLAB
costruisce un array come risultato della valutazione di espressione. Alla prima
esecuzione del blocco di istruzioni contenute nel ciclo, indice assume il valore della
prima colonna dell'array generato e, con tale valore di indice, vengono eseguite le
istruzioni del blocco. Dopo l'esecuzione del blocco, indice assume il valore della colonna
successiva dell'array generato e, con quel valore, esegue nuovamente il blocco. Questo si
ripete finch non sono state utilizzate sequenzialmente tutte le colonne dell'array generato.
Esempio: Un frammento di codice che legge da tastiera 10 numeri e li inserisce in un
vettore di nome numeri il seguente:
for n=1:10

%Per ogni valore del vettore


%[1 2 3 4 5 6 7 8 9 10]
numeri(n)=input('Inserisci numero');
%inserisco nell'elemento corrispondente
%di numeri un valore letto da tastiera

end

Esempio: Un frammento di codice che somma gli elementi in posizione pari di un vettore A
di 10 elementi il seguente:
somma=0;
for n=2:2:10
somma=somma+A(n);

%inizializzazione
%per ogni elemento di [2 4 6 8 10]
%aggiungo a somma il valore in posizione
%corrispondente di A

end

58

Se A=[12 3 2 11 4 7 1 5 8 9], alla prima iterazione il valore di A(2) viene sommato


a somma, ottenendo somma=3. Alla seconda iterazione il valore di A(4) viene aggiunto a
somma, che diviene pari a 14 e cos via fino a sommare A(10). Alla fine somma pari a
3+11+7+5+9, cio 35.

Esempio: Un frammento di codice che, letto da standard input un numero, stampa a video
il conto alla rovescia a partire da quel numero, il seguente
fine=input('Tempo a disposizione:');
for n=fine:-1:1
pause(1);
%funzione predefinita che attende un un'unit di
%tempo prima di passare alla successiva
%istruzione eseguibile
fprintf('%g secondi rimasti\n', n);
end

L'array utilizzato per assegnare i valori a indice pu essere un vettore riga, una stringa o
una matrice. In tutti e tre i casi a indice verranno assegnate in sequenza, partendo da
sinistra verso destra, le colonne dell'array. In caso di vettori riga a ogni iterazione indice
sar uno scalare, in caso di stringhe a ogni iterazione indice sar un carattere e in caso di
matrice a ogni iterazione indice sar invece un vettore colonna.
Esempio: Un frammento di codice per leggere da tastiera 10 numeri e inserirli in un vettore
di nome numeri, nelle posizioni di numeri specificate da un vettore riga indici il
seguente:
indici=[3 7 21 12 2 4 11 1 13 9]
for n=indici
numeri(n)=input('Inserisci numero');
end

Se vengono inseriti in sequenza i numeri 1, 2, 3, 4, 5, 6, 7, 8, 9 e 10, il vettore numeri


diventer [8 5 1 6 0 0 2 0 10 0 7 4 9 0 0 0 0 0 0 0 3]. Infatti alla prima
iterazione del ciclo viene letto 1 e inserito in numeri(3), creando il vettore [0 0 1], alla
seconda iterazione viene letto 2 e inserito in numeri(7) creando il vettore [0 0 1 0 0 0
2] e cos via. Alla fine del ciclo n varr 9.

Esempio: Un frammento che permetta di stampare a video, a uno a uno, con una pausa,
tutti gli elementi di una stringa x il seguente:
for n=x
display(n);
pause(1);
end

Se ad esempio x fosse la stringa 'informatica', il ciclo verrebbe eseguito undici volte e


alla prima iterazione n assumerebbe il valore 'i', alla seconda 'n' e cos via.

59

Esempio: Un frammento che stampa a video il massimo di ciascuna colonna di una matrice
A il seguente:
for n=A
fprintf('Il massimo %g\n', max(n));
end

Se ad esempio A fosse la matrice A=[1 5 7; 1 12 33; 35 4 2],


il ciclo verrebbe eseguito tre volte e alla prima iterazione n assumerebbe il valore del
vettore colonna [1; 2; 11; 35] e a video verrebbe stampato 35, alla seconda iterazione
n assumerebbe il valore del vettore colonna [5; 4; 12; 4] e a video verrebbe stampato
12, e all'ultima iterazione n assumerebbe il valore del vettore colonna [7; 1; 33; 2] e a
video verrebbe stampato 33.
Come precedentemente osservato le istruzioni contenute all'interno di un ciclo possono
essere di qualunque tipo. Quindi possibile avere cicli annidati.

Esempio: Un frammento di codice che permette di leggere da tastiera, riga per riga, i valori
da inserire in una matrice 3x5 il seguente
for n=1:3
%per ogni valore di [1 2 3]
for m=1:5
%per ogni valore di [1 2 3 4 5]
A(n,m)=input('Inserisci numero');
end
end

Alla prima iterazione del ciclo esterno (quello con indice n), n vale 1. Per tale valore di n si
esegue tutto il ciclo interno (quello con indice m). Andando quindi a inserire i primi 5 valori
letti da tastiera in A(1,1), A(1,2), A(1,3), A(1,4) e A(1,5), cio la prima riga. Si
passa quindi a un nuovo valore di n, procedendo analogamente.

Esempio: Un frammento di codice che permette, partendo da una matrice 3x5 A, di creare
due vettori riga, uno che contiene solo gli elementi positivi di A, l'altro che contiene solo gli
elementi negativi A il seguente:
x=1;
%indice usato per il vettore positivi
y=1;
%indice usato per il vettore negativi
for n=1:3
%per ogni indice di riga
for m=1:5
%per ogni indice di colonna
if A(n,m)>0 %se l'elemento considerato positivo
positivi(x)=A(n,m)
%inserisco il numero in positivi
x=x+1;
%incremento l'indice
elseif A(n,m)<0
negativi(y)=A(n,m)
y=y+1;
end
end
end

60

Per ogni iterazione del ciclo esterno si eseguono tutte le iterazioni del ciclo interno. Se, ad
esempio, A=[2 5 -11 15 -2; 3 -1 -3 6 7; -6 1 11 -8 -9], inizialmente si valuter la prima riga
(n=1), analizzando in sequenza tutti gli elementi (ciclo interno), inserendo 2 in
positivi(1) e incrementando x, 5 in positivi(2) e incrementando x, -11 in
negativi(1) e incrementando y, 15 in positivi(3) e incrementando x, -2 in
negativi(2) e incrementando y. Alla fine si ottiene
positivi=[2 5 15 3 6 7 1 11]

e
negativi=[-11 -2 -1 -3 -6 -8 -9].

3.2.2.1. Regole di buona programmazione


Quando si usa un ciclo for bisogna tenere a mente alcune norme di buona
programmazione:
Non modificare l'indice all'interno del ciclo: la variabile indice generalmente
utilizzata come contatore all'interno del ciclo. Modificarne il valore esplicitamente
all'interno pu causare errori che sono difficili da trovare. Ad esempio, se
consideriamo il seguente frammento di (pseudo-)codice:
for n=1:5
...
n=2;
operazioni su numeri(n);
end

le operazioni su numeri(n) verranno, a ogni iterazione del ciclo, svolte


sull'elemento in posizione 2, invece che sull'elemento in posizione corrispondente
all'iterazione corrente.
Preallocazione degli array utilizzati all'interno di cicli: questa pratica permette di
rendere pi veloce l'esecuzione del codice. Infatti ogni volta che all'interno di un
ciclo viene utilizzata una posizione successiva di un array non inizializzato,
MATLAB allunga l'array aggiungendo la nuova posizione o eventualmente le
nuove posizioni. In realt, quando MATLAB allunga un array crea un nuovo
array delle dimensioni necessarie, copia la prima parte dell'array dall'array
precedente, aggiunge i nuovi elementi e cancella il vecchio array. Se si usa un
array non inizializzato all'interno di un ciclo, MATLAB deve ripetere queste
operazioni a ogni iterazione, rallentando notevolmente la velocit di esecuzione
del codice. buona norma quindi creare gli array prima dei cicli in cui essi
verranno utilizzati, attribuendo a essi la dimensione massima che raggiungeranno
all'interno del ciclo.

3.2.2.2. Vettorizzazione
Nella pratica spesso possibile sostituire un ciclo for con l'uso di un semplice array, con
un processo chiamato processo di vettorizzazione. Infatti, abbiamo visto che un ciclo for
viene eseguito assegnando alla variabile indice tutte le colonne dell'array generato
dall'espressione di controllo. Qualora all'interno del ciclo si eseguano solo operazioni
sull'indice, che possono essere sostituite dall'equivalente operazione su vettori, il ciclo pu
essere evitato tramite il processo di vettorizzazione.

61

Per meglio capire questo processo, si consideri il seguente esempio, che permette di
calcolare il quadrato, la radice quadrata e la radice cubica dei numeri tra 1 e 100.
for n=1:100
square(n)=n^2;
square_root(n)=n^(1/2);
cube_root(n)=n^(1/3);
end

Tale frammento di codice esegue un ciclo 100 volte, per tutti i valori del vettore [1 2 3
... 99 100], e per ciascuno di questi valori inserisce nella corrispondente posizione di
square, square_root e cube_root il quadrato, la radice quadrata e la radice cubica di
tale numero. Si noti che, per quanto detto nella sezione precedente, se i vettori square,
square_root, cube_root non esistono gi, sarebbe buona norma crearli prima
dell'esecuzione del ciclo. Lo stesso risultato si pu ottenere mediate la vettorizzazione, nel
seguente modo:
n=1:100
square(n)=n.^2;
square_root(n)=n.^(1/2);
cube_root(n)=n.^(1/3);

Inizialmente si crea il vettore n=[1 2 3 ... 99 100] e poi si crea square come un
vettore di 100 elementi in cui, in ciascuna posizione c' il quadrato del corrispondente
elemento di n. Si procede analogamente per square_root e cube_root.
Anche se i due frammenti portano allo stesso risultato, in realt, il secondo viene eseguito
molto pi velocemente del primo. quindi consigliabile applicare il processo di
vettorizzazione tutte le volte in cui possibile.

3.2.3. Break e Continue


Durante lesecuzione di un ciclo potrebbe essere necessario passare all'iterazione successiva
senza completare le istruzioni del ciclo nell'iterazione corrente o terminare il ciclo. Anche
se entrambi i casi possono essere gestiti con i costrutti che conosciamo, esistono istruzioni
particolari per ottenere direttamente questo effetto. Nel primo caso, infatti, si pu usare
continue, che porta immediatamente a valutare la condizione del ciclo. Nel secondo caso
si pu utilizzare break, che interrompe il ciclo e porta alla prima istruzione dopo il ciclo.
Esempio: Codice che stampa a video tutti i numeri tra 1 e 100 tranne il 3 il seguente:
for n=1:1000
if n==3
%se n 3 (alla terza iterazione) salta
continue;
%all'iterazione successiva (cio n=4)
end
fprintf('%d\n', n);
end

Si noti che questo problema si pu risolvere senza luso di continue nel seguente modo:
for n=1:1000
if n~=3 %se n non 3 (tutte le iterazioni tranne la terza)
fprintf('%d\n', n);
end
end

62

Esempio: Un frammento di codice per acquisire numeri da tastiera finch non viene
inserito un numero negativo e in ogni caso non accettarne pi di mille il seguente:
vector=[] %crea un vettore vuoto
for count=1:1000
value=input('Prossimo numero')
if value<0
%se il valore letto negativo
break;
%esci dal ciclo
else
vector(end+1)=value;
end
end

Si noti che questo problema si pu risolvere senza luso di break nel seguente modo:
vector=[]; %crea un vettore vuoto
flag=1;
count=1;
while flag & count<1000
value=input('Prossimo numero')
if value<0
%se il valore letto negativo
flag=0;
%metti il valore di flag a 0, rendendo
%falsa la condizione del while
else
vector(count)=value;
count=count+1;
end
end

3.3.

Array Logici

Nel capitolo precedente sono stati introdotti i tipi logici, osservando come sia possibile
costruire anche array di tale tipo. Un' importante propriet di tali array che essi possono
funzionare da maschere per le operazioni aritmetiche. Una maschera un array che serve
per selezionare elementi in un altro array della stessa dimensione, in modo da applicare
un'operazione solo sugli elementi selezionati e non sugli altri.
Si consideri ad esempio il problema di creare un vettore con tutti e soli gli elementi positivi
di un vettore di 100 elementi di tipo double chiamato numeri. Tale problema pu essere
risolto con i costrutti for e if nel seguente modo:
k=0;
for n=1:100
if numeri(n)>0
numeri_positivi(k)=numeri(n);
k=k+1;
end
end

Si noti che la condizione numeri>0 genera un vettore logico con true in corrispondenza
dei valori positivi di numeri e false nelle altre posizioni. Tale vettore pu essere usato da
maschera selezionando solo gli elementi positivi di numeri. Utilizzando tali accorgimenti,
il problema precedente pu essere risolto da:
numeri_positivi=numeri(numeri>0);

63

I due frammenti di codice sono equivalenti dal punto di vista del risultato, ma il primo
viene eseguito molto pi velocemente del secondo.
Nel caso precedente abbiamo utilizzato un array logico per sostituire i cicli necessari per
scorrere la matrice e il costrutto if per selezionare gli elementi su cui applicare
l'operazione. In generale per possibile utilizzare gli array logici per rappresentare l'intero
costrutto if/else. Infatti, applicando l'operatore logico di negazione ~ a un array logico,
si selezionano gli elementi che non sarebbero stati selezionati da quella maschera e non si
selezionano quelli che sarebbero stati selezionati, simulando cos il ramo else del
costrutto di selezione if.
Esempio: Si consideri ad esempio il problema di creare due vettori uno con tutti e soli gli
elementi positivi di un vettore di 100 elementi di tipo double chiamato numeri e l'altro
con tutti e soli gli elementi negativi di numeri. Tale problema, similmente a quanto visto
in un esempio precedente, pu essere risolto con i costrutti for e if nel seguente modo:
x=1;
y=1;
for n=1:100
if numeri(n)>0
numeri_positivi(x)=numeri(n);
x=x+1;
elseif numeri(n)<0
numeri_negativi(y)=numeri(n);
y=y+1;
end
end

Osservando che numeri>0 genera un vettore logico con true in corrispondenza dei valori
positivi di numeri e false nelle altre posizioni e ~(numeri>0) genera un vettore logico
con true in corrispondenza dei valori negativi di numeri e false nelle altre posizioni e
che tali vettori si possono utilizzare come maschere, il problema precedente pu essere
risolto da:
numeri_positivi=numeri(numeri>0);
numeri_positivi=numeri(~(numeri>0));

In seguito riportiamo ulteriori esempi di soluzioni che fanno uso di array logici e
vettorizzazione al posto dei costrutti for e if.

Esempio: Un frammento di codice che fa uso di array logici per sostituire in un array A gli
elementi >5 con la loro radice il seguente:
A(A>5)=sqrt(A(A>5));

Se A=[1 2 3 4 5 6 7 8 9], la condizione A>5 genera il vettore logico [false false


false false false true true true true], per cui A(A>5) seleziona solo gli
elementi di A che sono maggiori di 5 (cio 6, 7, 8, 9). Quindi in A gli elementi maggiori di
5 verranno sostituiti dalla loro radice quadrata, ottenendo A=[1 2 3 4 5 2.4495
2.6458 2.8284 3].

64

Esempio: Siamo interessati a risolvere il seguente problema. Considerate due matrici f1 ed


f2 rappresentanti due immagini e due valori numerici C ed S, con C<S, rappresentanti due
diversi colori, vogliamo creare una terza figura f3, ottenuta da f1 e f2, secondo la
seguente regola:
Nelle posizioni (r,c) in cui f1(r,c)<C ed f2(r,c)>C si ha f3(r,c)=f2(r,c)f1(r,c)

Nelle posizioni (r,c)in cui f1(r,c)>S ed f2(r,c)<S si ha f3(r,c)=f1(r,c)f2(r,c)

Nelle posizioni rimanenti si ha f3(r,c)=f1(r,c).


Tale problema pu essere risolto dal seguente frammento di codice:
A = f1<C & f2>C;
%Creo l'array logico che rappresenta la regola 1
B = f1>S & f2<S;
%Creo l'array logico che rappresenta la regola 2
f3 = f1;
%Creo f3 uguale a f1
f3(A) = f2(A) f1(A);
%In tutte le posizioni in cui vale la regola 1,
%metto f3 pari a f2 f1
f3(B) = f1(B) f2(B);
%In tutte le posizioni in cui vale la regola 2,
%metto f3 pari a f1 f2

Se, ad esempio, f1=[1 2 7;1 5 8;1 9 10] , f2=[4 3 4;1 2 5;1 8 2], C=3 e S=7
f1<C = true true false
true false false
true false false
f2>C = true true true
false false true
false true false
A =

true false false


false false false
false false false

f1>S = false false false


false false true
false true true
f2<S = true
true
true
B =

true true
true false
false true

false false false


false false false
false false true

per cui f3 diventa


f3 =

3 2 7
1 5 8
1 9 8

65

Capitolo Quarto: Sottoprogrammi definiti


dallutente: le funzioni

I sottoprogrammi sono moduli di codice che svolgono operazioni particolarmente


significative o di uso frequente. Tra i pi importanti motivi che ne giustificano
lintroduzione citiamo i seguenti
riusabilit: quando unoperazione viene svolta frequentemente e in vari contesti
utile definirla una volta per tutte con un sottoprogramma e richiamarla tutte le
volte che necessario senza doverla codificare di nuovo. Per esempio, nellambito
di applicazioni di tipo geometrico, il calcolo della lunghezza di una linea spezzata
pu essere necessario in contesti anche diversi, come il calcolo della lunghezza di
un cammino in un grafo o della lunghezza del perimetro di un poligono;
astrazione (economia di ragionamento): chi utilizza un sottoprogramma che
svolge una ben identificata operazione pu ragionare su di esso in modo semplice
e astratto prescindendo dai dettagli della sua codifica e costruendo a partire da esso
elaborazioni pi complesse;
estendibilit del linguaggio di programmazione: un sottoprogramma pu essere
impiegato in modo semplice, generale e flessibile, ottenendo unestensione del
linguaggio di programmazione simile allintroduzione di una nuova istruzione; in
effetti tutti i moderni linguaggi di programmazione possono essere estesi, per
essere utilizzati nei pi svariati ambiti, mediante librerie di sottoprogrammi.
I sottoprogrammi in MATLAB hanno alcune caratteristiche in comune agli script, per
esempio vengono scritti in appositi file, ma in aggiunta possiedono dei meccanismi di
incapsulamento, di visibilit selettiva delle variabili e di scambio delle informazioni che ne
aumentano grandemente la possibilit di riuso, poich li rendono meglio distinti dagli altri
programmi e fanno s che il loro significato sia largamente indipendente dal contesto.
Come indicato dallo stesso termine, un sottoprogramma asservito a un altro programma,
detto il programma principale. Il sottoprogramma lavora solo su richiesta o, come spesso
si dice, a seguito di una chiamata o invocazione da parte del programma principale (per
questo motivo il programma principale a volte detto, con riferimento a un
sottoprogramma, il suo programma chiamante). In uno scenario tipico, quando il
programma principale chiama il sottoprogramma, la sua esecuzione viene temporaneamente
sospesa, avviene un primo scambio di informazioni dal programma chiamante verso il
programma chiamato, lesecuzione del sottoprogramma ha inizio e precede fino al
completamento. A questo punto avviene uno scambio di informazioni in direzione opposta,
trasmettendo i risultati dal sottoprogramma al chiamante, e infine lesecuzione del
chiamante riprende dal punto dove era stata sospesa,.

66

4.1.

Definizione e uso delle funzioni

Ogni sottoprogramma caratterizzato da due elementi principali: loperazione da esso


realizzata e il modo in cui esso va utilizzato. Questo secondo aspetto a suo volta include il
modo in cui esso viene identificato dal programma chiamante, i dati che esso utilizza come
punto di partenza per la sua esecuzione, e i risultati prodotti.
Per illustrare questi elementi occorre innanzitutto tener presente che in MATLAB, come
peraltro in molti altri linguaggi di programmazione, i sottoprogrammi vengono definiti
facendo riferimento alla nozione matematica di funzione. Per questo motivo il termine
usuale con cui si indicano i sottoprogrammi quello di funzione, che pure noi adotteremo
nel seguito.
Una funzione della matematica mette in relazione ogni elemento di un insieme, detto
dominio, con al pi un elemento di un secondo insieme detto codominio. La relazione
definita dalla funzione pu essere interpretata in senso operazionale come una
trasformazione o un calcolo che, a partire da un valore appartenente al dominio, chiamato
spesso argomento della funzione, produce come risultato il corrispondente valore nel
codominio.
Per esempio, la funzione matematica fattoriale, che noi chiamiamo per brevit fact
visualizzandola in figura, a ogni numero naturale n N fa corrispondere un numero naturale
fact(n) pari al suo fattoriale (ci viene spesso indicato scrivendo per questa funzione
lindicazione del suo tipo, fact: N N).
fact
N

24 N

Nelle funzioni MATLAB il dominio corrisponde ai dati di partenza che vengono


inizialmente trasmessi dal programma principale, il calcolo viene svolto eseguendo le
istruzioni caratteristiche della funzione, e il codominio corrisponde ai risultati
dellesecuzione, trasmessi allindietro dalla funzione al programma chiamante.
Proseguendo lesempio della funzione matematica fattoriale, una funzione MATLAB che
calcola il fattoriale di un numero pu essere definita come segue.
function [f]=fact(n)
f=1;
for k=1:n
f=f*k;
end

testata: linterfaccia della funzione


corpo: la parte eseguibile

La funzione si chiama fact, ha un argomento, denominato internamente n, che il valore


di partenza, fornito dal programma chiamante, corrispondente al numero di cui si vuole
calcolare il fattoriale, e produce un risultato f, che verr restituito al programma chiamante
al termine dellesecuzione di fact. Si vede facilmente che il risultato f viene calcolato
mediante una serie di prodotti realizzati da un ciclo for, in cui si fa uso di una variabile
aggiuntiva. Osserviamo fin dora che n, f e k sono a tutti gli effetti delle variabili, in un

67

certo senso riservate alla funzione fact: sono distinte da tutte le variabili del programma
principale e sono a esso inaccessibili.
La definizione della funzione viene data una sola volta, mentre le chiamate della funzione
possono essere effettuate in numero arbitrario e fanno naturalmente tutte riferimento alla
stessa, unica definizione. Nella definizione distinguiamo due parti principali: la testata e il
corpo. La testata costituisce linterfaccia della funzione, nel senso che contiene
linformazione necessaria a chi scrive nel programma principale la chiamata della funzione.
Nel nostro esempio occorre conoscere lidentificatore della funzione ( fact), il fatto che
essa ha un argomento (n) e produce un risultato (f). Il corpo della funzione contiene le
istruzioni che, eseguite al momento della sua chiamata, permettono di ottenere i risultati a
partire dagli argomenti. Come gi notato, non molto importante che chi utilizza la
funzione prenda visione del corpo della funzione e ne comprenda esattamente la logica: gli
basta conoscere la testata.
Considerando in dettaglio la sintassi della testata, notiamo che in generale gli argomenti
della funzione possono essere in numero qualsiasi, maggiore o uguale a zero5. I nomi degli
argomenti vanno scritti tra le parentesi tonde che seguono il nome della funzione, separati
da una virgola. Tali variabili dono dette parametri formali in ingresso. Il termine formali
si riferisce al fatto che al momento della definizione della funzione non hanno un valore
proprio ma assumeranno un valore solo allatto dellesecuzione del sottoprogramma. Sono
dette in ingresso per levidente motivo che il loro valore viene fornito dal programma
chiamante e costituisce il punto di partenza per lesecuzione della funzione.
Anche i risultati possono essere in numero qualsiasi, maggiore o uguale a zero. I nomi per i
risultati vanno scritti tra parentesi quadre, separati da una virgola.
Di passaggio notiamo che si ammette anche il caso di una funzione con zero risultati: in
questo caso nella testata compare solo la coppia di parentesi quadre [] senza nulla in
mezzo, e il significato di ci che il sottoprogramma (il termine funzione in questo caso
inappropriato) non produce un risultato utile restituendo direttamente un valore al
programma chiamante bens in qualche altro modo, per esempio visualizzando qualche
espressione sullo schermo o scrivendo dei dati su file.
Le variabili elencate tra parentesi quadre nella testata della funzione sono dette parametri
formali in uscita. Il termine formali si riferisce ancora al fatto che al momento della
definizione della funzione non hanno un valore proprio ma assumeranno un valore solo
alla fine dellesecuzione del sottoprogramma. Sono dette in uscita perch il loro valore
verr trasmesso al programma chiamante al termine dellesecuzione della funzione.
Quindi la funzione fact del nostro esempio possiede un solo parametro formale in
ingresso, la variabile n, e un solo parametro formale in uscita, la variabile f.
Le funzioni vengono utilizzate mediante unistruzione di chiamata o invocazione. La
funzione fact pu essere utilizzata dalla linea di comando dellinterprete MATLAB (che
quindi funge da programma chiamante) nel modo seguente.
>> x=fact(4)
x =24

Listruzione di chiamata contiene un assegnamento del valore della funzione alla variabile
x. Si noti che sulla seconda riga riportata la risposta dellinterprete allistruzione di
5

Dal punto di vista matematico una funzione con zero argomenti una costante, un caso
particolare ma perfettamente ammissibile.

68

chiamata della funzione fact. Largomento della chiamata, il valore 4, e la variabile x a cui
viene assegnato il risultato sono in corrispondenza, rispettivamente, con il parametro
formale in ingresso n e con quello in uscita f. Per questo motivo il valore 4 detto
parametro attuale in ingresso, mentre la variabile x detta parametro attuale in uscita.
Il termine attuale si riferisce al fatto che questi parametri sono quelli che effettivamente
entrano in gioco, assumendo un ben preciso valore, al momento dellesecuzione della
chiamata.
Notiamo ancora una volta che la notazione adottata fortemente ispirata a quella della
matematica: una funzione, applicata a suoi argomenti, fornisce un valore del suo
codominio. Nei programmi MATLAB i valori sono denotati da espressioni, quindi
uninvocazione di funzione sintatticamente costituisce unespressione. Perci le chiamate di
funzioni possono essere inserite in tutti i punti in cui le regole sintattiche del linguaggio
MATLAB prevedono la presenza di unespressione (per esempio, a destra di un operatore
di assegnamento o in corrispondenza della condizione che governa listruzione
condizionale if).
Linvocazione di una funzione pu avvenire senza che il risultato venga esplicitamente
assegnato, da parte del programmatore, a un variabile come succedeva nellesempio
precedente. Nel seguente caso
>> fact(3)
ans = 6

linterprete MATLAB provvede a fornire come parametro attuale in uscita la ben nota
variabile predefinita ans. Questo esempio pu essere generalizzato a tutti i casi in cui la
chiamata di una funzione non compare a destra di un operatore di assegnamento, ma viene
utilizzata direttamente come espressione che denota il valore da essa calcolato. Si intende
che in questi casi linterprete introduca opportune variabili implicite che costituiscono i
necessari parametri attuali in uscita.
Come conseguenza di ci le espressioni costituite da chiamate di funzioni possono essere
composte a formare altre espressioni, come nel seguente esempio, largamente
autoesplicativo6.
>> x=fact(2)+fact(3)
x = 8

Inoltre i parametri attuali in ingresso alle chiamate di funzioni possono a loro volta essere
espressioni qualsiasi, purch di tipo appropriato, quindi nulla vieta che siano costituite da
invocazioni di funzioni, come nel seguente esempio 7.
>> fact(fact(3))
ans = 720

Si pu immaginare che linterprete MATLAB sostituisca al codice


x=fact(2)+fact(3) il codice equivalente w=fact(2);z=fact(3);x=w+z.
7
Notiamo che, mentre il parametro attuale di in ingresso di una chiamata di funzione pu
essere una qualsiasi espressione, un parametro attuale in uscita deve necessariamente essere
una variabile. Non avrebbe quindi senso scrivere unistruzione come 6=fact(3) perch
6 qui compare a sinistra di unistruzione di assegnamento. Al contrario lespressione
6==fact(3) viene senza problemi valutata a vero (valore numerico 1) mentre
lespressione 4==fact(3) viene valutata a falso (valore numerico 0).

69

Esattamente come in matematica, la valutazione avviene dallinterno verso lesterno: viene


calcolato prima fact(3), che vale 6, e poi fact(6).
Nel caso in cui una funzione possieda pi parametri in uscita o in ingresso, nella chiamata
devono essere presenti tanti parametri attuali quanti sono i parametri formali. La sintassi del
linguaggio prescrive che nella chiamata i parametri attuali siano racchiusi tra una coppia di
parentesi, tonde per quelli in ingresso e quadre per quelli in uscita, in analogia a quanto si
fa nella definizione della funzione, come illustrato dal seguente esempio. Per comodit del
lettore, si riporta nel riquadro a lato la definizione della funzione sumProd, che calcola nel
primo e nel secondo parametro in uscita, rispettivamente, la somma e il prodotto dei due
parametri in ingresso.
>> [x, y]=sumProd(4, 5)
x = 9
y = 20

function [s,p]=sumProd(a,b)
s=a+b;
p=a*b;

La sintassi della chiamata di funzione prevede quindi, nel caso di pi parametri in ingresso
e uscita, di scrivere la lista dei parametri attuali in uscita tra parentesi quadre, seguita
dalloperatore = di assegnamento, dallidentificatore della funzione e dalla lista dei
parametri attuali in ingresso tra parentesi tonde. La corrispondenza tra parametri attuali e
parametri formali, sia in ingresso sia in uscita, viene stabilita in base alla posizione: il
primo parametro attuale corrisponde al primo formale, il secondo al secondo e cos via 8.
Esiste una notazione abbreviata per la chiamata di una funzione con pi parametri in uscita,
quando si sia interessati a raccogliere solo il primo dei risultati. Si pu mettere a sinistra
delloperatore = di assegnamento anche soltanto il nome del primo dei parametri attuali.
In questo caso a tale variabile viene assegnato il primo dei risultati prodotti dalla funzione,
mentre gli altri risultati vengono semplicemente scartati. Questa possibilit illustrata dal
seguente, semplice esempio che si riferisce alla funzione sumProd sopra descritta9.
>> x=sumProd(4,5)
x = 9

4.1.1. La compatibilit tra parametri formali e attuali


I linguaggi di programmazione fortemente tipizzati impongono delle regole riguardo al tipo
del parametri attuali delle funzioni, per assicurare che essi siano compatibili con quelli dei
parametri formali. Come gi notato, in MATLAB il tipo delle variabili implicito (non
viene indicato al momento della dichiarazione, peraltro non prevista) e dinamico (pu
cambiare nel corso dellesecuzione). Come conseguenza di ci, non esiste di fatto alcun
8

Per completezza aggiungiamo che la sintassi sopra descritta, che prevede di racchiudere i
parametri attuali in uscita tra una coppia di parentesi quadre, pu essere adottata anche nel
caso di un solo parametro. Quindi, per esempio, si pu invocare la funzione fact degli
esempi precedenti scrivendo [x]=fact(3): la scrittura x=fact(3) in realt una
comoda abbreviazione di quanto prescritto dalla regola generale.
9
Ancora per completezza, precisiamo che listruzione di chiamata pu essere scritta in
modo da ricevere non solo il primo di n parametri in uscita, ma anche i primi k (con k<n),
usando, in questo caso obbligatoriamente, le parentesi quadre. Per esempio, se definita la
funzione function [s, p, d, q]=sumProdDiffQuot(a,b) che produce quattro
risultati, la chiamata [x, y, w]=sumProdDiffQuot(2, 3) permette al programma
chiamante di ricevere, nei parametri attuali x, y, w, il valore dei primi tre parametri formali
s, p, d.

70

vincolo sul tipo delle variabili che costituiscono parametri attuali in uscita per invocazioni
di funzione. Semplicemente, al parametro attuale in uscita viene assegnato il valore
assunto, al termine dellesecuzione della funzione, dal corrispondente parametro formale;
ci eventualmente comporta la modifica dinamica del tipo della variabile parametro attuale,
che pu sempre avvenire senza restrizioni.
Per quanto riguarda i parametri attuali in ingresso, devono invece essere rispettate delle
regole di compatibilit tra parametri attuali e formali che qui ci limitiamo a enunciare in
modo informale, ma ugualmente utile ai fini pratici. I parametri attuali in ingresso devono
avere, al momento della chiamata della funzione, un valore coerente con le operazioni che,
durante lesecuzione della funzione, vengono applicate al corrispondente parametro
formale. Per esempio, se il parametro formale (cio nel corpo della funzione esso viene
manipolato nellassunzione che il valore del corrispondente parametro formale sia) un
array, allora tale deve essere anche il corrispondente parametro attuale; se il parametro
formale una struct con un certo insieme di campi, allora tale deve essere anche il
parametro attuale etc.

4.1.2. Dove si scrive una funzione?


Per poter utilizzare le funzioni, sia chiamandole dalla linea di comando dellinterprete
MATLAB sia includendo le chiamate allinterno di script o di altre funzioni, occorre
scrivere le funzioni stesse in appositi file, chiamati file di funzione. Questi sono detti Mfile, perch richiesto che il loro nome abbia estensione .m, esattamente come per i file
che contengono script. Inoltre i file di funzione devono soddisfare le seguenti, semplici
condizioni. Essi devono avere esattamente lo stesso nome della funzione in essi definita, e
devono iniziare, sulla prima riga, con la testata della funzione, quindi la prima parola
contenuta nel file deve essere function (si noti che la parola va scritta in minuscolo).
Questo permette allinterprete MATLAB di distinguere un file di funzione da un file di
script. Inoltre, per permettere allinterprete di trovare il file di funzione, questo deve
trovarsi in una cartella che stia nella variabile PATH, la quale contiene la lista delle
locazioni in cui linterprete cerca i file definiti dagli utenti.
Nel definire nuove funzioni importante tener conto di possibili interferenze con funzioni
gi esistenti. In particolare, nel dare un nome alle nuove funzioni dovrebbero essere evitati
gli identificatori gi utilizzati per qualche funzione o variabile predefinita di MATLAB. A
tale scopo assai utile la funzione predefinita exist che, ricevendo come argomento un
identificatore, restituisce il valore 0 se non esiste alcuna variabile o funzione con quel
nome, o un valore diverso da 0 in caso contrario (per esempio, il valore 1 se lidentificatore
corrisponde a una variabile nello spazio di lavoro, 2 per un M-file nel path di MATLAB, 5
per a una funzione predefinita).
Un semplicissimo esempio illustra luso della funzione exist per verificare se
lidentificatore cos gi usato (cos denota la funzione predefinita per il coseno).
>> exist('cos')
ans = 5

4.1.3. La documentazione delle funzioni


Come in tutte le attivit di programmazione luso di opportuni commenti nel codice delle
funzioni ne facilita la comprensione e la manutenzione.
MATLAB incoraggia i programmatori a documentare sistematicamente le loro funzioni.
Mediante il comando help, disponibile dalla linea comando dellinterprete per ottenere

71

informazioni sulle funzioni predefinite, si possono anche ottenere automaticamente


informazioni su qualsiasi funzione definita in un M-file, a patto che in esso siano stati
inseriti opportuni commenti seguendo alcune semplici convenzioni.
Se si inserisce una serie di righe di commenti subito dopo la prima riga dellM-file (quella
che obbligatoriamente contiene la testata della funzione) help li riporta sulla finestra
principale, scrivendo il contenuto del file fino alla prima riga vuota o alla prima istruzione.
Illustriamo questa possibilit con un semplice esempio: nel riquadro a destra riportiamo il
contenuto di un ipotetico M-file con la definizione di una funzione chiamata dist2, mentre
a sinistra mostrato leffetto del lookfor ed help applicati a dist2.
>> help dist2
dist2: calcola la distanza euclidea
tra due punti(x1, y1) e (x2, y2)
in un sistema di coordinate
cartesiane a due dimensioni
>>

4.2.

function d=dist2(x1, y1, x2, y2)


%dist2: calcola la distanza euclidea
%tra due punti(x1, y1) e (x2, y2)
%in un sistema di coordinate
%cartesiane a due dimensioni
d = sqrt((x2-x1).^2+(y2-y1).^2);

Esecuzione delle funzioni e passaggio dei parametri

In questa sezione descriviamo in dettaglio, se pur da un punto di vista esterno, il


funzionamento dellinterprete durante lesecuzione delle funzioni. importante, in
particolare, chiarire il meccanismo di trasferimento di informazione nei due versi, dal
programma chiamante alla funzione chiamata e viceversa, e rendere conto del modo in cui
sono gestite le variabili appartenenti alle funzioni e al programma chiamante. Useremo
come esempio la funzione MCDmcm mostrata nel riquadro qui sotto, che calcola e restituisce
al chiamante, a partire da due numeri interi a e b, il loro massimo comune divisore MCD e
il minimo comune multiplo mcm10. Forniamo ora una descrizione, astratta e semplificata,
della sequenza di operazioni interne eseguite dallinterprete a seguito della chiamata della
funzione riportata qui sotto a sinistra.
>> r=12; s=42; [h,k]=MCDmcm(r, s)
h = 6
k = 84

function [M, m]=MCDmcm(a, b)


x=a; y=b;
while x ~= y
if x>y
x=x-y;
else
y=y-x;
end;
end;
M=x;
m=a*b/M;

Per facilitare la comprensione si evita di considerare una serie di dettagli implementativi


concettualmente irrilevanti e si fa uso di una metafora. Si immagina che allatto della
chiamata della funzione, quando lesecuzione del programma chiamante viene sospesa,
venga creata ex novo una nuova copia del calcolatore, chiamata macchina astratta,
dedicata allesecuzione della funzione e distinta dal calcolatore che esegue il programma
chiamante. Si ipotizza quindi che esista una macchina astratta principale per lesecuzione
del programmam chiamante e una macchina astratta asservita per lesecuzione della
funzione; ogni macchina astratta dotata di un proprio insieme di variabili, disgiunto da
quello dellaltra chiamato ambiente di esecuzione.
10

Per il massimo comune divisore si usa il noto algoritmo di Euclide, e il minimo comune
multiplo viene ricavato dalla nota uguaglianza mcm=a*b/MCM.

72

Nellesempio, lambiente della macchina principale contiene: due variabili r e s, argomenti


della chiamata (parametri attuali di ingresso), due variabili h e k cui sono assegnati i
risultati (parametri attuali di uscita), mentre lambiente della macchina asservita (ambiente
locale della funzione) contiene: i quattro parametri formali, due di ingresso, a e b, e due di
uscita, M ed m, che sono a tutti gli effetti delle variabili locali alla funzione, sono visibili
solo al suo interno ed esistono indipendentemente da altre eventuali variabili anche
omonime esterne, altre due variabili locali x e y.
Descriviamo quindi leffetto dellesecuzione della chiamata [h,k]=MCDmcm(r, s)
facendo riferimento alla numerazione dei passi nella figura successiva.
La macchina principale valuta lespressione a destra dellassegnamento =
nellistruzione che contiene la chiamata, quindi viene calcolato il valore dei
parametri attuali di ingresso r ed s;
Viene creata macchina asservita;
Avviene il passaggio dei parametri in ingresso mediante copiatura del valore
parametri attuali in ingresso (r ed s) nei corrispondenti parametri formali a e b;
Viene ceduto il controllo alla macchina asservita (lesecuzione macchina
principale sospesa) ed eseguito il corpo della funzione, calcolando il valore di M
ed m;
Avviene passaggio dei parametri in uscita mediante di uscita ( M ed m) mediante
copiatura nei corrispondenti parametri attuali h e k;
La macchina asservita (con tutto il suo ambiente) viene distrutta e viene
restituito il controllo alla macchina principale, che riprende la sua esecuzione.

r:12

s:42

h:

k:

MCDmcm

x:

a:

b:

M:... m:

r:12

s:42

(1)

MCDmcm

x:

a:12

b:42

M:... m:

r:12

s:42

h:

k:

x:6

y:6

a:12

b:42

M:6

m:84

r:12

s:42

h:

k:

y:

principale

(2)

MCDmcm

(4)

k:

principale

principale

principale

h:

y:

(3)

MCDmcm

x:6

y:6

MCDmcm

x:6

y:6

a:12

b:42

M:6

m:84

a:12

b:42

M:6

m:84

r:12

s:42

h:6

r:12

s:42

h:6

principale

k:84

k:84

principale
(5)

(6)

Ribadiamo ancora una volta che gli ambienti della macchina principale e di quella asservita
sono disgiunti, essi comunicano esclusivamente attraverso i parametri. Ambienti disgiunti,

73

del programma chiamante e della funzione chiamata, potrebbero anche contenere variabili
omonime, che rimangono in ogni caso distinte.
Quindi il programma chiamante e la funzione possono fare uso di variabili con lo stesso
nome: esse rimangono distinte, senza pericolo di confusione proprio perch appartenenti ad
ambienti diversi. Si noti inoltre che al termine dellesecuzione di una funzione non rimane
traccia del suo ambiente.
Come esempi di quanto affermato, consideriamo le chiamate della funzione MCDmcm
mostrate nella seguente figura:
>> x=12;y=42;[h,k]=MCDmcm(x,y)
Le variabili x e y, parametri attuali, sono
h = 6
distinte dalle variabili x e y locali alla
k = 84
funzione
>> [x,y]
Il parametro formale a della funzione
ans = 12
42
MCDmcm invisibile dal programma
>> a
??? Undefined function or variable 'a'.chiamante
Nessun pericolo di confusione tra variabili
omonime nei due ambienti, la
comunicazione avviene mediante copiatura

>> M=12;m=42;[a,b]=MCDmcm(M,m)
a = 6
b = 84
>>

4.2.1. Funzioni che chiamano funzioni


Nel parlare del programma che chiama una funzione abbiamo finora usato il termine
generico di programma principale. Negli esempi discussi finora la funzione definita
dallutente viene sempre chiamata dalla linea di comando dellinterprete dei comandi, che
funge quindi da programma principale. Ci sono per altre possibilit: unistruzione di
chiamata di funzione pu essere inclusa in uno script o anche in una funzione.
Illustriamo questultimo caso, particolarmente interessante anche perch si presta a sviluppi
che saranno discussi in una sezione successiva (le funzioni ricorsive). Consideriamo il
problema del calcolo del coefficiente binomiale

, il cui valore notoriamente

n!
k! n

. Definiamo una funzione coefBin che lo calcola facendo uso della funzione
k !

fact definita in precedenza. Il codice di tale funzione, riportato qui sotto, contiene tre
chiamate della funzione fact, una per ognuno dei tre fattoriali che compaiono nella sua
definizione.
function [c]=coefBin(n, k)
f1=fact(n);
f2=fact(k);
f3=fact(n-k);
c=f1/(f2*f3);

Quanto affermato nella presente sezione riguardo allesecuzione delle funzioni vale, senza
alcuna eccezione o modifica, anche nel caso in cui il programma chiamante sia una
funzione definita dallutente. Quando si verifica una chiamata di funzione dallinterno di
una funzione, lesecuzione della macchina astratta della funzione chiamante viene sospesa e
si crea unulteriore macchina astratta, col relativo ambiente delle variabili locali. Pu quindi
succedere che durante lesecuzione di funzioni, siano contemporaneamente in essere

74

numerose macchine astratte, anche se in ogni istante solo una di esse, quella creata per
ultima, attiva, nel senso che le sue istruzioni sono in corso di esecuzione. Se per esempio
viene effettuata la chiamata coefBin(6,2), oltre alla macchina astratta dellinterprete
comandi viene creata la macchina astratta della funzione coefBin e poi, prima che questa
termini, vengono create e poi cancellate, in sequenza, le tre macchine astratte per il calcolo
di fact(6), di fact(2) e di fact(4), secondo quanto tratteggiato in figura, dove per
semplicit non si riportano tutti i dettagli delle macchine astratte, ma si evidenzia solo
lordine in cui esse vengono create e dismesse.
fact(6)
coefBin(6,2) coefBin(6,2)

fact(2)
coefBin(6,2) coefBin(6,2)

interprete
comandi

interprete
comandi

interprete
comandi

interprete
comandi

interprete
comandi

(1)

(2)

(3)

(4)

(5)

fact(4)
coefBin(6,2) coefBin(6,2)

coefBin(6,2)

interprete
comandi

interprete
comandi

interprete
comandi

interprete
comandi

(6)

(7)

(8)

(9)

importante notare che lordine tale per cui la prima macchina astratta a essere dismessa
quella che stata creata per ultima. Se, come mostrato in figura, le macchine astratte
vengono disegnate una sopra laltra mettendo quelle create pi recentemente nella parte
alta, si ottiene una pila di macchine astratte, che cresce e decresce sempre alla stessa
estremit, quella superiore. Si parla in proposito di gestione LIFO (Last In First Out), una
nozione che trova numerose applicazioni anche al di fuori dellinformatica e
dellingegneria.

4.2.2. Confronto tra funzioni e script


Luso delle macchine astratte per illustrare le chiamate di funzioni ci permette di effettuare
un puntuale confronto tra funzioni e script, evidenziando alcune cruciali differenze.
Gli script non hanno un proprio ambiente di esecuzione: esiste un unico ambiente valido sia
per il programma principale sia per lo script, quindi non c distinzione tra le variabili del
programma chiamante e quelle dello script. La trasmissione di informazione dal programma
principale allo script avviene per il fatto che le variabili del programma principale possono
essere lette dalle istruzioni dello script. Eventuali nuove variabili create durante
lesecuzione dello script continuano a esistere anche dopo la terminazione dello script. La
comunicazione nel verso opposto, dallo script al programma principale, avviene attraverso
la scrittura di variabili che il programma principale legge dopo la terminazione dello script.
La conseguenza di ci che il programma principale e lo script sono legati tra di loro in
modo molto pi stretto che nel caso di una funzione. Uno script che legge valori da
variabili create nel programma principale dipendente da tale contesto: pu essere usato da

75

programmi che possiedono variabili aventi esattamente quel nome e significato, ma non da
altri. La comunicazione tra programma chiamante e funzioni avviene in modo molto pi
ordinato e privo di rischi di effetti indesiderati. Luso dei sottoprogrammi permette quindi
di rispettare importanti principi di progettazione modulare (le unit di programma devono
avere alta coesione interna e interfacce identificate molto chiaramente e minimali), che
rivestono grande importanza nellingegneria del software e nellingegneria dei sistemi.
Illustriamo questi concetti con un esempio, in cui codifichiamo il calcolo della distanza tra
due punti in un piano cartesiano mediante uno script o una funzione.
% script per il calcolo
della
% distanza tra due punti
% sta nel file distScript.m
dx = x2 x1;
dy = y2 y1;
d = sqrt(dx^2 + dy^2);

function [d] =
distFunz(x1,y1,x2,y2)
dx = x2 x1;
dy = y2 y1;
d = sqrt(dx^2 + dy^2);

Immaginiamo di avere quattro punti: a(1,1), b(1,2), c(3,2) e d(3,4); supponiamo di aver
memorizzato le loro coordinate nelle variabili ax, ay, bx, by, cx, cy, dx e dy, mediante le
seguenti istruzioni, eseguite nel programma principale, per esempio dallinterprete
comandi.
>> ax = 1; ay = 1; bx = 1; by = 2;
>> cx = 3; cy = 2; dx = 3; dy = 4;

Si vuole calcolare la distanza tra i punti a e b e tra c e d, memorizzando i risultati


rispettivamente nelle variabili Dab e Dcd. I due riquadri sottostanti riportano le istruzioni
per eseguire tale calcolo, usando lo script oppure la funzione.
>>
>>
>>
>>
>>
>>
>>
>>

x1=ax; y1=ay; x2=bx; y2=by;


distScript
Dab = d
1 *****
x1=cx; y1=cy; x2=dx; y2=dy;
distScript
Dcd = d
**** errato

>>
Dab=distFunz(ax,ay,bx,by)
>> 1 *****
>>
Dcd=distFunz(cx,cy,dx,dy)
>> 1 *****

Si pu notare innanzitutto che il codice che impiega la funzione molto pi conciso, perch
listruzione di chiamata della funzione incorpora anche le operazioni di assegnamento dei
parametri attuali in ingresso ai corrispondenti parametri formali e, nellaltro verso, del
parametro formale in uscita al corrispondente parametro attuale. Ma ci che pi conta il
fatto che nel caso dello script si verifica un errore a causa del doppio uso delle variabili dx e
dy: nel programma chiamante esse memorizzano le coordinate del punto d, nello script la
differenza di ascissa e di ordinata tra i due punti. A causa di ci durante il calcolo della
distanza tra i punti a e b si verifica un effetto indesiderato: la modifica delle coordinate del
punto d, che poi naturalmente porta a un errore; si noti anche che tale errore potrebbe
passare del tutto inosservato, perch non esiste alcun meccanismo automatico che segnala
lassegnamento di valori alla stessa variabile nel programma principale e nello script. Al
contrario, nella funzione, le due variabili dx e dy appartengono allambiente locale e non
interferiscono con le variabili omonime del programma chiamante.

76

Da questo esempio si evince che uno script e il programma che ne fa uso non possono
essere sviluppati in modo separato e indipendente: occorre stabilire un insieme di variabili,
comuni allo script e al programma principale, da riservare esclusivamente per la
comunicazione tra di essi; inoltre gli insiemi delle variabili usate dai due programmi
(diverse da quelle utilizzate per la comunicazione) dovranno essere disgiunti, pena il
verificarsi di effetti collaterali indesiderati come quello sopra illustrato.

4.3.

Esempi di funzioni con vari tipi di parametro

Una delle caratteristiche pi apprezzabili in un linguaggio di programmazione la


componibilit dei suoi costrutti, che ne facilita lapprendimento e lutilizzo. Nelle funzioni
MATLAB si verifica una totale componibilit dei meccanismi di passaggio dei parametri
con i diversi tipi di dati che possono essere manipolati nel linguaggio. Ci significa che,
senza eccezioni, possibile passare come parametro di una funzione uno scalare, un
vettore, una matrice, una struct, un vettore di struct etc. Nel seguito illustriamo questa
possibilit con alcuni semplice esempi, introducendo, ove necessario, nuovi costrutti per la
gestione dei parametri formali dei vari tipi.

4.3.1. Parametri di tipo array


Le funzioni MATLAB ammettono parametri di tipo array, sia in ingresso sia in uscita. Nel
definire una funzione avente un array come parametro in ingresso, occorre spesso far
riferimento alle dimensioni di tale array, che per non sono note, sia perch esse possono
variare da una chiamata allaltra, sia perch al momento della definizione della funzione,
quando si scrive il codice del suo corpo, si ignora completamente quali saranno i parametri
attuali.
A esempio, per scandire in sequenza tutti gli elementi di un array passato come parametro
si usa tipicamente un ciclo for, quindi occorre sapere quanti sono tali elementi.
Per indicare il numero degli elementi di un parametro formale di tipo array v si usa quindi
la funzione predefinita length(v).
Illustriamo luso della funzione length definendo una funzione cerca che, ricevendo
come parametri in ingresso un array v, e uno scalare x, effettua una ricerca dello scalare
nellarray, determinando tutte le posizioni in cui esso compare; in uscita la funzione cerca
fornisce il parametro pres, nullo se x non compare in v, pari a 1 se invece in esso
presente, e un array pos che contiene tutte le posizioni in v in cui si trova una ripetizione di
x. Si noti che larray pos viene costruito incrementalmente, come si gi visto fare in
esempi precedenti. Se il valore x non compare in alcuna posizione dellarray v, al termine
dellesecuzione il parametro formale in uscita pos uguale allarray vuoto [].
Nel riquadro di destra mostrata la definizione della funzione cerca e in quello di sinistra
una sua invocazione dalla linea di comando dellinterprete.

77

>> A=[1,2,3,4,3,4,5,4,5,6]
A = 1 2 3 4 3 4 5 4 5 6
>> [p, i]=cerca(4,A)
p =
1
i = 4 6 8
>>

function [pres,pos]=cerca(x,v)
p=0; pos=[];
for i=1:length(v)
if v(i)==x
p=p+1;
pos(p)=i;
end
end
pres=p>0;

La funzione predefinita length(v) viene valutata dallinterprete al momento


dellesecuzione della funzione cerca, e viene applicata di volta in volta al parametro
attuale corrispondente al parametro formale v.
Per esempio eseguendo [p, i]=cerca(4,A) length(v) fa s che venga valutato il
numero di elementi del parametro attuale A, che vale 10.

4.3.2. Parametri di tipo matrice


Le matrici (o anche gli array con un numero qualsiasi n di dimensioni) possono costituire
parametri in ingresso e anche in uscita delle funzioni MATLAB.
Anche per essi occorre conoscere le dimensioni del parametro in ingresso, e si usano
opportune funzioni predefinite, in modo da poterle indicare in modo simbolico senza
bisogno di conoscere i parametri attuali. Si ha, rispetto al caso degli array, una maggiore
complessit a causa del fatto che in generale una matrice potrebbe avere pi indici (una
matrice bidimensionale ha due indici, uno per le righe e uno per le colonne, una
tridimensionale ne ha tre etc.). Si usano allo scopo le seguenti funzioni predefinite
ndims(v) restituisce il numero n delle dimensioni di v
size(v) restituisce un array con n valori (dove n=ndims(v)) uguali al numero di
elementi per ognuna delle dimensioni di v; per esempio, se m una matrice a due
dimensioni la chiamata [R,C]=size(m) d, in R e in C, rispettivamente, il numero delle
righe e delle colonne di m.

Illustriamo questo costrutto con la semplice funzione


function [t]=trasposta(m)

che crea una matrice t con righe e colonne scambiate rispetto alla matrice ingresso m. Il
codice della funzione riportato qui sotto. Si noti peraltro che loperazione di trasposizione
di una matrice presente come predefinita in MATLAB.
function [t]=trasposta(m)
[R,C]=size(m);
for r=1:R
for c=1:C
t(c,r)=m(r,c);
end;
end

4.3.3. Parametri di tipo struct


Le funzioni MATLAB ammettono senza restrizioni parametri di tipo struct, ma in questo
caso emerge un inconveniente che deriva dallassenza, in questo linguaggio, di

78

dichiarazioni esplicite dei tipi. Al momento della definizione della funzione non c alcun
controllo che il nome e il tipo di ogni campo delle struct che compaiono come parametro
formali siano corretti, cio corrispondano ai corrispondenti campi dei parametri attuali
(simmetricamente, al momento in cui si assegnano valori a una variabile struct che
costituisce il parametro attuale di una funzione non vi alcun controllo che essa sia definita
in modo consistente con il corrispondente parametro formale). In linguaggi fortemente
tipizzati (citiamo nuovamente come esempio C e Java) obbligatorio dichiarare ogni nuovo
tipo e attribuire esplicitamente un tipo a ogni variabile e a ogni parametro di funzione. Ci
fornisce un utile promemoria per il programmatore (e, quando chi scrive il programma
chiamante e il sottoprogramma sono due persone distinte, costituisce quasi un accordo: si
parla infatti di programmazione per contratto), ma soprattutto permette al compilatore di
effettuare dei controlli statici (allatto della compilazione) evitando di mandare in
esecuzione programmi inconsistenti.
In MATLAB, purtroppo, non dovendo dichiarare i nuovi tipi n attribuire un tipo a ogni
variabile e parametro, spesso il nome e tipo dei campi di una struttura non viene nemmeno
definito esplicitamente, ma deriva in modo implicito dalle istruzioni del programma
chiamante e della funzione. Pu quindi accadere che la funzione e il programma chiamante
usino in modo inconsistente i parametri rispettivamente attuali e formali di tipo struct, e che
ci emerga solo al momento dellesecuzione del programma.
Consideriamo lesempio della funzione
function [c]=polar2cart(p)

che permette di passare dalla rappresentazione polare di punto nel piano a quella cartesiana
(si noti che la funzione polar2cart assume che il parametro attuale sia una struct con
campi ro e teta).
function [c]=polar2cart(p)
c.x=p.ro*cos(p.teta);
c.y=p.ro*sin(p.teta);

P
polar2cart

79

La chiamata mostrata qui sotto si svolge correttamente.


>> P.ro=1; P.teta=pi/3
P =
ro: 1
teta: 1.0472
>> Q=polar2cart(P)
Q =
x: 0.5000
y: 0.8660
>>

Nella successiva, tuttavia, il campo ro del parametro attuale viene erroneamente chiamato
to, ma lerrore emerge solo al momento della chiamata della funzione con un messaggio
che tra laltro piuttosto fuorviante perch fa pensare che lerrore si trovi nella funzione
polar2cart che accede a un campo non esistente della struct.
>> R.to=1; R.teta=pi/3
R =
to: 1
teta: 1.0472
>> Q=polar2cart(R)
??? Reference to non-existent
field 'ro'.
Error in ==> polar2cart at 2
c.x=p.ro*cos(p.teta);

Come ulteriore esempio consideriamo la seguente funzione lunghezzaSpezzata, il cui


parametro sp, rappresentante una linea spezzata di cui si vuole calcolare la lunghezza, un
array di struct rappresentanti ognuna un punto in un piano cartesiano;
lunghezzaSpezzata fa uso di una funzione ausiliaria, distPunti2d, che ha due
parametri di tipo struct rappresentanti due punti e restituisce la loro distanza. La funzione
distPunti2d viene chiamata ripetutamente per calcolare la lunghezza dei segmenti della
spezzata.
function [d]=distPunti2d(p1,p2)
d=sqrt((p1.x-p2.x)^2+(p1.y-p2.y)^2);

function [d]=lunghezzaSpezzata2d(sp)
d=0;
for k=1:(length(sp)-1)
d=d+distPunti2d(sp(k),sp(k+1));
end;

Potrebbe sembrare un inutile dispendio definire due sottoprogrammi per svolgere un


compito relativamente semplice come il calcolo della lunghezza di una linea spezzata. In
realt, se si considera che lesecuzione dei sottoprogrammi introduce un assai limitato
sovraccarico di lavoro da parte dellinterprete, ladozione di uno stile di programmazione
un cui di introducono numerose, semplici funzioni porta sensibili vantaggi in termini di
costruzione incrementale dei programmi, e facilita la loro comprensione e manutenzione.

80

4.4.

Istruzione return e suo uso nelle funzioni

Allinterno delle funzioni possibile fare uso dellistruzione return che permette di
terminare lesecuzione della funzione e di restituire immediatamente il controllo al
programma chiamante. Si noti che usualmente ci avviene dopo lesecuzione dellultima
istruzione nel corpo della funzione; quando invece viene eseguita unistruzione return,
lesecuzione delle eventuali istruzioni che la seguono non avviene. Ci permette di scrivere
un codice conciso casi in cui tutte le azioni svolte dalla funzione sono state completate.
Prendiamo ad esempio la funzione cercaMultiplo che cerca un multiplo del numero v
( 0) nellarray a, e ne restituisce posizione p e valore m, se c, o una coppia di 0 altrimenti.
function [p,m]=cercaMultiplo(v, a)

Se nellarray ci sono pi multipli la funzione pu restituire i valori relativi a uno qualsiasi


di essi. Ci suggerisce unimplementazione in cui la funzione svolge una ricerca
sequenziale di un multiplo di v a partire dallinizio di a, e interrompe la ricerca appena ne
incontra uno oppure, se non ne trova alcuno, prosegue fino alla fine dellarray per poi
restituire 0 come valore di entrambi i parametri di uscita.
function [p,m]=cercaMultiplo(v, a)
for k=1:length(a)
if mod(a(k),v)==0
p=k; m=a(k);
return; %si restituisce il primo multiplo incontrato
% evita ulteriori inutili calcoli
end;
end;
p=0; m=0; %eseguite solo se non trovato alcun multiplo

Questa codifica permette di evitare inutili elaborazioni una volta incontrato il primo
multiplo del valore v, senza dover introdurre ulteriori istruzioni oltre a quella di return.
Si pu facilmente verificare che listruzione return non essenziale, nel senso che
qualsiasi funzione che ne faccia uso pu essere riscritta evitandone limpiego, anche se a
prezzo di qualche limitata complicazione nel codice, come lintroduzione di variabili
logiche e di istruzioni condizionali. Ne un esempio la seguente versione della funzione
cercaMultiploNR, che non fa uso dellistruzione return e in cui, per evitare di effettuare
ricerche successivamente al primo multiplo incontrato, si deve sostituire il ciclo for con un
ciclo while e introdurre una variabile logica trovato che memorizza la condizione di aver
gi incontrato un multiplo del valore v.
%versione senza istruzione return
function [p,m]=cercaMultiploNR(v, a)
trovato=0; k=1;
while k <= length(a) && ~trovato
if mod(a(k),v)==0
p=k; m=a(k); trovato=1;
end;
k=k+1;
end;
if ~trovato
p=0; m=0;
end;

81

4.5.

Introduzione alla programmazione ricorsiva

La ricorsione una tecnica di programmazione che si basa sulla possibilit che una
funzione chiami s stessa, direttamente o indirettamente (per esempio, la funzione P chiama
Q che chiama P). Un giudizio frettoloso e superficiale potrebbe considerare le funzioni
ricorsive come mal definite e quindi inutili. In realt la ricorsione costituisce una tecnica
avanzata di programmazione a volte assai vantaggiosa, non solo in termini di semplicit ed
eleganza, ma anche di prestazioni.

4.5.1. Induzione e ricorsione


Linduzione una delle pi elementari tecniche di dimostrazione di propriet matematiche.
Consideriamo linduzione sui numeri naturali. Si vuole dimostrare che una propriet vale
per tutti i numeri naturali: per farlo si mostra che essa vale per il numero 0, il primo dei
numeri naturali (base dellinduzione), poi effettua il passo induttivo, cio si argomenta che,
se essa vale per un qualsiasi valore k (ipotesi induttiva), allora vale anche per il valore k+1.
Rimane perci dimostrato che la propriet vale per tutti i numeri naturali: infatti, preso un
qualsiasi valore H posso dimostrare che la propriet vale per H immaginando di partire dal
fatto che essa vale per 0 e di ripetere H volte il passo induttivo.
Un semplice esempio: dimostriamo che la somma dei primi numeri dispari positivi pari a
un numero quadrato, precisamente la seguente propriet
n

i 0

vale per qualsiasi numero naturale n. La base dellinduzione corrisponde al caso di n=0,
0

i 0

Il passo induttivo si basa su fatto che se la propriet vale per n=k, cio se
k

, da questo segue che essa vale anche per k+1. Infatti

i 0
k

.
La ricorsione una tecnica di programmazione strettamente connessa allinduzione perch
la correttezza delle funzioni ricorsive pu essere dimostrata mediante un ragionamento
induttivo.
Consideriamo ora alcuni esempi di problemi con soluzione ricorsiva, che verr mostrata
nelle prossime sezioni, presentandone una formulazione in stile ricorsivo.
La funzione fattoriale
f(n) = n! = n * (n-1) * (n-2) * ... 3 * 2 * 1
pu essere definita ricorsivamente come segue:
Se n=0 allora f(n) = 1
(base della ricorsione)
Se n>0 allora f(n) = n * f(n-1)
(passo ricorsivo)
i 0

82

Si pu osservare che la ricorsione costituisce una versione particolare e un po pi


sofisticata dal punto di vista matematico, del tipico modo di procedere dellinformatica: per
molti problemi la soluzione per un caso generico viene ricavata con poche semplici
operazioni aggiuntive, dalla soluzione di una versione ridotta o semplificata dello stesso
problema.
Un altro esempio di definizione ricorsiva riguarda la ben nota sequenza dei numeri di
Fibonacci F = {f1, ..., fn}
f1 = 1
(caso base)
f2 = 1
(caso base)
Per n > 2, fn = f n1 + fn2
(caso ricorsivo).
Da questa formulazione ricorsiva segue, per esempio, che
f3 = f2 + f1 = 1 + 1 = 2
f4 = f3 + f2 = 2 + 1 = 3
f5 = f4 + f3 = 3 + 2 = 5
ed facile calcolare un qualsiasi numero della sequenza a partire dal suo indice.
Un noto esempio di calcolo formulabile in modo ricorsivo costituito dal noto algoritmo di
Euclide per il calcolo del massimo comune divisore di due numeri m ed n, indicato come
MCD(m, n).
se m = n,
MCD(m, n) = m
(caso base)
se m > n,
MCD(m, n) = MCD(m-n, n)
(passo ricorsivo)
se m < n
MCD(m, n) = MCD(m, n-m)
(passo ricorsivo)
La figura mostra il calcolo di MCM(30, 18): i due numeri di partenza, m=30 ed n=18, sono
raffigurati nella parte alta, e ogni passo ricorsivo produce da una coppia di numeri la coppia
successiva, sul livello inferiore.
30

18

12

12

18

4.5.2. Programmazione delle funzioni ricorsive


La definizione ricorsiva del fattoriale (cio: n! = n (n1)!, con 0! = 1) pu essere tradotta
direttamente in una funzione ricorsiva, cio in una funzione che contiene una chiamata a s
stessa.
function [f]=factRic(n)
if (n==0)
f=1;
else
f=n*factRic(n-1);

end

83

da notare la strettissima corrispondenza (al di l degli aspetti meramente lessicali quali le


parole chiave e segni di interpunzione) tra la definizione della funzione matematica
fattoriale e la funzione MATLAB che la calcola. Tale corrispondenza, che rende la scrittura
del codice una mera rifrasatura della definizione, resa possibile dal fatto che la sintassi del
linguaggio di programmazione, per la parte relativa alle espressioni aritmetiche e alle
chiamate di funzioni, stata attentamente progettata in modo da ricalcare quella della
notazione matematica. Listruzione del ramo else deve la sua forma concisa e intuitiva al
fatto che il parametro attuale di una chiamata di funzione pu essere unespressione
qualsiasi e che la chiamata stessa costituisce, dal punto di vista sintattico, unespressione e
quindi pu essere utilizzata per formare unulteriore espressione composta.
Come accennato nella sezione precedente, il legame tra ricorsione e induzione emerge
evidente per via del fatto che mediante un ragionamento induttivo si pu argomentare che
la funzione factRic calcola correttamente il valore della funzione matematica fattoriale.
La funzione corretta per il valore 0 del parametro n (caso base); inoltre (passo induttivo)
assumendo che sia corretta per n-1, cio calcoli correttamente il valore (n-1)! allora
chiaramente calcola correttamente n!, che vale n*fattRic(n-1).
Per ancor meglio illustrare, a beneficio del lettore, la logica di funzionamento della
funzione ricorsiva factRic riportiamo una sorte di sommaria simulazione del calcolo di
factRic(3)
3 = 0? No.

calcola fattoriale di 2 e moltiplica per 3.


2 = 0? No.

calcola fattoriale di 1 e moltiplica per 2.

1 = 0? No.

calcola fattoriale di 0 e moltiplica per 1.


0 = 0? S.

fattoriale di 1 1
fattoriale di 2 2
fattoriale di 3 3

fattoriale di 0 1.

fattoriale di 0, cio 1

fattoriale di 1, cio 2

fattoriale di 2, cio 3

1 = 1.

1 = 2.

2 = 6.

4.5.3. Gestione a pila degli ambienti locali nelle funzioni ricorsive


Durante lesecuzione della funzione factRic ogni chiamata ricorsiva determina la
sospensione dellesecuzione della chiamata corrente e lattivazione di una nuova chiamata,
con il parametro attuale n decrementato rispetto alla chiamata precedente. Come gi
illustrato nellesempio sulla funzione che calcola i coefficienti binomiali facendo uso di
quella per il fattoriale, accade quindi che pi macchine astratte siano create ed esistano
simultaneamente, essendo tutte sospese, eccetto quella creata pi recentemente.
Completiamo quindi la descrizione dellesecuzione di factRic(3) visualizzando la
sequenza degli ambienti locali delle diverse attivazioni della funzione.

84

factRic n:3

f:..

(1)

f:..

factRic n:1

f:..

factRic n:1

f:..

factRic n:2

f:..

factRic n:2

f:..

factRic n:2

f:..

factRic n:3

f:..

factRic n:3

f:..

factRic n:3

f:..

(2)

(3)

(4)

factRic n:0

f:1

factRic n:1

f:..

factRic n:1

f:1

factRic n:2

f:..

factRic n:2

f:..

factRic n:2

f:2

factRic n:3

f:..

factRic n:3

f:..

factRic n:3

f:..

(5)

factRic n:0

(6)

factRic n:3

(7)

f:6

(8)

Anche in questo caso notiamo che gli ambienti locali sono gestiti in modo LIFO (Last In
First Out): vengono cancellati in ordine inverso a quello un cui sono stati creati, e
memorizzati in una struttura di dati detta PILA.
interessante confrontare lesecuzione della funzione ricorsiva per il calcolo del fattoriale
con quella di una funzione equivalente che pure calcola il fattoriale, ma senza fare uso della
ricorsione.
function [f]=fact(n)
f=1;
for i=1:n
f=f*i;
end

Ci si convince facilmente che a ogni ripetizione del corpo del ciclo for nella funzione non
ricorsiva fact corrisponde una chiamata ricorsiva della funzione factRic: la ricorsione
quindi un modo particolarmente conciso ed elegante di esprimere uniterazione.
Unosservazione simile si pu fare per le due funzioni, ricorsiva e non, per il calcolo del
MCD di due numeri mediante lalgoritmo di Euclide mostrate qui sotto.

85

Versione iterativa
function
[M]=MCDeuclid(m,n)
while m ~= n
if m>n
m=m-n;
else
n=n-m;
end
end
M=m;

Versione ricorsiva
function [M]=MCDeuclidRic(m,n)
if m==n
M=m;
else if m>n
M = MCDeuclidRic(m-n,n);
else
M = MCDeuclidRic(m,n-m);
end
end

4.5.4. La terminazione delle funzioni ricorsive


Luso della ricorsione comporta il rischio di catene infinite di chiamate. Ci accade in
particolare in due casi facilmente riconoscibili. Se una funzione ricorsiva contiene una
chiamata a s stessa in cui i parametri attuali sono uguali a quelli formali allora, se la
chiamata ricorsiva viene eseguita, essa non pu che portare a una nuova, identica chiamata
ricorsiva, e cos via, in una sequenza potenzialmente infinita di chiamate ricorsive che non
generano alcun risultato utile e portano lesecuzione del programma in uno stato di errore.
Questo accadrebbe, per esempio, se la funzione per il calcolo del fattoriale contenesse una
chiamata ricorsiva con parametro attuale n,
function [f]=factRic(n)
.factRic(n); .

e questa chiamata ricorsiva venisse eseguita.


Un altro frequente, grave errore nella programmazione delle funzioni ricorsive si presenta
quando lesecuzione della funzione ricorsiva porta, sicuramente e in ogni caso,
indipendentemente dal valore dei parametri formali, a unulteriore chiamata ricorsiva.
Anche in questo caso quindi si verifica necessariamente una catena potenzialmente infinita
di chiamate ricorsive con conseguente raggiungimento di uno stato erroneo nellesecuzione.
Sempre nel caso della funzione factRic, il caso si presenta nellesempio qui sotto:
function [f]=factRic(n)
f=n*factRic(n-1);

che d origine a una catena illimitata di chiamate con argomento decrescente.


Possiamo quindi enunciare due semplici condizioni necessarie (si noti: non sufficienti) per
evitare catene infinite di chiamate ricorsive:
le chiamate ricorsive abbiano argomenti RIDOTTI; nella pratica succede spesso che
largomento di una chiamata ricorsiva sia un valore che avvicina il parametro al valore
caratteristico del caso di base della ricorsione,
le chiamate ricorsive devono essere condizionate, cio una chiamata deve poter non
generarne unaltra, il che possibile se le chiamate ricorsive sono interne a qualche
istruzione condizionale.

86

Queste due condizioni necessarie corrispondono a semplici criteri di correttezza, facili da


verificare dal programmatore esaminando il codice delle funzioni ricorsive: se il codice non
soddisfa le due condizioni sopra riportate certamente non corretto (ripetiamo che non vale
il viceversa: una funzione ricorsiva potrebbe soddisfare le due condizioni sopra enunciate e
ugualmente essere scorretta).
Si nota facilmente che entrambe queste due condizioni necessarie sono soddisfatte dalla
corretta versione della funzione ricorsiva per il calcolo del fattoriale, riportata qui di seguito
per comodit del lettore.
function [f]=factRic(n)
if (n==0)
f=1;
else f=n*factRic(n-1);
end

4.5.5. Ricorsione multipla


Una funzione ricorsiva pu contenere chiamate ricorsive multiple. Lesempio pi semplice
di ci fornito dalla funzione che calcola i numeri della serie di Fibonacci, riportata qui
sotto e basata sulla definizione ricorsiva della serie stessa fornita in precedenza.
function [f]=fib (n)
if n==1 | n==2
f=1;
else
f=fib(n-2) + fib(n-1);
end

Si vede facilmente che il numero complessivo di chiamate ricorsive cresce molto


velocemente con lindice del numero calcolato. Nella figura mostriamo un grafo (detto ad
albero) che riporta le chiamate effettuate per calcolare il sesto numero di Fibonacci: ogni
chiamata che non corrisponda al caso base della ricorsione collegata da un arco a due
chiamate ricorsive.
fib(6)

fib(4)

fib(5)

fib(3)

fib(2)

fib(1)

fib(4)

fib(3)

fib(2)

fib(1)

fib(2)

fib(3)

fib(2)

fib(1)

87

fib(2)

Il lettore pu verificare che la crescita esorbitante del numero delle chiamate ricorsive pu
rendere difficoltoso il calcolo dei numeri di Fibonacci anche per valori dellindice non
particolarmente elevati, dellordine delle poche decine.
Si noti per, osservando il grafo sopra riportato, che il calcolo di un determinato numero di
viene ripetuto numerose volte. Risulta quindi pi vantaggioso codificare la funzione in
forma non ricorsiva, calcolando una sola volta ogni distinto numero. Per esempio, la
seguente funzione produce, in corrispondenza al parametro n, la lista dei primi n numeri di
Fibonacci.
function [fl]=Fiblist(n)
fl(1)=1;
fl(2)=1;
for k=3:n
fl(k)=fl(k-2)+fl(k-1);
end

4.5.6. Un problema interessante con una semplice soluzione ricorsiva


Lesempio della ricorsione per il calcolo dei numeri di Fibonacci potrebbe far pensare che
la ricorsione permetta di formulare soluzioni eleganti, ma inefficienti, per problemi che
ammettono comunque soluzioni non ricorsive pi efficienti.
Unanalisi approfondita, che qui non riportiamo, mostra che qualsiasi funzione ricorsiva
pu essere trasformata sistematicamente (anche se a prezzo di qualche complicazione che
rende il codice risultante meno intuitivo e trasparente) in unequivalente funzione non
ricorsiva.
Esistono tuttavia molti problemi, anche di rilevante interesse applicativo, che hanno una
soluzione ricorsiva non solo semplice ed elegante, ma anche efficiente.
Ci sono infine dei problemi che per loro natura sono particolarmente complessi (nel senso
che la loro soluzione comporta inevitabilmente calcoli molto onerosi) ma possiedono una
soluzione ricorsiva molto semplice, e facile da comprendere, alla quale non facile trovare
alternative non ricorsive.
A titolo di esempio riportiamo un problema di enigmistica, noto in letteratura col nome di
Torri di Hanoi. Un esempio di tale problema composto da una tavoletta con tre pioli e un
certo numero di dischetti di diametro diverso infilati sullo stesso piolo in ordine di diametro
decrescente, col dischetto pi piccolo posto in cima. Obiettivo del gioco ricomporre la
stessa configurazione di dischetti su un piolo diverso, spostando un disco alla volta da un
piolo allaltro, con la restrizione che un dischetto non pu mai essere appoggiato su di un
altro di diametro inferiore. Mostriamo in figura la soluzione per il caso di tre dischetti da
spostare dal primo al secondo piolo, rappresentata attraverso la sequenza delle successive
configurazioni di dischetti sui diversi pioli, indicate con le lettere alfabetiche progressive
dalla (a) alla (h).

88

La soluzione illustrata pu essere estesa, con un po di accortezza, al caso di quattro dischi,


ma per un numero di dischi elevato il procedimento diventa un vero rompicapo, se non si
usa qualche metodo sistematico.
Cerchiamo di capire la strategia usata nel caso illustrato. Per spostare i tre dischetti dal
piolo 1 al piolo 2 si usato il piolo 3 come supporto intermedio: la pila formata dai due
dischi pi piccoli stata spostata dal piolo 1 al piolo 3. Poi si spostato il disco pi grande
dal piolo 1 al 2, e infine la pila formata dai due pi piccoli stata spostata dal piolo 3 al
piolo 2. A sua volta (ricorsivamente) la pila formata dai due dischi pi piccoli stata
considerata come la composizione del disco di grandezza intermedia e della pila 'banale
formata dal solo dischetto pi piccolo. Per spostare questa pila dal piolo 1 al piolo 3 si
perci usato 2 come piolo intermedio, e per spostarla da 3 a 2 si usato il piolo intermedio
1. Lo spostamento della pila formata dal solo dischetto pi piccolo pu essere compiuto
direttamente e non richiede quindi pioli di supporto.
Generalizzando losservazione, possiamo dire che per spostare una pila di k dischetti da un
piolo a un altro si usa il terzo piolo come supporto intermedio. Quindi si sposta su di esso la
pila di k-1 elementi (usando lo stesso accorgimento se necessario, cio se k-1>1). Poi si
sposta il disco pi grande sul piolo di destinazione, lasciando libero il piolo di partenza.
Questo pu essere eventualmente usato per spostare la pila di k-1 elementi dal piolo
intermedio a quello di destinazione. In tutto questo movimento non succede mai di
appoggiare un disco su di un altro pi piccolo perch, in una certa pila, il disco pi grande
viene spostato direttamente sul piolo di destinazione quando la pila che gli stava sopra gi
stata interamente sistemata sul piolo di supporto intermedio. Il caso della pila di k elementi,
se k=1, banale: essa pu essere direttamente spostata con una sola mossa, portando
lunico dischetto di cui composta dal piolo di partenza a quello di destinazione.
La funzione, riportata in figura insieme a un esempio di chiamata, risolve il generico
problema della Torre di Hanoi: il primo parametro, n, il numero dei dischetti che
compongono la pila iniziale, mentre i tre parametri da, a e per, anchessi numeri interi,
indicano il piolo di partenza, quello di arrivo e quello di supporto. Il risultato
dellelaborazione consiste di una serie di istruzioni per un ipotetico operatore che si
suppone sia in grado di spostare un dischetto da un generico piolo a un altro.

89

function []=hanoi(n, da, a, per)


if (n>1) hanoi(n-1, da, per, a); end;
fprintf('\n sposta un disco dal piolo %d al piolo %d \n', da, a);
if (n>1) hanoi(n-1, per, a, da); end;

>> hanoi(3, 1, 2, 3)
sposta un disco dal
sposta un disco dal
sposta un disco dal
sposta un disco dal
sposta un disco dal
sposta un disco dal
sposta un disco dal
>>

piolo
piolo
piolo
piolo
piolo
piolo
piolo

1
1
2
1
3
3
1

al
al
al
al
al
al
al

piolo
piolo
piolo
piolo
piolo
piolo
piolo

2
3
3
2
1
2
2

Di passaggio notiamo che la funzione hanoi produce come risultato la scrittura, a video,
delle istruzioni per spostare i dischi. Essa non restituisce al programma chiamante alcun
valore: per questo la lista dei suoi parametri formali in uscita vuota.

4.6.

Variabili di tipo funzione e riferimenti a funzioni

Le versioni recenti di MATLAB, oltre ai tipi predefiniti esaminati in precedenza,


definiscono in modo pieno il tipo funzione. Ci permette di introdurre nei programmi
variabili che rappresentano funzioni, e di eseguire due principali operazioni:
assegnare a tali variabili valori di tipo funzione e quindi, per esempio, trasmettere
tali valori di tipo funzione da un programma a un sottoprogramma,
a partire da una variabile con valore funzione, applicare tale valore a opportuni
argomenti;si ottiene quindi un meccanismo estremamente flessibile per manipolare
funzioni e programmare la loro applicazione.
I valori di tipo funzione vengono memorizzati in variabili dette, nel gergo di MATLAB,
handle (cio, in inglese: riferimento, maniglia). A una variabile handle possono essere
assegnati valori di tipo funzione in due modi:
1. indicando lidentificatore di una funzione gi esistente (sia essa definita dallutente o
predefinita), oppure
2. definendo ex novo una funzione distinta da tutte le altre; tale funzione non ha un
identificatore proprio e si accede a essa tramite la variabile handle a essa collegata:
viene quindi detta funzione anonima.
Il primo modo (1) di assegnare un valore a una variabile handle semplicissimo: basta
scrivere lidentificatore della funzione dopo il simbolo @ e assegnare tale espressione alla
variabile handle. Riportiamo qui sotto due esempi di assegnamento di valore funzionale a
una variabile handle e di uso della stessa handle per applicare la funzione a essa collegata.
>> f=@fact
f = @fact
>> f(4)
ans = 24

>> seno=@sin
seno = @sin
>> seno(pi/2)
ans = 1

90

Il secondo modo (2) richiede di utilizzare unespressione di tipo funzione, costruita come
indicato nel seguito. Si scrive il simbolo @ seguito dalla lista dei parametri in ingresso, tra
parentesi tonde e dallespressione che fornisce il risultato come funzione dei parametri in
ingresso. La figura seguente riporta un semplice esempio che include la definizione di una
funzione anonima, il suo assegnamento a una variabile handle, e lapplicazione della
funzione a un argomento passando attraverso la variabile handle.
>> sq=@(x)x^2
sq = @(x)x^2
>> sq(8)
ans = 64

Osserviamo ora che i parametri formali e attuali di una funzione sono a tutti gli effetti delle
variabili, e che il passaggio di parametri dal programma chiamante al chiamato costituisce
di fatto un assegnamento. Ci permette di definire funzioni di ordine superiore, che hanno
parametri di tipo handle e nella loro parte eseguibile contengono istruzioni per invocare,
attraverso tali handle, le funzioni passate loro dal programma chiamante.
Riportiamo, a mo di esempio, una semplice funzione di ordine superiore maxDiFunzione
che, ricevendo un parametro f funzione di una variabile reale, gli estremi a e b di un
intervallo, e il valore d (da usare come passo di incremento) trova (in modo approssimato)
il valore massimo della funzione f nellintervallo [a..b] applicandola in tutti i punti a
iniziare da a, fino a b, con un intervallo di scansione d.
function [M,xM]=maxDiFunzione(f, a, b, d)
xM=a;
M=f(xM);
for x = a+d:d:b
if f(x)>M
xM=x;
M=f(x);
end;
end;
end

La funzione di ordine superiore pu essere applicata per trovare il massimo della funzione
y=x3-3x nellintervallo [-2,2] mediante le seguenti istruzioni date dalla linea di comando
dellinterprete.
>> f=@(x)x^3-3*x;
>> maxDiFunzione(f, -2, 2, 0.01)
ans = 2
>>

91

Capitolo Quinto: Input/Output

Con Input/Output, o in breve I/O, si intendono tutte quelle operazioni che consentono a un
programma di scambiare informazioni con lesterno. Attraverso le operazioni di input il
programma riceve in ingresso le richieste dellutente e tutti i dati su cui svolgere le
elaborazioni. Attraverso le operazioni di output il programma pu comunicare il risultato
delle proprie elaborazioni allutente. Esistono diversi canali di input e output che possono
essere utilizzati. Il terminale, composto dal video e dalla tastiera, consente di effettuare in
maniera immediata sia le operazioni di input che quelle di output. Un altro canale di I/O
molto usato sono i file, dei contenitori gestiti dal sistema operativo che consentono di
memorizzare i dati in maniera persistente, cio il loro contenuto viene conservato sia dopo
il termine del programma, sia dopo lo spegnimento del calcolatore. I file sono molto
efficaci sia come sorgente di dati per le operazioni di input, sia come destinazione dei
risultati in fase di output.
Nella prima parte di questo capitolo, introdurremo le istruzioni che consentono di effettuare
le operazioni di I/O attraverso il terminale. Nella seconda parte ci dedicheremo alle
operazioni di I/O che riguardano i file. Infine, nellultima parte del capitolo vedremo le
istruzioni che MATLAB mette a disposizione per la rappresentazione grafica dei risultati
attraverso il terminale.

5.1.

I/O attraverso il terminale

5.1.1. Acquisizione dati da tastiera


In MATLAB possibile acquisire dei dati dalla tastiera mediante la semplice istruzione
input:
dato = input('messaggio')

Listruzione input visualizza la stringa messaggio e attende linserimento di un valore


attraverso la tastiera. Il valore inserito dallutente viene poi restituito dalla funzione input
e memorizzato nella variabile dato. In particolare, l'utente ha la possibilit di inserire un
valore scalare, una stringa (racchiudendola fra apici) oppure un vettore (racchiudendolo fra
parentesi quadrate). Riportiamo di seguito alcuni esempi di utilizzo della funzione input:
>> a = input('inserire uno scalare: ')
inserire uno scalare: 3
a =
3

92

>> b = input('inserire una stringa: ')


inserire una stringa: 'ciao'
b =
ciao
>> c = input('inserire un vettore: ')
inserire un vettore: [3,2,1]
c =
3

5.1.2. Output su video


Il modo pi immediato per mostrare sul video il risultato di una elaborazione in
MATLAB sfruttare lecho dell'interprete dei comandi: non terminando le istruzioni con il
carattere ; il risultato di ciascuna istruzione viene mostrato a video. In alternativa, esiste in
MATLAB una funzione specifica per stampare dei messaggi a video, la funzione disp che
ha la seguente sintassi:
disp('messaggio')

Quando linterprete incontra questa funzione, stampa la stringa passata come argomento a
video. Il seguente esempio illustra il funzionamento di disp.
disp('questo il mio messaggio');
questo il mio messaggio

Tuttavia, spesso necessario stampare non solo un messaggio di testo ma anche il valore di
una variabile. Dal momento che disp accetta solo argomenti di tipo stringa necessario
convertire i valori numerici in stringhe. A tale scopo si utilizza la funzione num2str che ha
la seguente sintassi:
stringa = num2str(valore)

dove valore il numero da convertire e nella variabile stringa viene memorizzato il


risultato della conversione.
Perci la funzione num2str pu essere facilmente combinata con la funzione disp per
stampare non solo messaggi di testo ma anche il contenuto di variabili, come illustra il
seguente frammento di codice:
risultato=5.2;
msg=['il risultato ' num2str(risultato)];
disp(msg);
il risultato 5.2

5.1.3. La funzione fprintf


In MATLAB esiste una funzione pi potente e flessibile per visualizzare a video messaggi
e dati, la funzione fprintf, che permette di stampare allo stesso tempo testo e dati. La
sintassi della funzione fprintf la seguente:
fprintf(formato,var1,var2,var3,)

93

dove formato una stringa che specifica come i dati devono essere visualizzati e
var1, var2, var3, sono le variabili che contengono i dati da visualizzare. La stringa
formato pu contenere:
caratteri normali, che vengono semplicemente stampati a video;
caratteri speciali, vengono utilizzati per ottenere tabulazioni, andare a capo, ecc;
sono rappresentati da una sequenza di due o pi caratteri che inizia con il carattere
\;
caratteri di conversione o di formato, che specificano il formato in cui dovranno
essere stampati gli argomenti che seguono la stringa formato; sono una sequenza
di due o pi caratteri che inizia con il carattere %; la specifica del formato dei
degli argomenti avviene in maniera posizionale: il primo carattere di conversione
presente nella stringa formato, specifica il formato del primo argomento dalla
funzione fprintf, il secondo specifica il formato del secondo argomento e cos
via.
Alcuni dei pi comuni caratteri di conversione e caratteri speciali sono riportati nella
seguente tabella:

Carattere

Output

\n

Salta alla riga seguente

\t

Inserisce una tabulazione

%%

Stampa il carattere %

\\

Stampa il carattere \

%d

Stampa il valore come un numero intero

%f

Stampa il valore come un numero in virgola


mobile

%e

Stampa il valore con notazione esponenziale

%g

Stampa il valore usando la notazione pi


compatta fra quella esponenziale e quella in
virgola mobile.

%c

Stampa il valore come carattere

Il seguente esempio illustra il funzionamento della funzione fprintf.


risultato=5.2;
fprintf(Il risultato %f,risultato);
Il risultato 5.2

5.2.

I/O su file

Il terminale permette di effettuare operazioni di I/O in maniera molto semplice, tuttavia ha


alcune importanti limitazioni: non particolarmente adatto per gestire grandi quantit di
dati in ingresso e loutput visualizzato attraverso il video non permette di archiviare i
risultati per usi futuri. In queste circostanze, i file sono unalternativa molto efficace.

94

5.2.1. Istruzioni load e save


In MATLAB possibile memorizzare le variabili dello spazio di lavoro su un file tramite il
comando save:
save nomefile

dove nomefile il nome del file in cui verranno memorizzate le variabili dello spazio
di lavoro (se omesso viene utilizzato il file matlab.mat). Lesito del comando save
quello di salvare tutte le variabili dello spazio di lavoro. In alternativa, il comando save
permette anche di salvare solo alcune variabili dello spazio di lavoro specificandone il
nome:
save nomefile <variabili>

dove <variabili> la lista di variabili da memorizzare (separate da uno spazio). Il


comando save consente anche di memorizzare delle variabili in un file gi esistente,
attraverso lopzione append:
save append nomefile <variabili>

la funzione save memorizza le variabili specificate in coda al file esistente. Le variabili


salvate tramite il comando save possono essere caricate successivamente per mezzo del
comando load, che ha la medesima sintassi di save:
load nomefile <variabili>

dove nomefile il nome del file da cui caricare i dati (se omesso viene utilizzato il file
matlab.mat); poi possibile specificare la lista di variabili da caricare (se la lista di
variabili viene omessa, verranno caricate tutte le variabili memorizzate nel file).
I comandi load e save permettono di gestire le operazioni di I/O su file in maniera molto
semplice ed efficace. Queste istruzioni lavorano con file di tipo MAT-files, un formato
proprietario di MATLAB. I MAT-files offrono diversi vantaggi: sono indipendenti dal
sistema operativo (possono cio essere facilmente trasferiti su altri sistemi senza il pericolo
di avere problemi di conversione) e, oltre ai dati, conservano tutte le informazioni sulle
variabili (nome, struttura, ecc.). Daltra parte, i MAT-files hanno anche unimportante
limitazione: possono essere utilizzati solo allinterno di MATLAB. Questo rende
impossibile utilizzarli per scambiare informazioni con altri programmi. Fortunatamente in
MATLAB esistono diversi modi alternativi per leggere e scrivere su file. Anche i comandi
load e save appena visti consentono di leggere e scrivere su semplici file di testo
attraverso lopzione -ascii:
save -ascii nomefile <variabili>

Specificando lopzione -ascii il comando save scrive il contenuto delle variabili in un


file di testo di nome nomefile. Lopzione -ascii pu essere usata solo per salvare su
file delle variabili numeriche. I dati vengono salvati separando con uno spazio i dati sulla
stessa riga e andando a capo per linizio di ogni nuova riga o prima di salvare il contenuto
della variabile successiva.
load -ascii nomefile

Il comando load -ascii viene usato per caricare il contenuto di un file di testo; tutto il
contenuto del file viene memorizzato in una variabile con lo stesso nome del file (privato
dellestensione). importante sottolineare che per il corretto funzionamento della
load -ascii tutte le righe del file devono contenere solo valori numerici separati da

95

spazio e ciascuna riga deve avere lo stesso numero di elementi. Solo in questo caso infatti
possibile rappresentare tutto il file come ununica matrice.
Nei seguenti paragrafi vederemo due ulteriori funzioni disponibili in MATLAB per
lacquisizione di dati da file: la funzione textread e la funzione xlsread. La prima
consente di leggere file di testo in cui i dati sono memorizzati per colonna. La seconda
funzione consente invece di leggere i file salvati con Microsoft Excel.

5.2.2. Funzione textread


La funzione textread consente di leggere file di testo che contengono colonne di dati. La
sintassi della funzione la seguente:
[var1, var2, , varM]= textread (nomefile, formato, N)

Dove nomefile il nome del file da caricare, formato definisce il tipo di dato di
ciascuna colonna, N un argomento opzionale per specificare il numero di righe che
devono essere lette (se omesso il file viene letto fino alla fine). Per definire il tipo di dato di
ogni colonna, viene utilizzata una stringa di fomato dello stesso tipo di quella utilizzata
nella funzione fprintf (Paragrafo 5.1.3.). per definire il formato delloutput. Il contenuto
della prima colonna viene memorizzato nella variabile var1, quello della seconda colonna
nella variabile var2 e cos via.
Esempio: si supponga di voler leggere le coordinate (x,y) e il colore di una serie di punti
contenute nel seguente file punti.txt.
(12,4) Rosso
(3,20) Verde
(1,10) Blu

La funzione textread permette di leggere tali informazioni in maniera molto semplice,


come mostrato nellesempio seguente.
[x,y,colore] = textread(punti.txt,(%d,%d) %s);

Inoltre, possibile utilizzare la stringa di formato per indicare che il contenuto di una o pi
colonne non deve essere memorizzato in alcuna variabile. Per ottenere questo risultato,
occorre inserire un * nel carattere di conversione appena dopo il %: in questo modo
linterprete legge il dato contenuto in quella colonna ma lo ignora passando alla colonna
successiva. Ad esempio, la seguente istruzione permette di leggere il contenuto del file
punti.txt (descritto nelesempio precedente) ignorando la coordinata y dei punti:
[x,colore] = textread(punti.txt,(%d,%*d) %s);

5.2.3. Funzione xlsread


La funzione xlsread consente di caricare in MATLAB i dati contenuti in un foglio di
calcolo creato con il programma Microsoft Excel.
La sintassi della funzione la seguente:
nomevariabile = xlsread('nomefile')

Dove nomefile il nome del file da caricare e nomevariabile il nome della


variabile in cui il contenuto del foglio di calcolo dovr essere memorizzato.

96

Esempio: si supponga che il file esempio.xls contenga le seguenti due colonne di


dati.
1
2
3

6
7
8

Il seguente esempio mostra come caricare in MATLAB il contenuto del foglio di calcolo.
A = xlsread('esempio.xls')
A =
1
6
2
7
3
8

Infine la funzione xlsread permette anche di specificare il nome del foglio di calcolo da
cui importare i dati (nel caso in cui il file excel contenga pi fogli di calcolo). Il nome del
foglio di calcolo deve essere specificato come secondo parametro della funzione xlsread
dopo il nome del file:
nomevariabile = xlsread('nomefile','nomefoglio')

dove nomefoglio il nome del foglio di calcolo da cui importare i dati.

5.3.

Gestione avanzata dei file

Le istruzioni illustrate finora consentono di memorizzare e caricare dati da file, ma non


danno al programmatore il completo controllo sulla gestione dei file (ad esempio le
operazioni di lettura e scrittura possono essere effettuate solo in sequenza). Esistono invece
altre istruzioni in MATLAB che permettono di avere pieno controllo delle operazioni
effettuate sui file. Prima di illustrare queste funzioni, opportuno introdurre alcuni concetti
di base sui file. Un file un flusso di dati disposti in sequenza (come su un nastro). In
particolare possiamo distinguere fra due tipologie di file: i file binari che sono costituiti da
una sequenza di byte, i file di testo che sono costituiti da una sequenza di caratteri. Prima di
poter leggere i dati contenuti in un file o scriverne di nuovi necessario aprire il file, cio
informare il sistema operativo che intendiamo lavorare con questo file. Durante
loperazione di apertura, occorre anche specificare il tipo del file da aprire (testo o binario)
e le operazioni che si desidera effettuare sul file (lettura, scrittura o entrambe). Una volta
aperto un file, il sistema operativo ne tiene traccia in una particolare tabella, in cui a ogni
file aperto viene associato un identificativo univoco e dove vengono anche memorizzate
tutte le informazioni utili per la gestione del file. In particolare, per ogni file viene anche
memorizzata la posizione corrente, cio la posizione allinterno del file dove stata
effettuata lultima operazione di lettura o scrittura. A meno di non modificare
esplicitamente tale posizione (ad esempio tramite la funzione fseek che vedremo in
seguito), le operazioni di lettura e scrittura avvengono sempre in maniera sequenziale a
partire dalla posizione corrente.Una volta che tutte le operazioni necessarie sul file sono
state effettuate, questo pu essere chiuso, affinch il sistema operativo lo tolga dalla tabella
dei file aperti.
In questa sezione vedremo prima di tutto le istruzioni che permettono di aprire e chiudere
un file. In seguito, vedremo le istruzioni per la lettura e la scrittura di informazioni su un
file, sia in forma binaria che testuale. Infine, mostreremo brevemente alcune istruzioni che
facilitano la manipolazione dei file.

97

5.3.1. Apertura e chiusura di un file


Per aprire un file occorre utilizzare la funzione fopen:
[fid, messagio] = fopen (nomefile,modo)

dove nomefile il nome del file da aprire e modo specifica la modalit in cui il file dovr
essere aperto.
Se loperazione di apertura ha successo, fid conterr un intero positivo che rappresenta
lidentificatore del file e messaggio sar vuota. Nel caso si verifichi qualche errore in fase
di apertura, fid conterr il valore -1 e la stringa messaggio conterr la descrizione
dellerrore che si verificato.
Lapertura di un file pu essere effettuata in diversi modi, specificando che tipo di
operazioni si intende effettuare sul file (lettura e/o scrittura) e come devono essere gestiti i
dati contenuti nel file in precedenza (se devono essere preservati o sovrascritti). La
seguente tabella riporta i principali modi in cui un file pu essere aperto, riportando per
ciascuno il significato e la stringa corrispondente.

Modo

Significato

Apre un file esistente e consente di effettuare


soltanto operazioni di lettura

r+

Apre un file esistente e consente di effettuare


sia operazioni di lettura che di scrittura

Crea un nuovo file (nel caso il file esista ne


cancella interamente il contenuto) e consente
di effettuare soltanto operazioni di scrittura

w+

Crea un novo file (nel caso il file esista ne


cancella interamente il contenuto) e consente
di effettuare sia operazioni di scrittura che di
lettura

Apre un file e consente di effettuare soltanto


operazioni di scrittura. Nel caso il file esista
gi, il precendente contenuto del file non
viene cancellato e la scrittura avviene in coda
al file.

a+

Apre un file e consente di effettuare sia


operazioni di scrittura che di lettura. Nel caso
il file esista gi, il precendente contenuto del
file non viene cancellato e la scrittura avviene
in coda al file.

I file vengono abitualmente aperti in modalit binaria, ma in alcuni casi pu essere utile
aprirli in modalit testo. A tale scopo sufficiente aggiungere una t dopo la r, w o
a nella specifica della modalit di apertura del file. Lapertura del file in modalit testo
non utilizzata nei sistemi unix, dove non c distinzione fra file binari e testo.

98

Inoltre possibile utilizzare la funzione fopen per avere informazioni sui file aperti:
fids = fopen(all)

restituisce un vettore fids con gli identificatori di tutti i file aperti.


anche possibile avere informazioni su un singolo file aperto:
[nomefile, modo] = fopen(fid)

Dove nomefile il nome del file corrispondente allidentificatore fid e modo il modo
in cui stato aperto.
Una volta concluse le operazioni di lettura e scrittura su un file, questo deve essere chiuso,
mediante la funzione fclose:
esito = fclose(fid)

dove fid lidentificatore del file che si desidera chiudere, mentre il valore di ritorno,
esito, sar pari a 0 in caso di successo o a -1 in caso di errori.
Attraverso la seguente chiamata:
esito = fclose(all)

possibile chiudere tutti i file aperti.

5.3.2. Lettura e scrittura di dati in modalit binaria


La scrittura di dati su file in modalit binaria, avviene tramite la funzione fwrite:
cont = fwrite (fid, dati)

dove fid lidentificatore del file su cui si desidera scrivere, dati un vettore contenente
le informazioni che si desidera scrivere sul file. Il valore restituito dalla funzione, cont,
rappresenta invece il numero di elementi scritti (viene solitamente usato per controllare la
corretta esecuzione delle operazioni di scrittura). La scrittura degli elementi contenuti in
dati viene efettuata dalla funzione fwrite colonna per colonna: vengono prima scritti
tutti gli elementi della prima colonna, poi gli elementi della seconda e cos via.
La lettura dei dati avviene tramite la funzione fread:
[dati, count] = fread(fid,dim)

dove fid il descrittore del file da cui si desidera leggere, dim viene utilizzato per
specificare la dimensione dei dati che si desidera leggere, dati conterr i valori letti dal
file e count conterr il numero di elementi letti. Largomento dim pu essere specificato in
tre diversi modi: n (legge esattamente n valori dal file e li memorizza come un vettore
colonna in dati), Inf (continua a leggere i valori fino alla fine del file e li memorizza
come un vettore colonna in dati), [n m] (legge n m valori e li memorizza in dati
come una matrice n m).

5.3.3. Lettura e scrittura formattata su file


La funzione fprintf, vista in precedenza pu essere utilizzata anche per salvare dati in
maniera formattata su file, tramite la sintassi:
cont = fprintf(fid, formato,var1,var2,var3,)

dove fid lidentificatore del file su cui si desidera scrivere, formato la stringa che
definisce il formato delloutput (come visto nel precedente paragrafo 5.1.3) e var1, var2,
var3, , sono le variabili contenenti i dati che si vogliono scrivere su file. La funzione
restituisce il numero di elementi scritti sul file.

99

La lettura di dati formattati da file pu essere effettuata tramite la funzione fscanf,


utilizzando la seguente sintassi:
[dati, cont] = fscanf(fid,formato,dim)

dove fid il descrittore del file da cui si desidera leggere, formato una stringa che
specifica il formato dei dati (come visto per la funzione fprintf), dim serve a specificare
la quantit di dati da leggere. I valori letti vengono memorizzati in dati, mentre attraverso
cont viene restituito il numero di elementi letti. Largomento dim viene utilizzato
esattamente come nella funzione fread vista in precendeza.

5.3.4. Altre funzioni


Oltre alle istruzioni di apertura, chiusura, lettura e scrittura, MATLAB dispone di diverse
istruzioni per gestire e manipolare i file. Di seguito vedremo alcune delle pi usate.

5.3.4.1. Funzione exist


La funzione exist, permette di verificare lesistenza di un file, attraverso la seguente
sintassi:
result = exist(nomefile,file)

dove nomefile il nome del file di cui si vuole verificare lesistenza. Se il file non esiste,
la funzione exist restituisce il valore 0.

5.3.4.2. Funzione feof


La funzione feof verifica se la posizione corrente nel file ha raggiunto la fine del file. La
sintassi della funzione la seguente:
result = feof(fid)

dove fid il descrittore del file di cui si desidera verificare la posizione. Il valore
restituito in result pari a 1 se la posizione corrente la fine del file, 0 altrimenti.

5.3.4.3. Funzione fseek


La funzione fseek permette di modificare la posizione corrente allinterno di un file. La
sintassi della funzione fseek la seguente:
esito = fseek (fid, offset, origine)

dove fid il descrittore del file, offset lo spostamento (misurato in byte) desiderato
della posizione nel file. Largomento origine serve a definire la posizione del file rispetto
alla quale si desidera eseguire lo spostamento. In particolare, largomento origine pu
assumere tre diversi valori:
bof

La posizione specificata dalloffset sar calcolata rispetto allinizio del


file

cof

La posizione specificata dalloffset sar calcolata rispetto alla posizione


corrente nel file

eof

La posizione specificata dalloffset sar calcolata rispetto alla fine del file

Il valore restituito sar 0 se loperazione ha successo, -1 in caso di errore.

100

5.4.

Diagrammi

Abbiamo gi introdotto i diagrammi. In questa sezione forniamo alcune informazioni


aggiuntive sui diagrammi bidimensionali e introduciamo i diagramma a tre dimensioni.

5.4.1. Diagrammi a due dimensioni


5.4.1.1. Colori e stili per linee e marcatori
Riprendiamo uno degli esempi presentati in modo da mostrare come rendere il grafico pi
leggibile. Consideriamo il programma che costruisce il grafico di x2 e x3. Come si nota
dalla Figura Figura 5. Visualizzazione nello stesso grafico di x3 e x2. del Capitolo 1, risulta
difficile distinguere x2 da x3. opportuno associare a ciascuna curva un colore, un tratto, o
un marcatore diverso e inserire una legenda che chiarisca la corrispondenza tra ciascuna
curva e la funzione rappresentata.
Colore
r (rosso)
b (blu)
g (verde)
k (nero)

Stile del marcatore


O
X
*
+

Stile della linea


- (linea solida)
: (linea punteggiata)
-- (linea tratteggiata)
<niente> (nessuna linea)

Tabella 10. Alcuni possibili colori e stili per linee e marcatori.


La Tabella 10 mostra alcuni dei possibili stili e colori che possono essere associati a una
curva insieme ai simboli corrispondenti (per la lista completa si faccia riferimento a un
manuale di MATLAB). Tali simboli possono essere utilizzati nella funzione plot in modo
da ottenere il risultato desiderato. In particolare, oltre ai due vettori contenenti le proiezioni
dei punti su ascisse e ordinate, la funzione plot prende come parametro anche una stringa
che contiene i simboli corrispondenti, nellordine a: colore della linea, stile del marcatore,
stile della linea.
Facendo riferimento al nostro esempio, possiamo modificare luso di plot come segue:
x = -10:1:10;
y=x.^3;
z=x.^2;
plot(x,y, 'g*-');
hold on
plot(x,z, 'bo-');
hold off
xlabel('x');
ylabel('x^2, x^3');
title('cubica & quadratica');
grid on;
legend('x^3', 'x^2');

In questo caso ci aspettiamo che la curva corrispondente a x 3 sia visualizzata sul diagramma
in verde, con un marcatore a stella e il tratto continuo, e quella corrispondente a x 2 in blu,
con un marcatore circolare e il tratto sempre continuo. La penultima istruzione dello script
(grid on) serve per abilitare la visualizzazione della griglia sul diagramma mentre
lultima istruzione (legend) ci consente di visualizzare la legenda che indica la
corrispondenza tra le curve e le rispettive funzioni. Il grafico ottenuto eseguendo questo
script viene mostrato in Figura 7. Si noti che lordine con cui le etichette vengono inserite

101

nella funzione legend corrisponde allordine con cui abbiamo chiamato la funzione plot.
Inoltre, il grafico deve essere stato creato prima dellesecuzione della funzione legend.

Figura 7. Andamento delle funzioni x2 e x3.


5.4.1.2. Scala logaritmica
La funzione plot che abbiamo usato finora visualizza i grafici su scala lineare. Esiste
anche la possibilit di visualizzare i grafici su scala logaritmica. In particolare:
la funzione semilogx consente di visualizzare i dati sulle ascisse in scala
logaritmica e quelli sulle ordinate in scala lineare; al contrario,
la funzione semilogy consente di visualizzare i dati sulle ordinate in scala
logaritmica e quelli sulle ascisse in scala lineare; infine,
la funzione loglog consente di visualizzare sia i dati sulle ascisse che quelli sulle
ordinate in scala logaritmica.
Queste funzioni sono utilizzabili con le stesse regole della plot, di conseguenza, il lettore
pu sperimentarle riprendendo gli esempi che sono stati gi proposti riguardo alla plot e
sostituendo a questultima una qualsiasi delle altre tre funzioni.

5.4.1.3. Diagrammi in coordinate polari


La funzione polar consente di creare diagrammi utilizzando le coordinate polari. In
particolare, la funzione polar(t, r) visualizza il grafico dei punti i cui angoli espressi in
radianti sono memorizzati nellarray t e le cui distanze dallorigine degli assi sono
memorizzate nellarray r. Per esempio, il seguente script:

102

t = 0:180;
r = ones(size(t)).*5;
polar(t,r);

ci permette di visualizzare il diagramma in Figura 8.

Figura 8. Esempio di diagramma ottenuto con la funzione polar.


5.4.1.4. Esportazione di un grafico come immagine
In molti casi utile salvare un grafico come immagine per poterlo importare in altri
programmi (per esempio in un editor di documenti) o per stamparlo. Il comando print
consente di effettuare questa operazione. La sintassi da utilizzare la seguente:
print <opzione>

nomefile

<opzione> permette di specificare il formato di salvataggio dellimmagine. nomefile

consente al programmatore di indicare il nome del file in cui salvare limmagine. Ove
necessario, il nome del file pu essere corredato dal percorso corrispondente nellalbero
delle directory su file system.
I formati possibili sono quelli tipici per le immagini. Per esempio, le opzioni
-djpeg e -dpng consentono di salvare limmagine rispettivamente nei formati jpeg e png.
Si rimanda a un manuale di MATLAB per lelencazione di tutti i formati possibili.
Il comando print deve seguire lesecuzione di un comando plot (o di qualsiasi altro
comando che consenta la visualizzazione di un grafico) e memorizza su file limmagine del
grafico generato con tale comando.

103

40

quote

30

20

10

0
40
20

40
20

-20
ordinate

-20
-40

-40

ascisse

Figura 9. Esempio di uso di plot3.


5.4.2. Diagrammi a tre dimensioni
5.4.2.1. Diagrammi lineari a tre dimensioni
Un diagramma lineare a tre dimensioni pu essere considerato una generalizzazione di un
diagramma a due dimensioni. Esiste una funzione apposita chiamata plot3 che consente di
creare tali diagrammi. Per esempio, il seguente script:
t = 0:0.1:10*pi;
plot3 (t.*sin(t), t.*cos(t), t);
xlabel('ascisse');
ylabel('ordinate');
zlabel('quote');
print dpng usoPlot3.png

consente la visualizzazione del diagramma in Figura 9. Si noti che, a differenza del plot,
in questo caso plot3 riceve tre vettori che contengono le proiezioni dei punti del grafico
sui tre assi cartesiani. Si noti infine luso di print per la memorizzazione del diagramma
in formato png nel file chiamato usoPlot3.png.
Esistono altre modalit di uso di plot3 per le quali rimandiamo a un manuale di
MATLAB.

5.4.2.2. Diagrammi tridimensionali a superficie


I diagrammi tridimensionali a superficie servono per visualizzare funzioni di due variabili:
z = f(x, y) come superfici nello spazio tridimensionale. Per visualizzare queste superfici a
partire dallinsieme delle triple (x, y, z) si pu utilizzare, per esempio, la funzione mesh.

104

Per capire il meccanismo di funzionamento, facciamo riferimento al seguente semplice


esempio: vogliamo visualizzare la funzione z = x + y, dove 1 x 3 e 0 y 1. Se
generiamo tutte le coppie possibili di valori di x e di y e calcoliamo per ogni coppia il
valore corrispondente di z, avremo identificato i seguenti punti che faranno parte del nostro
grafico: (1, 0, 1), (1, 1, 2), (2, 0, 2), (2, 1, 3), (3, 0, 3), (3, 1, 4) 11. In particolare, noi
vogliamo visualizzare la superficie che passa per questi punti. A questo scopo, la funzione
plot3 non sufficiente perch ci consente di visualizzare semplicemente una linea che
passa per i punti indicati, come mostrato in Figura 10.
Potremmo risolvere il problema organizzando opportunamente i dati per fare in modo che
la linea che congiunge i punti indicati racchiuda una superficie, ma dovremmo farlo in
modo manuale (il lettore invitato a individuare lopportuna organizzazione dei dati che
consente di ottenere il risultato richiesto).

Figura 10. Uso di plot3 per visualizzare z = x+y.


Possiamo procedere invece utilizzando la funzione mesh che, coadiuvata dalla funzione
meshgrid limita al minimo il lavoro manuale del programmatore.
Supponendo che x sia il vettore contenente tutti i valori delle ascisse e y quello contenente
tutti i valori delle ordinate, dobbiamo ottenere due matrici che chiamiamo X e Y, di
dimensione size(y) x size(x), che sono cos costituite: X replica su ciascuna riga i
valori di x mentre Y replica su ciascuna colonna i valori di y. Tali matrici possono essere
ottenute utilizzando la funzione meshgrid che le calcola automaticamente a partire dai
vettori x e y:
x = 1:3;
y = 0:1;
[X, Y] = meshgrid(x, y);

Dopo lesecuzione di queste istruzioni si ha che:

11

Per identificare i valori elencati, per semplicit, abbiamo fatto lipotesi di considerare per
x e y solo i valori interi compresi tra gli estremi indicati.

105

X =

Y =
1

A questo punto siamo pronti a 1) creare la matrice Z che ha le stesse dimensioni delle
matrici X e Y e i cui valori sono ottenuti, nel nostro esempio specifico, sommando i valori di
X e di Y, e 2) applicare la funzione mesh alla tripla X, Y, Z:
Z = X + Y;
mesh(X, Y, Z);

La superficie ottenuta con questo procedimento mostrata in Figura 11.


La scelta di usare due matrici distinte (qui chiamate X e Y) per memorizzare separatamente
le ascisse e le coordinate dei punti del grafo pu apparire a prima vista innaturale e
ridondante: si potrebbe per esempio, in alternativa, usare una sola matrice per
memorizzare, in ogni suo elemento, la coppia (x, y), delle coordinate di un punto. Tuttavia,
come si vede bene dallesempio sopra riportato e in quelli che seguono, luso delle due
matrici separate, X per le ascisse e Y per le ordinate, permette di produrre la terza matrice
Z, che contiene le quote z dei punti, senza alcuno sforzo di programmazione,
semplicemente usando unespressione Matlab del tutto simile allespressione algebrica che
definisce la funzione che si intende visualizzare. Infatti, nellesempio, per la funzione z = x
+ y, basta calcolare lespressione matriciale Z = X + Y.
Gli stessi passi individuati per il primo esempio si effettuano per qualsiasi z = f(x, y).
Vediamo qui di seguito altri due esempi un po pi complessi del precedente.

Figura 11. Uso di mesh per visualizzare z = x+y.

106

5.4.3. Esempi Riassuntivi


Esempio: Vogliamo disegnare il paraboloide ottenuto mediante la funzione z = x2+y2. I
passi da seguire sono sempre gli stessi:
definizione dei vettori x e y;
calcolo di X e Y mediante meshgrid;
calcolo di Z;
uso di mesh per la creazione del grafico.
Lo script risultante dallapplicazione di questi passi il seguente:
% assumiamo che x e y abbiano lo stesso intervallo di

% variabilit
x=[-4:0.05:4];
y=x;
[X,Y]=meshgrid(x,y);
Z=X .^ 2 + Y .^ 2;
mesh(X,Y,Z);
% assegnamo unetichetta ai tre assi del diagramma
xlabel('ascisse-x');
ylabel('ordinate-y');
zlabel('quote-z');

Il grafico che viene visualizzato mostrato in Figura 12.

Figura 12. Esempio 1 - paraboloide.

107

Esempio: Si vuole disegnare la superficie ottenuta applicando la seguente funzione:


sin

z
x

Lo sviluppo dello script procede secondo i passi gi sintetizzati nellesempio precedente:


tx=[-8:0.3:8];
ty=tx;
[TX, TY] = meshgrid (tx, ty);
R = sqrt (TX .^ 2 + TY .^ 2);
TZ = sin (R) ./ R;
mesh (TX, TY, TZ);

Il diagramma risultante viene detto a sombrero ed mostrato in Figura 13.

Figura 13. Esempio 2 - diagramma a "sombrero".

108

Capitolo Sesto: Esercizi

A conclusione del testo questultimo capitolo offre una serie di esercizi risolti utili per
verificare le conoscenze acquisite. Le soluzioni proposte sono un esempio di possibile
soluzione al problema, certo non lunica possibile.

6.1.

Equazioni di secondo grado

Si scriva un programma che chiede l'inserimento dei tre coefficienti di una equazione di
secondo grado ax2+bx+c=0 e stampa il valore delle (eventuali) radici reali dellequazione.
Soluzione
Bisogna calcolare il discriminante dell'equazione con la formula: b2-4ac
Se positivo abbiamo due radici distinte, se nullo le radici sono reali e coincidenti, se
negativo le radici non sono reali.
a=input('Inserire a: ');
b=input('Inserire b: ');
c=input('Inserire c: ');
delta=b^2-4*a*c;
if delta < 0
disp('L''equazione non ha soluzioni reali');
elseif delta==0
disp(['x=' num2str(-b/(2*a))]);
else
disp(['x1=' num2str((-b-sqrt(delta))/(2*a)) ' x2=' ...
num2str((-b+sqrt(delta))/(2*a))]);
end

Esecuzione
Inserire a:
Inserire b:
Inserire c:
L'equazione

1
1
1
non ha soluzioni reali

Inserire a: 1
Inserire b: 2
Inserire c: 1
x=-1
Inserire a: 1
Inserire b: 1
Inserire c: -1
x1=-1.618 x2=0.61803

109

6.2.

Sistemi di equazioni lineari

Si scriva uno script che chiede l'inserimento dei coefficienti e dei termini noti di un sistema
di equazioni di primo grado in N equazioni e N incognite e ne calcola la soluzione.
a 11 x 1

a 12 x 2

...

a1n x n

b1

a 21 x 1

a 22 x 2

...

a2n xn

bn

a nn x n

bn

...
a n1 x1

an2 x2

...

Soluzione
Il sistema pu essere rappresentato in forma di matrice:
a 11

a 12

...

a1n

x1

b1

a 21

a 22

...

a2n

x2

b2

...

...

...

...

...

a n1

an2

...

a nn

xn

bn

-1

Sappiamo che S=A b. In MATLAB equivale alla divisione sinistra: S=A\b


N=input('Inserire il numero di equazioni e di incognite: ');
for x=1:N % righe (equazioni)
for y=1:N % colonne (incognite)
A(x,y)=input(['Coefficiente ' num2str(y) ' equazione '
num2str(x) ': ']);
end
b(x)=input(['Termine noto equazione ' num2str(x) ': ']);
end
A
b
S=A\b'

Esecuzione
Inserire numero di equazioni e di incognite: 2
Coefficiente 1 equazione 1: 1
Coefficiente 2 equazione 1: 2
Termine noto equazione 1: 4
Coefficiente 1 equazione 2: -6
Coefficiente 2 equazione 2: 5
Termine noto equazione 2: -1
A =
1
-6

2
5

-1

b =
S =
1.2941
1.3529

110

6.3.

Sequenze palindrome

Si scriva uno script che chiede l'inserimento di una sequenza di N numeri e alla fine dice se
la sequenza palindroma o no.
Si ricorda che una sequenza palindroma se risulta uguale letta da sinistra verso destra e da
destra verso sinistra.
Soluzione
Controllo se il primo elemento uguale all'ultimo, se il secondo elemento uguale al
penultimo e cos via fino a quando raggiungo la met della sequenza.
Si assume che la stringa sia palindroma fino a quando non si trova il primo carattere diverso
dal suo simmetrico.
N=input('Inserire N: ');
for x=1:N
a(x) = input('Inserire numero: ');
end
palindroma = true; % finch non trovo controesempi palindroma
for x=1:N/2
if a(x) ~= a(N-x+1)
palindroma = false;
end
end
if palindroma
disp('La sequenza risulta palindroma');
else
disp('La sequenza non risulta palindroma');
end

Codice alternativo (pi efficiente) per il ciclo for


palindroma = all(a==a(end:1));

Esecuzione
Inserire N: 5
Inserire numero: 8
Inserire numero: 3
Inserire numero: 5
Inserire numero: 3
Inserire numero: 8
La sequenza risulta palindroma

Esecuzione
Inserire N: 5
Inserire numero: 8
Inserire numero: 3
Inserire numero: 5
Inserire numero: 3
Inserire numero: 9
La sequenza non risulta palindroma

111

6.4.

Confronti

Si scriva uno script che chiede di inserire una sequenza di N numeri seguita da un altro
numero M e dice se tutti i numeri della sequenza sono minori, uguali o maggiori di M.
Soluzione
Presentiamo due soluzioni. La seconda evita l'utilizzo del for ed pi efficiente e leggibile.
N=input('inserire N: ');
for x=1:N
a(x) = input('inserire numero: ');
end
M=input('inserire M: ');
minori=true;
maggiori=true;
uguali=true;
for x=1:N
if a(x)>M
minori=false;
uguali=false;
elseif a(x)<M
maggiori=false;
uguali=false;
else
maggiori=false;
minori=false;
end
end
if minori
disp('I numeri della sequenza sono minori del numero dato');
else
disp('I numeri della sequenza non sono minori del numero dato');
end
if maggiori
disp('I numeri della sequenza sono maggiori del numero dato');
else
disp('I numeri della sequenza non sono maggiori del numero
dato');
end
if uguali
disp('I numeri della sequenza sono uguali al numero dato');
else
disp('I numeri della sequenza non sono uguali al numero dato');
end

Codice alternativo (pi efficiente) per il ciclo for


minori = all(a<M);
maggiori = all(a>M);
uguali = all(a==M);

112

Esecuzione
inserire
inserire
inserire
inserire
inserire
inserire
inserire
I numeri
I numeri
I numeri

6.5.

N: 5
numero: 1
numero: 2
numero: 3
numero: 4
numero: 5
M: 6
della sequenza sono minori del numero dato
della sequenza non sono maggiori del numero dato
della sequenza non sono uguali al numero dato

Rotazione matrice

Si scriva un programma che data una matrice a NxN crea una nuova matrice b ruotata di 90
gradi in senso antiorario rispetto ad a.
Si consideri N=4 e la matrice a inizializzata con i valori [1 2 3 4; 2 3 4 5; 6 7 8 9; 0 0 0 0].
Soluzione
N=4;
a=[1 2 3 4; 2 3 4 5; 6 7 8 9; 0 0 0 0];
b=zeros(N); % inizializzo a zero tutti gli elementi di b
for x=1:N
for y=1:N
b(x,y)=a(y,N-x+1);
end
end

% stampo la matrice originale e quella ruotata


a
b

In alternativa possiamo usare una funzione MATLAB predefinita:


N=4;
a=[1 2 3 4; 2 3 4 5; 6 7 8 9; 0 0 0 0];
b=rot90(a)

% stampo la matrice originale e quella ruotata


a
b

Esecuzione
a =
1
2
6
0

2
3
7
0

3
4
8
0

4
5
9
0

4
3
2
1

5
4
3
2

9
8
7
6

0
0
0
0

b =

113

6.6.

Matrici

Scrivere in Matlab una funzione che, ricevendo in ingresso una matrice m di numeri,
restituisce in uscita una matrice mr, ottenuta da m nel seguente modo: si calcola la media
aritmetica dei valori di m; per i valori che in m sono minori della media, in mr si pone nella
stessa posizione il valore -1, per quelli superiori alla media si pone il valore 1, e per gli altri
(quelli uguali alla media) si pone lo stesso valore.
Soluzione
Prima versione che fa uso dei vettori logici e della funzione mean per il calcolo della media
function [mr]=selMediaMatVL(m)
media = mean(mean(m));
mr=m;
mr(m>media)=1;
mr(m<media)=-1;

Seconda versione, scritta con cicli espliciti.


function [mr]=selMediaMat(m)
[R, C] = size(m);
s=0;
for r = 1:R
for c = 1:C
s=s+m(r,c);
end;
end;
media = s/(R*C)
for r = 1:R
for c = 1:C
if m(r,c)>media
mr(r,c)=1;
else if m(r,c)<media
mr(r,c)=-1;
else mr(r,c)=media;
end;
end;
end;
end;

6.7.

Tariffe telefoniche

Una nota compagnia di telefonia offre due tariffe ai propri clienti.


La tariffa T1 ha un costo di 0.17 euro al minuto tariffati al secondo, la tariffa T2 ha un
costo di 0.12 euro al minuto tariffato a scatti di 30 secondi, pi un ulteriore scatto alla
risposta di 0.16 euro.
Si chieda l'inserimento di un numero di secondi e si tracci il grafico di entrambe le tariffe
da 0 secondi fino al numero di secondi inserito.
Soluzione
N=input('Inserire il numero di secondi: ');
tempo=0:N;
T1=0.17*tempo/60;
T2=0.16+0.06*ceil(tempo/30); % 0.06 il valore dello scatto (0.12/2)
plot(tempo,T1,tempo,T2);

114

Esecuzione
Inserire il numero di secondi: 1000

6.8.

Vettori logici e ordinamenti

Scrivere uno script che dopo aver chiesto l'inserimento di una sequenza di N numeri,
stampa i valori dei numeri in posizione pari ordinati in modo crescente, i valori dei numeri
in posizione dispari ordinati in modo decrescente, i valori dei numeri pari ordinati in modo
crescente, i valori dei numeri dispari ordinati in modo decrescente.
Soluzione
N=input('inserire N: ');
clear a;
for x=1:N
a(x) = input('inserire numero: ');
end
sort(a(2:2:N),'ascend')
sort(a(1:2:N),'descend')
sort(a(mod(a,2)==0),'ascend')
sort(a(mod(a,2)==1),'descend')

Esecuzione
inserire
inserire
inserire
inserire
inserire
inserire
ans =
1
ans =
9
ans =
4
ans =
9

N: 5
numero:
numero:
numero:
numero:
numero:

3
1
8
4
9

4
8

8
3

115

6.9.

Matrici logiche misteriose

Date le seguenti matrici a e b si dica cosa stampano le seguenti istruzioni.


a =
1
4
7

2
5
8

3
6
9

b =
9
8
7
6
5
4
3
2
1
a(3,1)
a(8)
a(a==b)
b(a>b|b>a)
a(b)
c=a;c(a>b)=b(a?b).^2
find(mod(a,b))
[r c]=find(mod(a,b))
[a(1,:)' b(:,1) (min(a([2 3],:))+max(b(:,2:3)'))']

Soluzione
>> a(3,1)
ans =
7

L'istruzione accede al valore memorizzato nella riga 3 e colonna 1 della matrice a.


>> a(8)
ans =
6

L'istruzione accede al valore memorizzato nell'ottavo elemento della matrice.


Gli elementi sono contati per colonna. La prima colonna ha i primi 3 elementi, la seconda
ne ha altri 3... In questo caso l'ottavo elemento coincide con l'elemento della seconda riga e
della terza colonna.
>> a(a==b)
ans =
5

Utilizzo il vettore logico generato dalla relazione a==b per selezionare gli elementi di a. In
questo caso seleziono l'elemento di riga 2 e colonna 2 (unico elemento di a uguale al
corrispondente elemento di b).
La selezione crea un vettore con gli elementi selezionati, il numero 5 in questo caso.
>> b(a>b|b>a)
ans =
9
6
3
8
2
7
4
1

116

Sono selezionati tutti gli elementi di b per cui vero che "a>b|b>a". Questo avviene per
tutti i numeri che sono diversi, quindi tutti tranne l'elemento di riga 2 e colonna 2. Tutti gli
elementi selezionati dalla relazione sono copiati in un vettore.
>> a(b)
ans =
9
8
7

6
5
4

3
2
1

In questo caso genero una nuova matrice in cui ogni elemento (i,j) contiene il valore della
matrice a degli elementi con indice il valore memorizzato in b(i,j).
Ad esempio l'elemento (1,1) di b contiene 9, per cui copio in posizione (1,1) della nuova
matrice il valore in posizione 9 in a (che pari a 9).
>> c=a;c(a>b)=b(a>b).^2
c =
1
2
3
4
5
16
9
4
1

Tutti i valori di a vengono copiati in c, quindi si assegnano a tutti i valori di c selezionati


dalla matrice logica a>b i quadrati dei corrispondenti valori di b. Ricordiamo che la matrice
logica a>b ha valore 1 (vero) per gli elementi di a che sono maggiori di b e valore 0 (falso)
negli altri casi. Solo gli elementi (2,3) (3,1) (3,2) (3,3) saranno cambiati.
>> find(mod(a,b))
ans =
1
2
3
4
7
8

La funzione find restituisce gli indici dei valori non nulli passati come parametro alla
funzione. In questo caso il parametro mod(a,b) che equivale alla matrice dei resti delle
divisioni tra gli elementi di a e di b. Il risultato l'indice degli elementi di a che non sono
multipli di b (resto nullo).
>> [r c]=find(mod(a,b))
r =
1
2
3
1
1
2
c =
1
1
1
2
3
3

117

Questo comando ha un effetto simile al precedente, ma anzich restituire l'indice lineare


(che varia da 1 a 9 e procede colonna per colonna) restituisce le due coordinate
corrispondenti ai valori non nulli. La prima il numero della riga, la seconda il numero
della colonna.
>> [a(1,:)' b(:,1) (min(a([2 3],:))+max(b(:,2:3)'))']
ans =
1
9
12
2
6
10
3
3
8

Se si specifica ':' come riga o come colonna si intende l'intera riga o l'intera colonna. La
precedente istruzione crea una nuova matrice composta da tre colonne. La prima colonna
equivale alla prima riga di a trasposta. La seconda colonna equivale alla prima colonna
della matrice b. Infine la terza colonna uguale alla somma degli elementi pi bassi scelti
tra le ultime due righe della matrice a e degli elementi pi alti scelti tra le ultime due
colonne della matrice b. Per ci che riguarda la terza colonna si faccia attenzione agli
operatori di trasposizione: le funzioni min e max normalmente agiscono sulle colonne, per
cui bisogna trasporre il vettore b. La seguente sequenza di istruzioni pu aiutare a capire
ci che avviene nella generazione della terza colonna passo per passo:
>> a([2 3],:)
ans =
4
5
6
7
8
9
>> min(a([2 3],:))
ans =
4
5
6
>> b(:,2:3)'
ans =
8
5
2
7
4
1
>> max(b(:,2:3)')
ans =
8
5
2
>> min(a([2 3],:))+max(b(:,2:3)')
ans =
12
10
8
>> (min(a([2 3],:))+max(b(:,2:3)'))'
ans =
12
10
8

6.10. I caff del dipartimento - matrici logiche


In un dipartimento ci sono 10 persone, ognuna nell'ultima settimana ha consumato un certo
numero di caff (memorizzati in una matrice "caffe" data).
Si vuole sapere quanto deve pagare ogni persona sapendo che ogni caff costa 0,25 euro e
che il fisso di noleggio della macchinetta per fare il caff costa 10 euro a settimana. La
met di tale costo divisa equamente tra coloro che hanno consumato almeno un caff e
l'altra met tra coloro che ne hanno consumato di pi rispetto alla media.

118

Soluzione
Creiamo un vettore logico (bevitori) per selezionare chi ha consumato almeno un caff. Un
altro vettore (superbevitori) per chi ha consumato pi caff rispetto alla media.
caffe=[0
1
4
1
2
3
0
3
0
2

0
0
6
1
1
0
0
0
0
3

0
2
3
1
2
3
0
0
0
3

0
1
3
1
2
2
0
0
0
4

0
0
2
1
2
2
0
0
0
2

0
1
2
1
1
3
0
0
0
3

0;
1;
1;
1;
2;
1;
0;
0;
1;
3]

...
...
...
...
...
...
...
...
...

somme_caffe = sum(caffe,2);
costi_a=somme_caffe*0.25
bevitori=somme_caffe~=0;
costi_b=costi_a;
costi_b(bevitori)=costi_b(bevitori)+5/sum(bevitori);
superbevitori=somme_caffe>mean(somme_caffe);
costi_b(superbevitori)=costi_b(superbevitori)+5/sum(superbevitori)

Esecuzione
costi_a =
0
1.5000
5.2500
1.7500
3.0000
3.5000
0
0.7500
0.2500
5.0000
costi_b =
0
2.1250
7.1250
2.3750
4.8750
5.3750
0
1.3750
0.8750
6.8750

119

6.11. Pagella dei film preferiti - dati strutturati


Si vuole compilare la pagella dei propri film preferiti.
1. Scrivere uno script che chieda di inserire i film. Ogni film caratterizzato da un
anno, un titolo e un voto.
2. Scrivere il codice che visualizzi il numero totale di film con voto superiore a 6.
3. Scrivere il codice che visualizzi i titoli e i voti dei film prodotti tra il 2000 e il
2005.
4. Salvare la pagella in un file .mat, cancellarla, ricaricarla e stampare il titolo del
primo film.
Soluzione
% parte 1
nome=input('Inserire nome film (''q'' per uscire): ');
ii=0;
clear pagella;
while nome~='q'
ii=ii+1;
pagella(ii).nome = nome;
pagella(ii).anno = input('Inserire anno: ');
pagella(ii).voto = input('Inserire voto: ');
nome=input('Inserire nome film (''q'' per uscire): ');
end

% parte 2
somma = 0;
for x=1:ii
if pagella(x).voto > 6
somma = somma + 1;
end
end
disp(['Film con voto >6: ' num2str(somma)]);

% parte 3
for x=1:ii
if pagella(x).anno >= 2000 && pagella(x).anno <= 2005
disp([pagella(x).nome ' ' num2str(pagella(ii).voto)]);
end
end

% parte 4
save pagella.mat pagella
clear pagella
load pagella.mat pagella
disp(pagella(1).nome)

Esecuzione
(parte 1)
Inserire
Inserire
Inserire
Inserire
Inserire
Inserire
Inserire

nome film ('q' per uscire): 'Bel film'


anno: 2002
voto: 10
nome film ('q' per uscire): 'Bellissimo film'
anno: 2005
voto: 10
nome film ('q' per uscire): 'Film poco interessante'

120

Inserire
Inserire
Inserire
Inserire
Inserire
Inserire

anno: 1999
voto: 5
nome film ('q' per uscire): 'Filmaccio'
anno: 2004
voto: 1
nome film ('q' per uscire): 'q'

(parte 2)
Film con voto >6: 2

(parte 3)
Bel film 1
Bellissimo film 1
Filmaccio 1

(parte 4)
Bel film

Possiamo migliorare la soluzione sostituendo i cicli utilizzando vettori logici. Per svolgere
correttamente l'esercizio bisogna ricordare che per accedere a un particolare campo di tutti
gli elementi di un array di struct si utilizzano le parentesi quadre.
% Estraggo la somma dei film con voto superiore a 6
somma=sum([pagella.voto]>6);
disp(['Film con voto >6: ' num2str(somma)]);

% Estraggo i titoli dei film prodotti tra il 2000 e il 2005


pagella([pagella.anno]>=2000&[pagella.anno]<=2005).titolo

6.12. Crivello di Eratostene


Scrivere uno script che trovi tutti i numeri primi compresi tra 2 e N utilizzando il metodo
del Crivello di Eratostene. Secondo questo metodo bisogna scrivere tutti i numeri da 2 a N.
Dopodich partendo da 2 fino ad arrivare a N si rimuovono tutti i multipli del numero
considerato, a eccezione del numero stesso. Alla fine resteranno soltanto numeri primi.
Soluzione
Utilizzo un vettore di N elementi booleani. Ogni elemento vale true se presente nella
sequenza, vale false se stato cancellato dalla sequenza. Prima di utilizzare il metodo del
crivello tutti i numeri sono inizializzati a true a eccezione di 1 che non un numero primo
per convenzione.
N=input('inserire N: ');
clear a;
a(2:N)=true; % assumo inizialmente che tutti i numeri siano primi
a(1)=false; % 1 non un numero primo

% marco come non primi i numeri multipli del numero iniziale


for x=2:N
a(2*x:x:N) = false; % il 2*x esclude il numero iniziale
end

% stampo risultato
find(a==true)

Esecuzione
inserire N: 30
ans =
2

11

13

121

17

19

23

29

6.13.

Elemento pi ripetuto

Scrivere una funzione che, data una matrice, restituisce l'elemento che compare pi spesso
al suo interno.
Soluzione
Per ogni elemento della matrice conto quante volte ripetuto, e in ogni momento considero
come pi ripetuto quello che appare come il pi ripetuto fino a quel momento.
function [elem]=elemento_piu_ripetuto(m)
elem = m(1,1);
count = 0;
[r c] = size(m);
for ii=1:r
for jj=1:c
tmp_count = sum(sum(m==m(ii,jj)));
if tmp_count>count
elem = m(ii,jj);
count = tmp_count;
end
end
end

Esecuzione
>> elemento_piu_ripetuto([1 2 3; 3 4 5; 6 7 3])
ans =
3

6.14.

Costruzione matrici

Scrivere una funzione che, date due matrici quadrate A e B aventi le stesse dimensioni,
restituisce due matrici C e D. C contiene le righe di A o di B scelte in questo modo: sommo
gli elementi della prima riga di A e della prima riga di B, copio in C la riga di A se questa
ha la somma maggiore, altrimenti copio la riga di B. Allo stesso modo si procede per le
righe successive. Per la generazione della matrice D invece valuto le colonne di A e di B e
copio in D le colonne la cui somma maggiore.
Soluzione
function [c d]=costruzione_matrici(a,b)
N=size(a);
c=zeros(N);
d=zeros(N);
for ii=1:N
if sum(a(ii,:))<sum(b(ii,:))
c(ii,:)=a(ii,:);
else
c(ii,:)=b(ii,:);
end
if sum(a(:,ii))>sum(b(:,ii))
d(:,ii)=a(:,ii);
else
d(:,ii)=b(:,ii);
end
end

122

Esecuzione
x =
0
2
8

1
3
2

0
0
0

1
0
1

3
1
1

0
2
1

y =

>> [v w] = costruzione_matrici(x,y)
v =
0
1
0
0
1
2
1
1
1
w =
0
1
0
2
3
2
8
2
1

6.15.

Agenzia viaggi - accesso ai file

Un'agenzia viaggi possiede un archivio composto da due file: il primo contiene in ogni riga
il nome di una destinazione e il suo prezzo; il secondo contiene in ogni riga il nome di un
cliente e di una destinazione. Scrivere uno script che (1) carica i dati, (2) stampa il fatturato
generato da ogni destinazione, (3) aumenta i prezzi del 10% e salva i dati aggiornati.
Soluzione
% parte 1
[dest_nome dest_costo]=textread('dest.dat','%s %f')
[acquisti_nome acquisti_dest]=textread('acquisti.dat','%s %s')

% parte 2
for ii=1:length(dest_nome)
fatturato=0;
for jj=1:length(acquisti_dest)
if strcmp(acquisti_dest(jj),dest_nome(ii))

% strcmp restituisce 1 se sono uguali, 0 se sono diversi


fatturato = fatturato + dest_costo(ii);
end
end
disp(['Fatturato per ' dest_nome(ii) ': ' num2str(fatturato)]);
end

% parte 3
dest_costo=dest_costo*1.1;
[fid msg] = fopen('dest.dat','w');
if fid>0
for ii=1:length(dest_nome)
fprintf(fid,'%s %f\n',char(dest_nome(ii)),dest_costo(ii));
end
fclose(fid);
else
disp(msg) % errore
end

123

6.16.

Funzione misteriosa

Data la seguente funzione:


function [a b] = mistero(s,k)
h(k)='a':'z';
a=h(s);
b=h(a);

Sapendo che s una stringa che pu contenere un numero imprecisato di caratteri alfabetici
e che k un'altra stringa che contiene tutte le lettere dell'alfabeto in un ordine non
precisato, si dica cosa stampa il comando: [x y] = mistero('prova','z':-1:'a') e cosa fa in
generale la funzione mistero?
Soluzione
In questo caso alla funzione si passa come parametro s la stringa "prova" e come
parametro k la stringa "zyxwvutsrqponmlkjihgfedcba" che corrisponde
all'alfabeto al contrario.
L'istruzione h(k)='a':'z'; corrisponde a eseguire le seguenti istruzioni individuali:
h('z')='a';
h('y')='b';
h('x')='c';
....
h('a')='z';

Cio ogni carattere in k associato a una lettera dell'alfabeto procedendo da 'a' a 'z'.
Si noti che, come in C, anche in MatLab si possono utilizzare i caratteri (che corrispondo a
dei numeri della tabella ASCII) come indici degli array.
L'istruzione a=h(s) copia in a tutti i caratteri di s dopo averli sostituiti con i
corrispondenti caratteri associati in h. Cio come eseguire individualmente:
a(1)=h(s(1))
a(2)=h(s(2))
...
a(N)=h(s(N))

L'istruzione b=h(a) effettua di nuovo la sostituzione, ma utilizzando i caratteri contenuti


in 'a'.
In pratica tutte le lettere contenute in s sono sostituite con le lettere corrispondenti
all'alfabeto al contrario memorizzato in k ottenendo un banale esempio di crittazione
(simile a quella dell' "aneddoto cifrato" di un famoso settimanale di enigmistica). Perci la
lettera a viene sostituita con z, la b con y, la c con x e cos via. La soluzione quindi:
>> [x y] = mistero('prova','z':-1:'a')
x =
kilez
y =
prova

Come si nota la chiave k utilizzata permette di riottenere la stringa s originale applicando 2


volte le sostituzioni, ma non sempre vero! Ad esempio:
>> [x y] = mistero('prova','uvktzcjsfwlyarxiepmgnqodbh')
x = rnwbm
y = nujys

124

6.17. Matrice trasposta


Scrivere una funzione che generi la matrice trasposta a partire da una matrice data.
Si ricorda che data una matrice A NxM, la sua trasposta T una matrice MxN in cui gli
elementi T(x,y) sono uguali ad A(y,x).
Soluzione
function [t]=trasposta(a)
[r c] = size(a);
for ii=1:r
for jj=1:c
t(jj,ii)=a(ii,jj);
end
end

Esecuzione
>> trasposta([1 2 3; 4 5 6])
ans =
1
4
2
5
3
6

6.18. Matrici
Scrivere una funzione che riceve come parametro due matrici A e B, della stessa
dimensione, e restituisce i seguenti 3 valori: il numero di elementi uguali in posizioni
corrispondenti, il numero di elementi di A massimali per la matrice B (cio il numero di
posizioni, nella matrice A, in cui presente un elemento che maggiore o uguale a tutti gli
elementi presenti nella matrice B), il numero massimo di elementi di A massimali per la
matrice B (secondo la definizione precedente) presenti in una stessa colonna di A.
Per esempio, se A e B sono definite come segue:
A = [4 11 3; 3 8 5; 0 10 2; 6 3 9];
B = [1 2 3; 3 4 5; 1 1 3; 6 3 7];

Il numero di elementi uguali in posizioni corrispondenti 5: lelemento di posizione (1, 3);


gli elementi di posizione (2, 1) e (2, 3); gli elementi di posizione (4, 1) e (4, 2). Il numero di
elementi di A massimali per B pari a 4, infatti gli elementi 11, 8, 10 e 9 sono gli elementi
di A maggiori di tutti gli elementi in B. Il numero massimo di elementi di A massimali per
B che si trovano sulla stessa colonna di A pari a 3, infatti nella seconda colonna di A si
trovano i tre valori 11, 8 e 10, mentre nella terza colonna si trova solo il valore 9.
Soluzione
Osserviamo che un elemento della matrice A maggiore o uguale a tutti gli elementi della
matrice B se e solo se maggiore o uguale al massimo fra di essi. Quindi per verificare che
un elemento di A sia massimale per B sufficiente confrontarlo con lelemento massimo di
B, calcolato preventivamente e una tantum.
function [r1,r2,r3]=soluzioneEs1a(A, B)
t1 = A==B;
M = max(max(B));
t2 = A >= M;
r1 = sum(sum(t1));
r2 = sum(sum(t2));
r3 = max(sum(t2));

125

6.19. Ricerca di sequenze in matrici


Scrivere una funzione che riceve una matrice di interi e un array di interi che rappresenta
una sequenza e cerca tale sequenza allinterno della matrice. La sequenza pu essere
disposta, nella matrice, verticalmente dallalto verso il basso o orizzontalmente da sinistra
verso destra. La funzione deve avere l intestazione:
function[riga, col, dir]=cercaInizioSequenza(matrice, seq)

Se la sequenza presente nella matrice allora riga e col indicano gli indici di riga e di
colonna del suo primo elemento, mentre dir uguale al carattere v se la sequenza
disposta verticalmente, o se orizzontalmente (se la sequenza presente ripetuta in pi
posizioni, i valori restituiti possono essere quelli relativi a una qualsiasi delle ripetizioni); se
la sequenza non presente, riga e col valgono entrambi 0 e dir vale n.
Per codificare la funzione in questione, si sviluppino prima le seguenti funzioni ausiliarie
function[pres]=verificaSeqOrizDaPosizione(matrice, seq, riga, col)
function[pres]=verificaSeqVertDaPosizione(matrice, seq, riga, col)

che ricercano la sequenza a partire da una posizione, in direzione orizzontale o verticale:


riga e col sono il punto di inizio; pres vale 1 se la sequenza presente, 0 altrimenti.
Successivamente si utilizzino queste due funzioni per codificare le due seguenti
function[riga,col]=cercaInizioSeqOriz(matrice, seq)
function[riga,col]=cercaInizioSeqVert(matrice, seq)

che ricercano la sequenza nella matrice con disposizione orizzontale e verticale, restituendo
in riga e col le coordinate del punto dinizio, se la sequenza trovata, 0 altrimenti.
Infine si implementi la funzione cercaInizioSequenza facendo uso delle due precedenti.
Soluzione
function[pres]=verificaSeqOrizDaPosizione(matrice,seq,riga,col)
len=length(seq);
pr=matrice(riga,col:col+len-1);
pres=all(pr==seq);
function[pres]=verificaSeqVertDaPosizione (matrice, seq, riga, col)
len=length(seq);
pr=matrice(riga:riga+len-1,col);
pres=all(pr==seq');
function[riga, col]=cercaInizioSeqOriz(matrice, seq)
len = length(seq);
[R,C] = size(matrice);
for r = 1 : R
for c = 1: C-len+1
pres = verificaSeqOrizDaPosizione(matrice, seq, r, c);
if pres
riga=r;
col=c;
return;
end;
end;
end;
riga=0;
col=0;

126

function[riga, col]=cercaInizioSeqVert(matrice, seq)


len = length(seq);
[R,C] = size(matrice);
for c = 1 : C
for r = 1: R-len+1
pres = verificaSeqVertDaPosizione(matrice, seq, r, c);
if pres
riga=r;
col=c;
return;
end;
end;
end;
riga=0;
col=0;
function[riga, col, dir]=cercaInizioSequenza(matrice, seq)
[ro, co] = cercaInizioSeqOriz(matrice, seq);
if ro ~= 0
riga = ro;
col = co;
dir = 'o';
return;
end;
[rv, cv] = cercaInizioSeqVert(matrice, seq);
if rv ~= 0
riga = rv;
col = cv;
dir = 'v';
return;
end;
riga=0;
col=0;
dir='n';

6.20. Immagini in matrici


Si rappresenta unimmagine mediante una matrice rettangolare di numeri, corrispondenti al
colore dei suoi pixel (punti luminosi che compongono la figura). Si progetti una funzione
che, ricevendo come parametri due matrici f1 ed f2 rappresentanti due immagini e due
valori numerici C ed S, con C<S, rappresentanti due diversi colori, produce come risultato
una terza figura f3, ottenuta da f1 ed f2 secondo la seguante regola.
Nelle posizioni (r,c) in cui f1(r,c)<C ed f2(r,c)>C si ha f3(r,c)=f2(r,c)-f1(r,c) nelle posizioni
(r,c) in cui f1(r,c)>S ed f2(r,c)<S si ha f3(r,c)=f1(r,c)-f2(r,c) nelle posizioni rimanenti si ha
f3(r,c)=f1(r,c).
Codificare la funzione combinaImmagini, preferibilmente in forma compatta evitando di
utilizzare istruzioni for.
Soluzione
function [f3]=combinaImmagini(f1, f2, C, S)
f3=f1;
f3(f1<C & f2>C)=f2(f1<C & f2>C)-f1(f1<C & f2>C);
f3(f1>S & f2<S)=f1(f1>S & f2<S)-f2(f1>S & f2<S);

127

6.21. Scomposizione in fattori


Scrivere una funzione che scompone in fattori primi un numero. Il risultato dovr essere un
array costruito nel seguente modo: il primo parametro conterr le basi dei fattori, il secondo
parametro conterr gli esponenti dei fattori, cio quante volte essi sono ripetuti.
Esempio: il numero 100 uguale a 22x52, per cui il vettore delle basi sar [2 5] mentre
quello degli esponenti corrispondenti sar [2 2].
Soluzione
Dichiaro un array fattori avente un numero di elementi pari al valore del numero inserito
con ogni elemento inizializzato a zero. Quando si rilever che il numero n un fattore
primo del numero inserito, l'elemento di indice n dell'array viene incrementato di uno.
A questo punto provo a dividere il numero dato per tutti i divisori a partire dal numero 2.
Se il numero inserito viene diviso in modo esatto (cio con resto zero), sostituisco il suo
valore con il risultato della divisione e incremento nell'array fattori l'elemento di indice
corrispondente al divisore considerato. Se il numero non diviso in modo esatto significa
che il divisore considerato non un fattore primo del numero, per cui passo a considerare il
divisore successivo. L'algoritmo termina quando il numero sar uguale a 1 (cio non
esistono pi altri divisori maggiori di 1 in grado di dividerlo in modo esatto).
Infine per calcolare il risultato bisogna estrapolare dall'array fattori le basi e gli esponenti:
le basi sono gli indici degli elementi dell'array fattori diversi da zero, mentre gli esponenti
sono i valori dell'array fattori corrispondenti a tali indici.
function [basi esponenti]=scomponi(numero)
divisore=2;
fattori(1:numero)=0;
while numero>1
resto = mod(numero,divisore);
if resto==0
fattori(divisore)=fattori(divisore)+1;
numero=numero/divisore;
else
divisore=divisore+1;
end
end
basi=find(fattori);
esponenti=fattori(basi);

Esecuzione
>> [base esp]=scomponi(128)
base =
2
esp =
7
>> [base esp]=scomponi(133)
base =
7
19
esp =
1
1

128

6.22. Serie di Fibonacci


Scrivere una funzione che calcoli l'n-esimo numero della Serie di Fibonacci F sapendo che
definita in questo modo:
F(1)=0, F(2)=1, F(N)=F(N-1)+F(N-2)
Scriverla in versione iterativa;
Scriverla in versione ricorsiva.
Soluzione
Nella versione iterativa usiamo la definizione per impostare i valori di F(1) e di F(2),
dopodich calcoliamo tutti i valori da F(3) a F(N) usando iterativamente la formula
F(N)=F(N-1)+F(N-2).
Nella versione ricorsiva la nostra funzione MatLab corrisponde direttamente alla F(N).
In questo modo la funzione richiama semplicemente se stessa usando direttamente la
formula F(N)=F(N-1)+F(N-2). Per fare in modo che la ricorsione termini consideriamo
separatamente i casi in cui la funzione viene chiamata con N pari a 1, e N pari a 2: in questa
situazione sar restituito il valore F(1)=0 e F(2)=1 senza che la funzioni richiami se stessa
(condizione di terminazione della ricorsione).
Versione iterativa
function [x]=fibonacci_iterativa(N)
F(1)=0;
F(2)=1;
for ii=3:N
F(ii)=F(ii-1)+F(ii-2);
end
x=F(N);

Versione ricorsiva
function [x]=fibonacci_ricorsiva(N)
if N==1
x=0;
elseif N==2
x=1;
else
x=fibonacci_ricorsiva(N-1)+fibonacci_ricorsiva(N-2);
end

Esecuzione
>> fibonacci_iterativa(4)
ans =
2
>> fibonacci_ricorsiva(5)
ans =
3
>> fibonacci_ricorsiva(6)
ans =
5

129

6.23. Massimo Comun Divisore


Scrivere una funzione che calcoli il il Massimo Comune Divisore tra due numeri (1) in
modo iterativo, (2) in modo ricorsivo, (3) tra un insieme di numeri.
Si utilizzi l'algoritmo di Euclide ottimizzato: per a>b si ha che:
MCD(a,b)=b se mod(a,b)==0
MCD(a,b)=MCD(b,mod(a,b)) se mod(a,b)~=0
Soluzione parte 1
Versione iterativa
function [MCD]=mcd_iterativa(a,b)
if a<b
c=a;
a=b;
b=c;
end
r = mod(a,b);
while r~=0

% Nuovo MCD(a,b)=MCD(b,mod(a,b))
a=b;
b=r;
r=mod(a,b);
end
MCD=b;

Soluzione parte 2
Per realizzare la versione ricorsiva consideriamo che l'algoritmo gi ricorsivo nella
formulazione matematica. Se mod(a,b) diverso da zero, il valore restituito sar il risultato
della chiamata alla funzione stessa con parametri b e mod(a,b). Se invece mod(a,b)
uguale a zero restituisco b.
function [MCD]=mcd_ricorsiva(a,b)
% Se il primo numero maggiore del secondo li scambio poich MCD(a,b)=MCD(b,a)
if a<b
c=a;
a=b;
b=c;
end
r = mod(a,b);
if r~=0
[MCD]=mcd_ricorsiva(b,r);
else
MCD = b;
end
Soluzione parte 3
Bisogna calcolare il MCD tra una serie indefinita di numeri. Consideriamo che
MCD(a1,a2,a3,...,aN) uguale a MCD(MCD(a1,a2),a3,...,aN), cio che il MCD tra tutti i
numeri uguale al MCD del MCD tra i primi due e i restanti numeri.
Esempio: la funzione deve calcolare il massimo comun divisore tra i numeri a1, a2, a3 e a4.
risultato=MCD(a1,a2,a3,a4). Calcoliamo prima il MCD tra i primi due numeri usando una

130

delle funzioni trovate nel punto 1 o 2 di questo esercizio. Quindi definiamo


a12=MCD(a1,a2). Il nostro risultato sar uguale a MCD(a12,a3,a4). Riapplichiamo ancora
una volta il ragionamento definendo a123=MCD(a12,a3). Il risultato diventer uguale a
MCD(a123,a4). A questo punto abbiamo un MCD tra due numeri che calcolabile sempre
con una delle funzioni dei punti precedenti.
Riassumendo: se i numeri sono pi di due richiamiamo ricorsivamente la funzione
passando come primo numero il MCD tra i primi due, e come numeri successivi quelli dal
terzo in poi; se i numeri sono esattamente due calcoliamo il risultato usando la funzione del
punto precedente; se il numero uno solo il MCD sar uguale a tale numero (per
definizione).
function [MCD]=mcd_serie(numeri)
if length(numeri)==1
MCD=numeri;
elseif length(numeri)==2
MCD=mcd_iterativa(numeri(1),numeri(2));
else
tempMCD=mcd_iterativa(numeri(1),numeri(2));
MCD=mcd_serie([tempMCD numeri(3:length(numeri))]);
end

Esecuzione
>> mcd_serie([51 357 34])
ans =
17
>> mcd_serie([12 30 72])
ans =
6

6.24. Funzione ricorsiva misteriosa


Si dica cosa calcola la seguente funzione ricorsiva:
function [z]=mistero(x,y)
if x<y
z=0;
else
if mod(x,y)==0
z=x+ mistero(x-y,y);
else
z= mistero(x-1,y);
end
end

Soluzione
Per capire cosa calcola la funzione la eseguiamo tracciando gli ambienti locali di
esecuzione di ogni chiamata. Proviamo ad esempio a eseguirla con i parametri 7 e 2.
IMMAGINE DELLO STACK ALL'ISTANTE 1
mistero(7,2): x=7, y=2, z=?
IMMAGINE DELLO STACK ALL'ISTANTE 2
mistero(7,2): x=7, y=2, z=?
mistero(6,2): x=6, y=2, z=?

131

IMMAGINE DELLO STACK ALL'ISTANTE 3


mistero(7,2): x=7, y=2, z=?
mistero(6,2): x=6, y=2, z=?
mistero(4,2): x=4, y=2, z=?
IMMAGINE DELLO STACK ALL'ISTANTE 4
mistero(7,2): x=7, y=2, z=?
mistero(6,2): x=6, y=2, z=?
mistero(4,2): x=4, y=2, z=?
mistero(2,2): x=2, y=2, z=?
IMMAGINE DELLO STACK ALL'ISTANTE 5
mistero(7,2): x=7, y=2, z=?
mistero(6,2): x=6, y=2, z=?
mistero(4,2): x=4, y=2, z=?
mistero(2,2): x=2, y=2, z=?
mistero(0,2): x=0, y=2, z=0 (riduzione al caso particolare)
IMMAGINE DELLO STACK ALL'ISTANTE 6
mistero(7,2): x=7, y=2, z=?
mistero(6,2): x=6, y=2, z=?
mistero(4,2): x=4, y=2, z=?
mistero(2,2): x=2, y=2, z=2 (riduzione al caso particolare)
IMMAGINE DELLO STACK ALL'ISTANTE 7
mistero(7,2): x=7, y=2, z=?
mistero(6,2): x=6, y=2, z=?
mistero(4,2): x=4, y=2, z=6 (riduzione al caso particolare)
IMMAGINE DELLO STACK ALL'ISTANTE 8
mistero(7,2): x=7, y=2, z=?
mistero(6,2): x=6, y=2, z=12 (riduzione al caso particolare)
IMMAGINE DELLO STACK ALL'ISTANTE 9
mistero(7,2): x=7, y=2, z=12 (riduzione al caso particolare)

Quando x<y la funzione restituisce un numero che utilizzato dalla chiamata precedente
per completare la propria esecuzione. Si noti che y non cambia. Se x<y si restituisce zero.
Se x>=y si controlla se x multiplo di y. Se lo viene restituito x sommato con il risultato
di una chiamata alla funzione con primo parametro x-y. Se x non multiplo di y si
restituisce il risultato di una chiamata alla funzione con primo parametro x-1.
Quindi la funzione calcola la somma di tutti i multipli di y compresi tra 0 e x.
Esecuzione
>> mistero(7,2)
ans =
12
>> mistero(7,4)
ans =
4
>> mistero(7,5)
ans =
5

132

6.25. Funzione ricorsiva misteriosa (2)


Si consideri il seguente programma:
function [ris] = s(n)
if n<1
ris = -1;
elseif n>=1 & n<=4 (*)
ris = n;
(*)
else
ris = s(n-2)*s(n-4);
end
% script che richiama s
for x = 1:8
fprintf("%d, ", s(x));
end

Quali risultati vengono stampati a video? Non necessario calcolare i valori numerici
esatti, ma sufficiente riportare le espressioni artimetiche necessarie per calcolarli.
Si supponga di rimuovere le righe di codice evidenziate da un asterisco: la terminazione
della ricorsione ancora garantita per ogni valore dellargomento n? In caso affermativo
giustificare brevemente la risposta, in caso negativo riportare almeno un esempio di
argomento in cui la ricorsione non termina. Con la modifica apportata quali risultati
vengono stampati a video? Non necessario calcolare i valori numerici esatti, ma
sufficiente riportare le espressioni artimetiche necessarie per calcolarli.
Si forniscano opportune giustificazioni per tutte le risposte.
Soluzione
Per x compreso tra 1 e 8 il programma calcola e stampa la seguente sequenza di numeri 1,
2, 3, 4, 3, 8, 9, 32
La ricorsione termina sempre, dato che per qualsiasi argomento la funzione viene
richiamata su argomenti sempre minori fino a raggiungere il caso base: un argomento
minore o uguale a zero
La nuova sequenza 1, 1, -1, -1, -1, -1, 1, 1

6.26. Funzione ricorsiva misteriosa (3)


Si dica cosa restituisce la seguente funzione sapendo che sia i parametri sono stringhe:
function [x]=mistero(s)
if s(1)==s(length(s))
p='[';
q=']';
else
p='(';
q=')';
end
if length(s)<=2
x=[p s q];
else
x=[p s(1) mistero(s(2:length(s)-1)) s(length(s)) q];
end

133

Soluzione
Se il primo carattere di s uguale all'ultimo, alle variabili p e q sono assegnate le parentesi
quadre, altrimenti le tonde. Se la lunghezza di s maggiore di due caratteri il risultato (x)
uguale a: una parentesi aperta p, il primo carattere di s, il risultato della chiamata alla stessa
funzione passando per la stessa s privata del primo e dell'ultimo carattere, l'ultimo
carattere di s, una parentesi chiusa q. Se la lunghezza di s minore o uguale a due caratteri
il risultato sar semplicemente la stessa s, posta tra parentesi (questa la condizione di
terminazione della ricorsione).
Di seguito vediamo gli ambienti locali di esecuzione utilizzando 'prova come stringa s:
IMMAGINE DELLO STACK ALL'ISTANTE 1
mistero('prova'): s='prova', p='(', q=')', x=?
IMMAGINE DELLO STACK ALL'ISTANTE 2
mistero('prova'): s='prova', p='(', q=')', x=?
mistero('rov'): s='rov', p='(', q=')', x=?
IMMAGINE DELLO STACK ALL'ISTANTE 3
mistero('prova'): s='prova', p='(', q=')', x=?
mistero('rov'): s='rov', p='(', q=')', x=?
mistero('o'): s='o', p='[', q=']', x='[o]'
IMMAGINE DELLO STACK ALL'ISTANTE 4
mistero('prova'): s='prova', p='(', q=')', x=?
mistero('rov'): s='rov', p='(', q=')', x='(r[o]v)'
IMMAGINE DELLO STACK ALL'ISTANTE 5
mistero('prova'): s='prova', p='(', q=')', x='(p(r[o]v)a)'

Il risultato quindi la prima e ultima lettera di s tra parentesi (quadre se le lettere sono
uguali, tonde se diverse) che racchiudono la seconda e la penultima lettera di s tra altre
parentesi, che racchiudono a loro volta la terza e la terzultima lettera di s tra ulteriori
parentesi, e cos via fino al centro di s.
Esecuzione
>> mistero('prova')
ans =
(p(r[o]v)a)
>> mistero('onorarono')
ans =
[o[n[o[r[a]r]o]n]o]
>> mistero('orto')
ans =
[o(rt)o]

134

6.27. Funzione di aggregazione generica


Si vuole scrivere una funzione che permetta di aggregare dei dati in modo generico. Il
primo parametro della funzione una funzione di aggregazione (come min, max, sum,
mean, ecc), il secondo parametro contiene i dati numerici da aggregare. Si scriva la
funzione. Si utilizzi la funzione per trovare la somma e la media dei numeri dati. Si utilizzi
la funzione per trovare la somma dei quadrati dei numeri (si agisca solo sul secondo
parametro della funzione). Si utilizzi la funzione per trovare la somma dei quadrati dei
numeri (si agisca solo sul primo parametro della funzione).
Soluzione
Per risolvere il punto 1 creo una funzione chiamata aggrega avente due parametri di
ingresso: il primo una variabile di tipo funzione f, il secondo un vettore di numeri n. Nel
corpo della funzione chiamo la funzione f attraverso la sua variabile passando come
parametro n. Il risultato della chiamata di f sar infine assegnato al parametro di ritorno di
aggrega.
Per risolvere il punto 2 invoco semplicemente la funzione aggrega passando come
parametro l'handler alla funzione esistente di MatLab sum e mean (cio nel codice si
scriver @sum e @mean).
Per risolvere il punto 3 chiamo la funzione aggrega come nel punto 2, ma modifico
semplicemente il secondo parametro nel suo quadrato.
Per risolvere il punto 4 al posto di chiamare direttamente la sum come fatto nel punto 2
creo un handler a una funzione anonima avente un solo parametro. All'interno di questa
funzione anonima chiamer la funzione sum passando come parametro il quadrato del
parametro di ingresso della funzione anonima.
function [res]=aggrega(f,n)
res=f(n);
n=1:10 % creo dei varoli di esempio nel vettore n
aggrega(@sum,n)
aggrega(@mean,n)
aggrega(@sum,n.^2)
aggrega(@(x)sum(x.^2),n)

Esecuzione
>> n=1:10
n =
1 2

10

>> aggrega(@sum,n)
ans = 55
>> aggrega(@mean,n)
ans = 5.5000
>> aggrega(@sum,n.^2)
ans = 385
>> aggrega(@(x)sum(x.^2),n)
ans = 385

135

6.28.

Calcolo dello zero di una funzione

Si scriva una funzione che calcoli lo zero di una generica funzione matematica continua f
all'interno dell'intervallo (a,b) e avente segno di f(a) discorde da f(b). Lo zero di una
funzione definito come il valore x tale che f(x)=0. Poich utilizziamo valori numerici
approssimati considereremo zeri validi anche approssimazioni f(x)<eps, per eps definito
come numero molto piccolo.
Soluzione
Usiamo il metodo della bisezione: si divide l'intervallo dato in parti uguali a ogni passo e si
controlla il segno della funzione nel punto medio.
Dal testo dell'esercizio sappiamo che la funzione sopra lo zero a un estremo e sotto lo
zero all'altro, per cui (per il teorema degli zeri) c almeno uno zero nell'intervallo. Per
trovarlo si considera il punto medio m dell'intervallo e si calcola la funzione in quel punto.
Se la funzione vale zero o ha un valore comunque abbastanza piccolo restituisco m,
altrimenti lo zero nell'intervallo (pi piccolo) compreso tra m e l'estremo in cui la
funzione ha segno diverso da quello che ha in m. Ripeto lo stesso ragionamento per il
nuovo intervallo.
Acquisisco la variabile di tipo funzione f e le variabili a e b (a<b) che rappresentano gli
estremi dell'intervallo in cui voglio trovare lo zero; se f(a) ha segno uguale a f(b) stampo un
errore e termino; calcolo il punto medio m tra a e b; se f(m) vale zero o il suo valore
assoluto minore di un numero sufficientemente piccolo (epsilon), la funzione ritorner il
valore m e terminer la sua esecuzione, se f(m) ha segno diverso da f(a) dimezzo
l'intervallo assegnando a b il valore di m, altrimenti dimezzo l'intervallo assegnando ad a il
valore di m.
function [m]=calcola_zero(f,a,b)

% se la funzione agli estremi dell'intervallo non ha segno


% diverso, esco restituendo un errore
if f(a)*f(b)>0
disp('Errore: segno della funzione agli estremi uguale');
return
end
m=(a+b)/2; % calcolo il punto medio
while abs(f(m))>eps % esco quando la funzione vale numericamente zero

% controllo se lo zero sta nella prima o nella seconda met


if f(a)*f(m)<0
b=m; % cambio solo il secondo estremo
else
a=m; % cambio solo il primo estremo
end
m=(a+b)/2; % ricalcolo il punto medio
end

Esecuzione
>> calcola_zero(@cos,0,4)
ans = 1.5708
>> calcola_zero(@sin,0,4)
ans = 3.1416
>> calcola_zero(@(x)x-1,-2,2)
ans = 1

136

6.29. Statistiche meteorologiche


Si vogliono avere delle funzioni per elaborare dei dati da un archivio di misurazioni
meteorologiche. Un archivio costituito da un file avente righe analoghe alla seguente:
CODICE_CITTA ANNO MESE GIORNO TIPO_MISURAZIONE VALORE

Tutti i campi della riga sono numeri interi a eccezione di VALORE che un numero reale.
Si scriva una funzione che, dato il nome del file, generi un array di strutture chiamato
"misure" che contiene tutti i dati letti.
Si scriva una funzione che, dato un array di misure, un codice citt e un tipo di misurazione
restituisce il minimo, la media e il massimo valore misurato in quella citt.
Soluzione
Leggo tutti i dati dal file specificato come parametro della funzione utilizzando il comando
textread, dopodich li copio opportunamente in un array di struct.
function [misure]=leggimisure(file)
[citta anno mese giorno tipo valore] = ...
textread(file,'%d %d %d %d %d %f');
for ii=1:length(citta)
misure(ii).citta=citta(ii);
misure(ii).anno=anno(ii);
misure(ii).giorno=giorno(ii);
misure(ii).tipo=tipo(ii);
misure(ii).valore=valore(ii);
end

Esecuzione
>> misure=leggimisure('misure.dat')
misure =
1x25 struct array with fields:
citta
anno
giorno
tipo
valore

Esprimo con un vettore logico chiamato selezione le citt di mio interesse, dopodich sulla
base di tale selezione calcolo minimo, media e massimo utilizzando le funzioni di
aggregazione min, mean e max.
function [minimo media massimo]=minmedmax(misure,citta,tipo)
selezione=[misure.citta]==citta&[misure.tipo]==tipo;
minimo=min([misure(selezione).valore]);
media=mean([misure(selezione).valore]);
massimo=max([misure(selezione).valore]);
Esecuzione
>> [min med max]=minmedmax(misure,1000,1)
min =
21.2000
med =
36.7500
max =
52.3000

137

6.30.

Funzione misteriosa di ordine superiore

Considerare la seguente funzione:


1 function [a]=supermistero(b,c)
2
switch c
3
case 1
4
a(1,:)=[0 b(0)];
5
a(2,:)=[1 b(1)];
6
case 2
7
for ii=[0 1]
8
for jj=[0 1]
9
a(jj+1+ii*2,:)=[ii jj b(ii,jj)];
10
end
11
end
12
case 3
13
for z=0:7
14
kk=mod(z,2);
15
jj=mod(floor(z/2),2);
16
ii=mod(floor(z/4),2);
17
a(z+1,:)=[ii jj kk b(ii,jj,kk)];
18
end
19
end
Si dica il valore restituito dalle seguenti invocazioni della funzione:
supermistero(@not,1)
supermistero(@and,2)
supermistero(@(x,y,z)x&~y|z,3)

Cosa calcola in generale la funzione data?


Soluzione
Nella prima chiamata si passa come primo parametro un handler alla funzione MatLab not.
Come secondo parametro si passa 1. Il secondo parametro serve a scegliere quale ramo del
costrutto switch sar eseguito. In questo caso eseguiremo le istruzioni 4 e 5. L'istruzione 4
assegna alla prima riga della matrice un vettore contenente 0 come primo elemento e b(0)
(equivalente a not(0), cio 1) come secondo elemento. L'istruzione 5 assegna alla seconda
riga della matrice a il vettore contenente 1 come primo elemento e b(1) (equivalente a
not(1), cio 0) come secondo elemento. Il risultato sar quindi una matrice avente 0 1 nella
prima riga e 1 0 nella seconda.
>> supermistero(@not,1)
ans =
0
1
1
0

Nella seconda chiamata passiamo come primo parametro un handler alla funzione MatLab
and e come secondo il valore 2. Si eseguiranno perci le istruzioni dalla 7 alla 11. Tali
istruzioni contengono due cicli, ognuno eseguito con indice che varia da 0 a 1. L'istruzione
9 viene eseguita 4 volte con le seguenti coppie di valori per gli indici ii,jj:
(0,0),(0,1),(1,0),(1,1). Ogni esecuzione assegna un vettore a una riga della matrice a: alla
prima un vettore di tre elementi [ii, jj, and(ii,jj)], cio [0 0 0], alla seconda [0 1 0], alla terza
[1 0 0] e alla quarta [1 1 1].

138

>> supermistero(@and,2)
ans =
0
0
0
0
1
0
1
0
0
1
1
1

Nella terza chiamata si passa come primo parametro un handler a una funzione anonima
contenente solo operatori booleani: x AND NOT y OR z. Per le regole di precedenza degli
operatori questo equivalente a (x AND (NOT y)) OR z. Per semplicit chiameremo questa
funzione f(x,y,z). Il secondo parametro fa in modo che vengano eseguite soltanto le
istruzioni dalla 13 alla 18. Queste istruzioni contengono un ciclo eseguito 8 volte (con
indice z che varia da 0 a 7). L'istruzione 17 all'interno del ciclo assegna un vettore a 8 righe
della matrice. Questo vettore ha come primi tre elementi le variabili ii,jj,kk calcolate dalle
righe 14,15,16 e il valore della funzione definita prima f(ii,jj,kk). Le variabili ii,jj,kk
rappresentano le cifre date dalla conversione dell'indice z da decimale a binario (cio
rappresentano i resti delle divisioni per 2 del numero z). Per cui le triple di valori ii,jj,kk
presenti come primi 3 elementi delle righe della matrice a sono: (0,0,0) (z=0), (0,0,1) (z=1),
(0,1,0) (z=2), (0,1,1) (z=3), (1,0,0) (z=4), (1,0,1) (z=5), (1,1,0) (z=6), (1,1,1) (z=7) e la
funzione f(ii,jj,kk), corrispondente al quarto elemento, avr rispettivamente i valori: 0, 1, 0,
1, 1, 1, 0, 1.
Esecuzione
>> supermistero(@(x,y,z)x&~y|z,3)
ans =
0
0
0
0
0
0
1
1
0
1
0
0
0
1
1
1
1
0
0
1
1
0
1
1
1
1
0
0
1
1
1
1

6.31. Funzioni di ordine superiore


Facendo uso della funzione di ordine superiore acc sottoriportata, codificare le funzioni
modulo1(v) e modulo2(v). La funzione modulo1(v) prende come argomento un vettore di
n

numeri v=[v1, v2, vn] e calcola e restituisce come risultato il valore

v i . La

vi *
i 1

i 1

funzione modulo2(v) invece prende come argomento un vettore di numeri v=[v 1, v2, vn]
n

e calcola e restituisce come risultato il valore

vi
i 1

Codice della funzione acc


function [x]=acc(f, a, u)
x = u;
for i=1:length(a)
x = f(x, a(i));
end

139

vi
i 1

Soluzione
function ris = modulo1(v)
prod = @(x, y) x*y;
sum = @(x, y) x+y;
ris = acc(prod, v, 1)*acc(sum, v, 0);
function ris = modulo2(v)
prod = @(x, y) x*y;
sum = @(x, y) x+y;
ris = acc(sum, v, 0)/acc(prod, v, 1);

6.32.

Statistiche esami

Un professore, dopo aver fatto sostenere l'esame agli studenti, vuole visualizzare delle
statistiche. Per fare questo ha a disposizione un file (voti.txt) avente in ogni riga il nome
dello studente e il voto conseguito separati da una virgola. Studenti assenti e ritirati sono
stati inseriti con voto pari a zero.
Si scriva il comando che estragga dal file "voti.txt" un array di studenti e un array di voti.
Si scriva una funzione che accetti entrambi gli array come parametri e li ordini dal voto
minore al voto maggiore.
Si scrivano i comandi per visualizzare i nomi degli studenti che hanno passato l'esame con
lode (voto>30) e si modifichi tale voto in 31.
Si scriva una funzione che genera un array di 31 elementi. Ogni elemento contiene il
numero di studenti con voto corrispondente allindice dell'elemento. Ignorare gli studenti
con voto 0.
Si tracci un grafico avente sull'asse x i vari voti e sull'asse y il numero di studenti che hanno
preso tali voti inserendo un opportuno titolo al grafico e agli assi.
Soluzione punto 1
[nomi voti]=textread('voti.txt','%s,%d')

Soluzione punto 2
Non si pu usare la funzione sort poich gli array da ordinare sono due. Per questo
decidiamo di ordinarli manualmente. L'algoritmo che decidiamo di usare (una variante del
bubble sort) prevede di scandire tutto l'array dal primo al penultimo elemento considerando
due elementi alla volta, e di sostituire gli elementi che non sono ordinati. Questo fino a
quando non si compie pi alcuna sostituzione. A ogni sostituzione di elementi nell'array dei
voti, sostituisco anche gli elementi corrispondenti dell'array dei nomi.
Chiamo i due array v (contenente i voti) e n (contenente i nomi);
Creo un indice i inizializzato a 0;
Imposto la variabile booleana scambio a falso (non ho ancora eseguito scambi);
Confronto l'elemento i-esimo dell'array dei voti con l'elemento (i+1)-esimo. Se i due
elementi sono nell'ordine desiderato vado al punto 8;
Scambio l'elemento i-esimo di v con l'elemento (i+1)-esimo di v;
Scambio l'elemento i-esimo di n con l'elemento (i+1)-esimo di n;
Assegno il valore vero alla variabile scambio;
Incremento l'indice i;

140

Se l'indice i minore della dimensione dell'array v torno al punto 4;


Se la variabile scambio vera torno al punto 3;
Restituisco i due array ordinati v e n.
function [nomi,voti]=ordina(n,v)
scambio=true;
while scambio
scambio=false;
for ii=1:length(v)-1
if v(ii)>v(ii+1)
scambio=true;
tv=v(ii);
tn=n(ii);
v(ii)=v(ii+1);
n(ii)=n(ii+1);
v(ii+1)=tv;
n(ii+1)=tn;
end
end
end
nomi=n;
voti=v;

Soluzione punto 3
[n v]=ordina(nomi,voti);
n(v>30)
v(v>30)=31

Soluzione punto 4
Consideriamo ogni elemento del vettore v. Per ogni elemento positivo incrementiamo
l'elemento del vettore risultato (z) avente indice pari al voto memorizzato nell'elemento di v
considerato.
function [z]=statistiche_voti(v)
z(31)=0;
for ii=1:length(v)
if v(ii)>0
z(v(ii))=z(v(ii))+1;
end
end

Soluzione punto 5
plot(1:31,statistiche_voti(v))
title('Grafico andamento voti')
xlabel('Voto')
ylabel('Numero di studenti')

141

Esecuzione

6.33.

Roulette truccata

Nel gioco della roulette si ha una ruota con 37 numeri da 0 a 36. A ogni turno un giocatore
pu scommettere su un numero. Alla fine delle puntate la ruota mostra il numero vincente.
Si scriva una funzione che simuli la ruota e generi il numero vincente accettando come
parametro un generatore di numeri casuali compresi tra 0 e 1.
Si scriva una funzione che provi a eseguire N giri e salvi i risultati delle frequenze di ogni
numero in un array di 37 elementi (il primo elemento per lo 0, il secondo per l'1 e cos via).
Si tracci il grafico delle frequenze prima utilizzando "rand" come generatore e poi
utilizzando la funzione "rand_truccata" mostrata di seguito e commentare il risultato.
function [n]=rand_truccata()
r=rand();
if r<0.02
n=0;
else
n=rand();
end
Qual la probabilit di vincere se si scommette sull'uscita di un numero dispari? Scrivere
una funzione che calcoli questa probabilit eseguendo 100000 simulazioni di giocate.
Soluzione punto 1
Creo una funzione che accetta come parametro una variabile di tipo funzione r. r dovr
restituire un valore razionale compreso tra 0 e 1 (0 incluso, 1 escluso). Si dovr poi
normalizzare tale valore nellintervallo di 37 numeri (da 0 a 36). Per farlo si moltiplica il
numero casuale per 37. Il risultato cos ottenuto anch'esso razionale, ma, poich il numero
che noi vogliamo generare intero, dobbiamo utilizzare anche la funzione floor, che
restituisce l'intero inferiore (o uguale) al numero dato.

142

function [n]=gioca(r)
n=floor(r()*37);

Esecuzione
>> gioca(@rand)
ans = 32
>> gioca(@rand)
ans = 29
>> gioca(@rand)
ans = 35

Soluzione punto 2
La funzione chiede in ingresso due parametri: un intero n che identifica il numero di giri
della roulette e un generatore di numeri casuali r. Nel corpo della funzione eseguo n giri di
roulette con il generatore di numeri casuali r. Dopo ogni giro incremento di uno l'elemento
del vettore risultato (freq) avente indice pari al numero ottenuto nel giro.
function [freq]=gioca_n_volte(n,r)
freq(37)=0;
for ii=1:n
giro=gioca(r);
freq(giro+1)=freq(giro+1)+1;
end

Esecuzione
>> gioca_n_volte(100000,@rand)
ans =
Columns 1 through 8
2642 2743 2770 2676
Columns 9 through 16
2762 2635 2664 2645
Columns 17 through 24
2754 2822 2762 2780
Columns 25 through 32
2721 2775 2641 2657
Columns 33 through 37
2784 2701 2633 2635

2642

2661

2601

2755

2680

2736

2637

2729

2713

2742

2731

2583

2701

2685

2667

2784

2751

Soluzione punto 3
plot(0:36,gioca_n_volte(10000,@rand))
xlabel('Numero generato dalla roulette')
ylabel('Numero di volte in cui il numero stato generato')
title('Test di affidabilit roulette')
plot(0:36,gioca_n_volte(10000,@rand_truccata))

Esecuzione con rand

143

Esecuzione con rand_truccata

Nel primo grafico si vede che le frequenze di tutti i numeri, sebbene non uguali, tendono ad
avere valori simili. Nel secondo grafico, poich la funzione rand_truccata nel 2% dei casi

144

d come valore zero e nell'altro 98% chiama la rand non truccata, si vede una dominanza
di tale numero rispetto agli altri.
Soluzione punto 4
La probabilit si pu calcolare analiticamente come rapporto tra il numero di casi
favorevoli e il numero di casi ammissibili. Essendo i casi favorevoli 18 (perch solo 18
numeri della roulette sono dispari), e i casi ammissibili 37 (36 pi lo zero), la probabilit
data da 18/37=0,486...
Vogliamo verificare con MATLAB che la probabilit calcolata sia simile a quella reale
ottenuta effettuando 100000 giocate sul pari.
Creiamo dunque una funzione che ha come parametri di ingresso il numero di giocate (n) e
il generatore di numeri casuali, e come parametro di uscita la probabilit calcolata sulla
base dei risultati delle giocate. Nel corpo della funzione generiamo n numeri e per ogni
numero dispari incrementiamo una variabile vittorie precedentemente inizializzata a zero.
Infine calcoliamo la probabilit come rapporto tra il numero di vittorie e il numero di
giocate totali.
function [p]=calcola_probabilita(n,r)
vittorie=0;
for ii=1:n
giro=gioca(r);
if mod(giro,2)>0
vittorie=vittorie+1;
end
end
p=vittorie/n;

Esecuzione
>> calcola_probabilita(100000,@rand)
ans = 0.4866

6.34.

Paraboloide iperbolico

Si disegni la superficie del paraboloide iperbolico dato dalla seguente equazione: z=x.^2y.^2 per valori di x e y nell'intervallo [-5,+5]. Impostare titoli ed etichette.
Soluzione
Assegno innanzitutto (come nei grafici a due dimensioni) vari valori nell'intervallo da -5 a
+5 (separati da microintervalli di dimensione opportuna) alle variabili x e y. Pi piccoli
sono tali intervalli e pi definito sar il grafico. Dopodich creo con la funzione meshgrid
le matrici xx e yy contenenti la prima i valori di x ripetuti length(y) volte, la seconda i
valori di y' ripetuti length(x) volte. La coppia di queste matrici identifica la griglia
rettangolare che sar utilizzata per modellare la superficie identificata da zz (pi piccoli
sono i microintervalli di x e y e pi fitta sar la griglia). La matrice zz si calcola a partire da
xx e yy utilizzando direttamente l'equazione della funzione a due variabili da rappresentare
(zz=xx2-yy2 in questo caso). Infine, le tre matrici ottenute (xx,yy,zz) saranno i parametri
dell'istruzione mesh che disegner il grafico.
x=-5:0.05:5;
y=x;
[xx yy]=meshgrid(x,y);
zz=xx.^2-yy.^2;
mesh(xx,yy,zz);

145

title('Paraboloide iperbolico')
xlabel('Asse x')
ylabel('Asse y')
zlabel('Asse z')

Esecuzione

146