Esercitazione 11 11 Gennaio 2011 (3 ore) Riassunto Nell'esercitazione di oggi abbiamo visto che in MATLAB è disponibile un'alternativa a disp per stampare su schermo. La funzione introdotta e' fprintf e si utilizza in modo simile alla printf del C. Esempio: a=input('inserire un numero da raddoppiare: '); fprintf('il doppio di %d fa %d\n', a, a*2); Abbiamo inoltre visto come tracciare grafici di superfici su spazio cartesiano con la funzione mesh: mesh(xx,yy,zz) xx e yy sono delle matrici create dalla funzione meshgrid(x,y), dove x e y rappresentano i valori di ascisse e ordinate, mentre zz e' creato a partire da xx e yy a seconda di come e' definita la funzione del piano che si vuole rappresentare. Abbiamo infine ripreso il concetto di funzione di ordine superiore introdotto a lezione. Si definisce funzione di ordine superiore una funzione avente tra i suoi parametri una o piu' variabili di tipo funzione. La dichiarazione di una funzione di ordine superiore e' analoga a quella di una funzione normale. Esempio: function [res]=funordsup(f,a,b) res=f(a,b); La funzione definita sopra ha come parametri di ingresso la variabile di tipo funzione f e le variabili a,b. Il risultato e' generato dall'invocazione di f a cui si passano i parametri a e b. Per inizializzare una variabile di tipo funzione si utilizza nell'assegnamento il simbolo '@' seguito dal nome della funzione esistente, oppure per assegnare una nuova funzione anonima si utilizza il simbolo '@' seguito dalle variabili di ingresso tra parentesi e separate da virgole, seguiti a loro volta dall'espressione che calcola il valore restituito della nuova funzione. Esempio di creazione di una variabile di tipo funzione miocoseno con handler ad una funzione esistente (coseno): >> cos(pi) ans = -1 >> miocoseno=@cos >> miocoseno(pi) ans = -1
Esempio di creazione di una variabile di tipo funzione mioquadrato con assegnamento di una nuova funzione anonima: >> mioquadrato=@(x)x.^2; >> mioquadrato(2) ans = 4 >> mioquadrato(4) ans = 16 Esercizio 1. (Paraboloide iperbolico) Si disegni la superficie del paraboloide iperbolico dato dalla seguente equazione: z=x.^2-y.^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. Piu' piccoli sono tali intervalli e piu' definito sara' il grafico. Dopodiche' 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 sara' utilizzata per modellare la superficie identificata da zz (piu' piccoli sono i microintervalli di x e y e piu' fitta sara' 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=xx 2 -yy 2 in questo caso). Infine, le tre matrici ottenute (xx,yy,zz) saranno i parametri dell'istruzione mesh che disegnera' il grafico. Codice x=-5:0.05:5; y=x; [xx yy]=meshgrid(x,y); zz=xx.^2-yy.^2; mesh(xx,yy,zz); title('paraboloide iperbolico') xlabel('asse x') ylabel('asse y') zlabel('asse z') Esecuzione
Esercizio 2. (Funzione di aggregazione generica) Si vuole scrivere una funzione che permetta di aggregare dei dati in modo generico. Il primo parametro della funzione e' una funzione di aggregazione (come min, max, sum, mean, ecc), il secondo parametro contiene i dati numerici da aggregare. 1. Si scriva la funzione; 2. Si utilizzi la funzione per trovare la somma e la media dei numeri dati; 3. Si utilizzi la funzione per trovare la somma dei quadrati dei numeri (si modifichi il punto 2 ago solo sul secondo parametro della funzione); 4. Si utilizzi la funzione per trovare la somma dei quadrati dei numeri (si Soluzione modifichi il punto 2 ago solo sul primo parametro della funzione). Per risolvere il punto 1 creo una funzione chiamata aggregazione avente due parametri di ingresso: il primo e' 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 sara' infine assegnato al parametro di ritorno di aggregazione. Per risolvere il punto 2 invoco semplicemente la funzione aggregazione passando come parametro l'handler alla funzione esistente di MatLab sum e mean (cioe' nel codice si scrivera' @sum e @mean). Per risolvere il punto 3 chiamo la funzione aggregazione 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 ad una funzione anonima avente un solo parametro. All'interno di questa funzione anonima chiamero' la funzione sum passando come parametro il quadrato del parametro di ingresso della funzione anonima. Codice punto 1 function [res]=aggregazione(f,n) res=f(n); Comandi punti 2,3,4 n=1:10 % creo dei varoli di esempio nel vettore n aggregazione(@sum,n) % punto 2 (summa) aggregazione(@mean,n) % punto 2 (media) aggregazione(@sum,n.^2) % punto 3 aggregazione(@(x)sum(x.^2),n) % punto 4
Esecuzione >> n=1:10 n = 1 2 3 4 5 6 7 8 9 10 >> aggregazione(@sum,n) ans = 55 >> aggregazione(@mean,n) ans = 5.5000 >> aggregazione(@sum,n.^2) ans = 385 >> aggregazione(@(x)sum(x.^2),n) ans = 385 Esercizio 3. (Roulette truccata) Nel gioco della roulette si ha una ruota raffigurante 37 numeri da 0 a 36. Ad ogni turno un giocatore puo' scommettere su un numero o su particolari combinazioni degli stessi. Alla fine delle puntate la ruota selezionera' il numero vincente. 1. 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. 2. Si scriva una funzione che provi ad eseguire N giri e salvi i risultati delle frequenze di ogni numero in un array di 37 elementi (il primo elemento per lo zero, il secondo per l'uno e cosi' via). 3. 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. 4. Qual e' la probabilita' di vincere se si scommette sull'uscita di un numero dispari? Scrivere una funzione che calcoli questa probabilita' effettuando 100000 simulazioni di giocate. function [n]=rand_truccata() r=rand(); if r<0.02 n=0; else n=rand(); Soluzione punto 1 Creo una funzione chiamata gioca che accetta come parametro una variabile di tipo funzione r. La funzione r, per ipotesi, dovra' restituire un valore razionale compreso tra 0 e 1 (0 incluso nell'intervallo, 1 escluso dall'intervallo). Il risultato sara' percio' la normalizzazione di tale valore all'interno di un intervallo di 37 numeri (da 0 a 36). Per ottenerlo dobbiamo semplicemente moltiplicare il numero casuale per 37. Il risultato cosi' ottenuto e' anch'esso razionale, ma, poiche' il numero che noi vogliamo generare e' intero, dobbiamo utilizzare anche la funzione floor, che restituisce l'intero inferiore al numero dato.
Codice 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 usando la funzione gioca con il generatore di numeri casuali r. Per ognuno di questi giri incremento di uno l'elemento del vettore risultato (freq) avente indice pari al numero ottenuto nel giro. Codice function [freq]=gioca_n_volte(n,r) freq(37)=0; for ii=1:n giro=gioca(r); freq(giro+1)=freq(giro+1)+1; Esecuzione >> gioca_n_volte(100000,@rand) ans = Columns 1 through 8 2642 2743 2770 2676 2642 2661 2601 2755 Columns 9 through 16 2762 2635 2664 2645 2680 2736 2637 2729 Columns 17 through 24 2754 2822 2762 2780 2713 2742 2731 2583 Columns 25 through 32 2721 2775 2641 2657 2701 2685 2667 2784 Columns 33 through 37 2784 2701 2633 2635 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 e'' stato generato') title('test di affidabilita'' roulette') plot(0:36,gioca_n_volte(10000,@rand_truccata))
Esecuzione con rand Esecuzione con rand_truccata Commento Nel primo grafico si vede che le frequenze di tutti i numeri, sebbene non uguali, tono ad avere valori simili. Nel secondo grafico, poiche' la funzione rand_truccata nel 2% dei casi da' 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 probabilita' si puo' calcolare analiticamente come rapporto tra il numero di casi favorevoli e il numero di casi ammissibili. Esso i casi favorevoli 18 (perche' solo 18 numeri della roulette sono dispari), e i casi ammissibili 37 (36 piu' lo zero), la probabilita' e' data da 18/37=0,486... Vogliamo verificare con MATLAB che la probabilita' 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 probabilita' 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 probabilita' come rapporto tra il numero di vittorie e numero di giocate totali. Codice function [p]=calcola_probabilita(n,r) vittorie=0; for ii=1:n giro=gioca(r); if mod(giro,2)>0 vittorie=vittorie+1; p=vittorie/n; Esecuzione >> calcola_probabilita(100000,@rand) ans = 0.4866 Esercizio 4 (Media pesata, TDE 08/02/2010) Data una serie di misurazioni i cui valori misurati sono contenuti in un vettore x e i relativi pesi sono contenuti in un vettore w (delle stesse dimensioni di x), la media pesata si calcola come segue: Si risponda ai seguenti quesiti utilizzando il linguaggio MATLAB. 1) Scrivere una funzione mediapesata avente come argomenti i vettori x e w e come risultato la media pesata. 2) Scrivere una funzione mediapesataspeciale con parametri analoghi alla precedente, ma che calcoli la media pesata considerando come zeri i pesi relativi alle misurazioni con il valore minimo e il valore massimo. 3) Si consideri una matrice Z di dimensione 2xN precedentemente definita in cui le colonne rappresentano le N misurazioni, la prima riga contiene i valori di ogni misurazione e la seconda riga i relativi pesi. Si scriva uno script per trovare gli indici delle misurazioni con valore compreso tra la media pesata e la media pesata speciale (estremi inclusi). 4) Scrivere una funzione mediapesatasuperiore avente come argomenti x, w, e una funzione f con parametri analoghi a quelle sviluppate ai punti 1 e 2. Il risultato sarà la media pesata calcolata utilizzando f. Si mostri infine un esempio di invocazione.
Soluzione punto 1 function r=mediapesata(x,w) r=sum(x.*w./sum(w)); Soluzione punto 2 function r=mediapesataspeciale(x,w) selmin=min(x)==x; selmax=max(x)==x; w(selmin selmax)=0; r=mediapesata(x,w); Soluzione punto 3 x=z(1,:); w=z(2,:); sel1=x>=mediapesata(x,w)&x<=mediapesataspeciale(x,w); sel2=x<=mediapesata(x,w)&x>=mediapesataspeciale(x,w); find(sel1 sel2) Soluzione punto 4 function r=mediapesatasuperiore(x,w,f) r=f(x,w); mediapesatasuperiore(x,w,@mediapesata) Esercizio 5 (Divisione intera, TDE 27/07/2010) Implementare in MATLAB una funzione ricorsiva che calcoli risultato e resto della divisione intera fra due numeri interi. La funzione deve ricevere come parametri di ingresso i due numeri interi x, y e fornire come parametri di uscita risultato e resto della divisione intera fra x e y. Nell implementazione non è possibile alcuna funzione di libreria disponibile in MATLAB. Suggerimento: x/y = (x - y + y)/y = 1 + (x - y)/y Soluzione function [r,q] = divintera(x,y) if (x<y) r = x; q = 0; else [r,q] = divintera (x-y,y); r = r+1;
Esercizio 6 (Coefficienti binomiali, TDE 01/09/2010) È noto, dalla definizione del coefficiente binomiale n, che, se n>0 e k 0<k<n, vale la seguente relazione ricorsiva n n 1 n 1 = + k k 1 k dove la base della ricorsione è data da n = 1 se n=0 o k=0 o k=n. k Utilizzare tale definizione ricorsiva per scrivere una funzione MATLAB ricorsiva che calcoli il valore del coefficiente binomiale n a partire dai k due parametri n e k. Simulare l'esecuzione della funzione che calcola il coefficiente 3 2 mostrando la sequenza delle chiamate ricorsive che hanno luogo durante il calcolo. Soluzione function [c]=coefbinric(n, k) if n==0 k==0 k==n c=1; else c=coefbinric(n-1,k-1)+coefbinric(n-1,k); La chiamata coefbinric(3,2)dà origine a coefbinric(2,1)+coefbinric(2,2); la prima di queste dà origine a coefbinric(1,0)+coefbinric(1,1), entrambe corrispondenti al caso base della ricorsione. Viene quindi restituito 2, che sommato al valore di coefbinric(2,2), pure corrispondente al caso base e quindi pari a 1, dà correttamente il valore 3.