You are on page 1of 54

Introduzione a ”MAPLE”

Andrea Ellero, Alberto Zorzi - AA.2002/2003

Questi appunti hanno lo scopo di introdurre all’uso del programma Maple


(Waterloo Maple Inc.) e sono di supporto alle lezioni di Informatica (idoneità),
Facoltà di Economia dell’Università Ca’Foscari di Venezia. La conoscenza del
programma puù essere approfondita utilizzando un qualsiasi manuale di Maple.

INDICE DEI PARAGRAFI

1. Calcoli, espressioni e funzioni.

2. Risoluzione di equazioni e sistemi.

3. Limiti, derivate, integrali.

4. Funzioni di più variabili e grafici.

5. Algebra delle matrici.

6. Introduzione alla programmazione.

1 1. Calcoli, espressioni e funzioni


1.1 Calcoli numerici e letterali

Maple è in grado di soddisfare esigenze di calcolo sia di tipo simbolico che


numerico.
1.1.1 Numeri razionali e numeri floating point

Provate a calcolare una somma algebrica di due numeri interi. Seguite


l’esempio e battete il tasto di ritorno a capo.
> 3-5;
−2
NB: non è necessario scrivere ”=” mentre è obbligatorio concludere
l’espressione con ”;”
> 7/2;

7
2
NB: non viene eseguita la divisione in modo numerico per non perdere
precisione negli eventuali calcoli successivi. Per Maple, 7/2 e 3.5 sono oggetti
diversi: il primo è un numero razionale, il secondo è un numero in virgola
mobile (floating point). Per chiarire la differenza consideriamo uno stesso
calcolo eseguito con Maple utilizzando la notazione razionale e con virgola:
> (1/3.0)*3;
.9999999999
> (1/3)*3;
1
NB: il simbolo ’*’ indica la moltiplicazione e non puù essere sottinteso.
Si noti che il primo calcolo viene effettuato in virgola mobile anche se un solo
numero (3.0) è di tipo floating point. Il secondo calcolo è esatto perchè 1/3 è
riconosciuto e trattato come numero razionale. Vediamo che pasticci possono
accadere: consideriamo un calcolo in cui siano utilizzate le due notazioni
appena viste
> (1/3.0)*3-(1/3)*3;

−.1 10−9
cioè -0.1 per un miliardesimo ovvero -0.0000000001 mentre, ovviamente,
dovrebbe risultare 0.
Possiamo chiedere un calcolo numerico più accurato chiedendo a Maple di
utilizzare un maggior numero di cifre (digits) decimali:
> Digits:= 10;

Digits := 10
> (1/3.0)*3-(1/3)*3;
−.1 10−24
ora gli zeri che precedono la cifra 1, dopo la virgola, sono 24: si tratta di un
numero molto vicino allo zero ma non è esattemente zero.
1.1.2 Arrotondamenti, troncamenti ed errori

La precisione nei calcoli effettuati da Maple è assai elevata, ma alla precisione


dei calcoli è necessario accompagnare attenzione nel fornire i dati alla
macchina e nell’interpretare i risultati che la macchina restituisce. Ad esempio
se forniamo dati poco precisi è inutile, se non dannoso, utilizzare molte cifre
decimali nei calcoli effettuati da Maple. Vediamo allora come comportarci in
alcuni casi frequenti.
Anzitutto, quando è opportuno trascurare alcune cifre decimali di un numero
possiamo semplicemente tenere solo le cifre che ci interessano: effettuiamo in
tal caso un troncamento del numero.
Possiamo diminuire l’errore nel considerare il dato effettuando un
arrotondamento. Effettuare un arrotondamento significa aumentare di una
unità l’ultima cifra che consideriamo qualora la prima cifra che stiamo per
eliminare sia maggiore o uguale a 5, troncare il numero altrimenti.
Ad esempio se
> x:=123.4492;
x := 123.4492
volendo considerare due cifre decimali con un troncamento otteniamo il
numero 123.44, arrotondando troviamo invece 123.45. Se desideriamo una sola
cifra decimale allora sia troncando che arrotondando otteniamo 123.4.
E’ chiaro che in generale l’arrotondamento, a parità di cifre considerate,
consente di ridurre l’errore commesso ed è pertanto preferibile.
Vediamo ora cosa accade se effettuiamo gli arrotondamenti troppo presto.
Supponiamo di dover calcolare quanto vino sia necessario per riempire un
contenitore cilindrico di alluminio (qui semplifichiamo e supponiamo si tratti
di un cilindro perfetto). Prendiamo le misure interne del cilindro. Con un
calibro (precisione 1/10=0.1 mm) riusciamo a misurare il diametro:
> Diam:= 9.31 ; # cm

Diam := 9.31
per l’altezza usiamo un metro con precisione di un millimetro:
> Altezza:= 19.4 ; # cm

Altezza := 19.4
Calcoliamo il volume:
> Volume:=(Diam/2)^2*Pi*Altezza; # il risultato è in cm^3

Volume := 420.3790850 π
> evalf(%);
1320.659845
AnzichÈ considerare l’intera cifra decidiamo di considerare solo le quattro cifre
a sinistra della virgola.

Quindi, arrotondando all’unità, otteniamo 1321 centimetri cubi (in litri:


1,321). Supponiamo che il vino costi 0,51 euro al litro e di dover riempire
19800 lattine. Il costo che dovremo sostenere sarà allora:
> Costo_totale:=1.321*0.51*19800;

Costo totale := 13339.45800

ovvero 13339,46 euro.

E’ una bella cifra che ci spinge ad effettuare una valutazione più precisa.
Tornando al calcolo del volume prendiamo subito qualche cifra in più, anzi
teniamo tutte quelle che vediamo scritte, non ci costa più fatica:
> Costo_totale:=1.320659845*0.51*19800;

Costo totale := 13336.02312

La differenza, in euro, è data da


> 13339.46-13336.02;
3.44

L’esempio ci suggerisce di effettuare i calcoli ritardando il più possibile il


momento nel quale effettuare gli arrotondamenti.

Errori nei dati iniziali e trasmissione dell’errore

Ma il nostro conto è anche affetto da un altro errore, un errore inevitabile


anche se meno evidente, dovuto alla precisione con la quale sono noti i dati
iniziali.

Per misurare il diametro del cilindro avevamo infatti a disposizione un calibro


con precisione di un decimo di millimetro. In realtà dunque siamo certi che il
diametro (Diam=9,31 cm) ha una misura compresa tra 9,30 e 9,32 cm; di più
non possiamo chiedere al calibro. Diciamo che l’errore assoluto in questa
misura è di 0,01 cm e possiamo scrivere Diam = 9,310,01. L’errore percentuale,
o errore relativo, è dato dal rapporto tra l’errore assoluto e la misura effettuata
> er_Diam:=0.01/9.32;

er Diam := .001072961373

vale a dire circa uno su mille.

Analogamente per l’altezza, l’errore assoluto è di 0,1 cm, ovvero Altezza=19,4


0,1 cm. L’errore relativo è in tal caso:
> er_Altezza:=0.1/19.4;
er Altezza := .005154639175

quindi dell’ordine del 5 per mille.

Ma quale errore commettiamo nel calcolo del volume?

Si dimostra che moltiplicando tra loro due misure l’errore percentuale


trasmesso nel calcolo è dato dalla somma degli errori percentuali. Nel nostro
caso allora:
> er_Volume:=er_Diam+er_Diam+er_Altezza;

er Volume := .007300561921

L’errore relativo nel calcolo del volume è dunque del 7 per mille (perchÈ
sommiamo due volte l’errore relativo del diametro?). Lo stesso errore relativo
si ripercuote sul calcolo del costo totale. Si noti che gli altri fattori che
compaiono nel calcolo del costo totale sono il numero 1/2, che è esatto cioè con
errore assoluto nullo, e π, che Maple tiene in memoria con un numero di cifre
significative sufficientemente elevato da poter essere considerato con errore
relativo trascurabile.

In termini assoluti il calcolo del volume è affetto allora dall’errore:


> ea_Volume:=er_Volume*Volume;

ea Volume := 3.069003540 π

> evalf(%);
9.641558976

In realtà quindi il volume di una singola lattina è 1320.659845 9.641558976


ovvero di millilitri 132110. L’errore su di una singola lattina è dell’ordine di
mezzo cucchiaio da cucina!

Per quanto riguarda il costo complessivo abbiamo invece:


> ea_Costo_totale:=er_Volume*Costo_totale;

ea Costo totale := 97.36046257

quindi un errore dell’ordine di un centinaio di euro, un errore che rende in


realtà trascurabile, in questo caso, l’errore complessivo dovuto al precedente
arrotondamento al centimetro cubo del volume della lattina!

Problemi simili a quelli incontrati nel caso di una moltiplicazione si hanno


anche nella trsmissione degli errori effettuando altre operazioni tra i dati: per
un loro adeguato trattamento rimandiamo ai testi specializzati in analisi
numerica.
1.1.3 Calcoli simbolici

Maple è in grado di fare calcoli di tipo letterale utilizzando moltissimi comandi


per la manipolazione algebrica. Vediamo qualche esempio.
> 3*a-5*a+4*a-b*a;

2a−ba

Manipoliamo l’espressione raccogliendone i fattori:


> factor(%);

−a (−2 + b)

NB: per indicare la riga di calcolo (execution group) appena eseguita si utilizza
il simbolo di percentuale (%), nelle versioni di Maple meno recenti lo stesso
effetto si ha utilizzando il doppio apice (”).
> 3*x*(x^2-y^2)^2/((x+y)*9*x);

1 (x2 − y2 )2
3 x+y
NB: l’elevamento a potenza viene indicato dal simbolo ’ˆ’.

Si puù notare che Maple effettua immediatamente le semplificazioni ovvie. Ma


puù fare di meglio:
> simplify(%);

1
(x − y) (x2 − y2 )
3
Vediamo qualche altra semplificazione:
> root(x^2,2);

x2
> simplify(%);

csgn(x) x

NB: csgn(x) indica il segno di x. Poteva far di meglio scrivendo il valore


assoluto di x, che pure è definito (si provi a scrivere >abs(x);) e si legge
meglio: questa è una avvisaglia del fatto che Maple puù perdersi in un bicchier
d’acqua.

Ancora un esempio:
> (x+2)*(x^2-1)/(x+1);

(x + 2) (x2 − 1)
x+1
cerchiamo di riscrivere l’espressione in modo più semplice:
> factor(%);
(x − 1) (x + 2)

Proviamo ad eseguire le operazioni


> expand(%);

x2 + x − 2

ancora non ci soddisfa, torniamo a fattorizzare


> factor(%);

(x − 1) (x + 2)

Rifacciamo il conto in ordine diverso


> (x+2)*(x^2-1)/(x+1);

(x + 2) (x2 − 1)
x+1
proviamo prima ad espandere
> expand(%);

x3 x 2 x2 2
− + −
x+1 x+1 x+1 x+1
un disastro! Proviamo a vedere se si semplifica qualcosa
> simplify(%);

x2 + x − 2

meglio. Ora proviamo a fattorizzare


> factor(%);

(x − 1) (x + 2)

L’ordine delle operazioni è ovviamente importante: l’abbiamo provato tante


volte facendo i conti a mano, qui almeno possiamo riprovare velocemente.
Provate a rifare il conto cambiando ancora l’ordine delle manipolazioni e con
altre espressioni.

Dagli esempi fin qui visti simplify puù apparire come il comando più utile; in
realtà il comando più flessibile è expand che consente, ad esempio, di stabilire
quale fattore raccogliere:
> expand((x+2)*(x+3)*(y+z),x);

x2 y + x 2 z + 5 x y + 5 x z + 6 y + 6 z
> expand((x+2)*(x+3)*(y+z),x+2);
(x + 2) x y + (x + 2) x z + 3 (x + 2) y + 3 (x + 2) z
> expand((x+2)*(x+3)*(y+z),y+z);
(y + z) x2 + 5 (y + z) x + 6 y + 6 z
> factor(%);
(x + 2) (x + 3) (y + z)

1.1.4 Altre informazioni

Maple consente operazioni sui numeri interi quali la divisione con resto, il
fattoriale, la fattorizzazione..., sui numeri complessi, su insiemi, vettori,
matrici,...

Sono inoltre definite alcune costanti quali


> exp(1);

e
> Pi;

1.2 Assegnazioni e funzioni

Possiamo associare un nome ad un oggetto matematico quale ad esempio


un’espressione, un’equazione, una funzione. La sintassi è nome := oggetto; .
Ad esempio
> fattore1:=x*y;

fattore1 := x y

ora fattore1 è una variabile che vale xy. Consideriamo una seconda variabile
> fattore2:=x*z;

fattore2 := x z

e moltiplichiamo
> prodotto:=fattore1*fattore2;

prodotto := x2 y z

Maple ha già effettuato qualche conto riconoscendo il valore delle variabili


utilizzate.

Possiamo definire in questo modo anche le funzioni:


> f:=x->x^2-1;

f := x → x2 − 1

La variabile f è in questo caso un oggetto di tipo funzione che possiamo


utilizzare come siamo abituati, per esempio per valutarla in un punto
> f(2);
3
ma anche in un punto simbolico
> f(antonio);

antonio 2 − 1
o componendola
> f(y-1);

(y − 1)2 − 1
Combiniamo una variabile di tipo numero con la funzione f
> alfredo:=3;

alfredo := 3
> f(alfredo);
8
E’ poi semplicissimo disegnare grafici mediante il comando plot:
> plot(f,-2..4,-2..5);

–2 –1 0 1 2 3 4
–1

–2

Nell’esempio la porzione di grafico che interessa è quella racchiusa nel


rettangolo [-2,4]x[-2,5]. Il secondo argomento del comando plot è un intervallo
contenuto nel dominio di f relativamente al quale interessa rappresentare il
grafico di f. Il terzo argomento è opzionale e, se presente, individua l’intervallo
di interesse relativamente al codominio.
2 2. Risoluzione di equazioni e sistemi

2.1 Equazioni

La risoluzione di equazioni è particolarmente semplice, il comando da


utilizzare è solve.
> solve({x^2=4},{x});

{x = 2}, {x = −2}

Maple commette errori nel caso di calcoli letterali, anche semplici, se ci sono
parametri
> solve({a*x+b=0},{x});

b
{x = − }
a
(cosa succede se a=0?) e non risponde in alcuni casi numerici ”proibiti”
> solve({0*x+3=0},{x});

E’ capace di lavorare con i numeri complessi


> solve({x^2+1=0},{x});

{x = I}, {x = −I}

(I è l’unità immaginaria vale a dire il numero complesso tale che Iˆ2=-1).

Vediamo qualche altro esempio


> solve({x^3+x^2-5*x=0},{x});

1 1√ 1 1√
{x = 0}, {x = − + 21}, {x = − − 21}
2 2 2 2
> solve({x^3-13*x+12=0},{x});

{x = 1}, {x = 3}, {x = −4}


> solve({x^2+y=0},{x,y});
{y = −x2, x = x}
> solve({x^2+y^2=0},{x,y});
{x = I y, y = y}, {x = −I y, y = y}
> solve({x^7+x^2=0},{x});
1√ 1 1 √ p √
{x = 0}, {x = 0}, {x = −1}, {x = − 5 + − I 2 5 + 5},
4 4 4
1 1√ 1 √ p √ 1 1√ 1 √ p √
{x = + 5 − I 2 5 − 5}, {x = + 5 + I 2 5 − 5},
4 4 4 4 4 4
1√ 1 1 √ p √
{x = − 5 + + I 2 5 + 5}
4 4 4
> solve({exp(x)*x^2-3=0},{x});
1√ 1√
{x = 2 LambertW( 3)}, {x = 2 LambertW(− 3)}
2 2
Nell’ultimo esempio LambertW è una funzione che soddisfa l’equazione
LambertW(x) * exp(LambertW(x)) = x .

Maple è riuscito a fornirci una soluzione esatta anche in questo caso.

In genere siamo perù più interessati alla risoluzione numerica di una equazione
come la precedente. Il comando da usare è in tal caso fsolve, con la stessa
sintassi di solve
> fsolve({exp(x)*x^2-3 = 0},{x});

{x = 1.033230904}

Ecco un altro caso interessante


> f:=sin(x);

f := sin(x)
> sol1:=solve({f=0.3},{x});
sol1 := {x = .3046926540}
> sol2:=fsolve({f=0.3},{x});
sol2 := {x = .3046926540}

Quale soluzione è corretta? In realtà queste sono solo due delle infinite
soluzioni dell’equazione considerata. Maple non è in grado, in questo caso, di
avvisarci della presenza di altre soluzioni.

Possiamo comunque accertare la bontà delle soluzioni trovate sostituendole


come argomento della funzione f utilizzando il comando subs
> subs(sol1,f);

sin(.3046926540)

chiedendo il calcolo del valore della funzione nel punto mediante il comando
evalf
> evalf(%);
.3000000000
> subs(sol2,f);

sin(.3046926540)
> evalf(%);

.3000000000
2.2 Sistemi di equazioni

Per risolvere sistemi di equazioni è sufficiente scrivere come argomenti del


comando solve l’elenco delle equazioni e delle variabili rispetto alle quali
risolverle
> eq1:=3*x+2*y=2;

eq1 := 3 x + 2 y = 2
> eq2:=x-y=4;

eq2 := x − y = 4
> solve({eq1,eq2},{x,y});

{x = 2, y = −2}
Vediamo un caso in cui il sistema presenta infinite soluzioni
> eq3:=x+2*y=1;

eq3 := x + 2 y = 1
> eq4:=2*x+4*y=2;

eq4 := 2 x + 4 y = 2
> solve({eq3,eq4},{x,y});

{y = y, x = −2 y + 1}
Mettiamo ora alla prova Maple su di un sistema di due equazioni non lineari.
Sia
> primo1:=3*x^3-exp(y);
primo1 := 3 x3 − ey
il primo membro della prima equazione e
> primo2:=y^2+x;

primo2 := y2 + x
il primo membro della seconda equazione e risolviamo il sistema primo1=0,
primo2=3 dando anche un nome all’insieme delle soluzioni
> soll:=fsolve({primo1=0,primo2=3},{x,y});

soll := {x = .4052948807, y = −1.610808840}


Controlliamo l’esattezza del risultato sostituendo le soluzioni trovate in primo1
e primo2
> subs(soll,primo1);

.1997260023 − e(−1.610808840)
> evalf(%);
0.
> subs(soll,primo2);
3.000000000
Si noti che la soluzione trovata non è unica (anche se Maple non lo dice):
> subs({x=1.098015136,y=1.379124673},primo1);

3.971423811 − e1.379124673
> evalf(%);
0.
> subs({x=1.098015136,y=1.379124673},primo2);
3.000000000

3 3. Limiti, derivate, integrali

Maple fornisce tutti gli strumenti tradizionali dell’analisi. Iniziamo a vedere


alcune delle possibilità offerte nel caso di funzioni reali di variabile reale.
Arriveremo a poter svolgere il tradizionale ”studio di funzione” in modo
completo.

3.1 3.1 Limiti

Definiamo una funzione della quale andremo poi a cercare alcuni limiti
> g:= x-> (x+1)*(x+2)*(x-3)/(x-1);

(x + 1) (x + 2) (x − 3)
g := x →
x−1
Proviamo a calcolare il limite per x - > 1. Prima definiamo il limite che ci
interessa

> Limit(g(x),x=1);
(x + 1) (x + 2) (x − 3)
lim
x→1 x−1
e adesso cerchiamone il valore
> value(%);

undefined
La risposta è corretta infatti calcolando i limiti da sinistra e da destra troviamo
> Limit(g(x),x=1,left);

(x + 1) (x + 2) (x − 3)
lim
x→1− x−1
> value(%);

Per il limite destro utilizziamo la lettera minuscola nel comando limit , questo
consente di ottenere subito il valore numerico del limite
> limit(g(x),x=1,right);

−∞

Se gli ultimi due limiti calcolati da Maple sono giusti (e lo sono) allora il primo
limite cercato non esiste. Vediamo come si calcolano i limiti a + e - infinito.
Ad esempio
> Limit(g(x),x=-infinity);

(x + 1) (x + 2) (x − 3)
lim
x→(−∞) x−1
> value(%);

3.2 3.2 Derivate

Consideriamo una funzione di x e contenente il parametro k:


> f:=x->x*cos(k*x);

f := x → x cos(k x)
> diff(f(x),x);

cos(k x) − x sin(k x) k

In realtà il fatto che f sia definita come funzione di x a Maple interessa poco.
Possiamo infatti derivare anche rispetto a k:
> diff(f(x),k);

−x2 sin(k x)

Cerchiamo ora i punti stazionari di una funzione. Definiamo la funzione


> h:=x->x^3-2*x^2-4*x;

h := x → x3 − 2 x2 − 4 x

e calcoliamone i punti stazionari ai quali diamo anche un nome (staz ):


> staz:=solve(diff(h(x),x)=0,x);

−2
staz := 2,
3
Più in generale possiamo studiare la monotonia della funzione determinando
gli intervalli nei quali la derivata si mantiene non negativa:
> solve(diff(h(x),x)>=0,x);

−2
RealRange(−∞, ), RealRange(2, ∞)
3
Otteniamo cosı̀ che -2/3 è un punto di massimo locale mentre è di minimo
locale il punto 2.
Vediamo come classificare i punti stazionari utilizzando la derivata seconda.
Anzitutto calcoliamola nel generico punto x:
> diff(h(x),x,x);
6x−4
Speghiamo ora a Maple di considerare l’espressione appena trovata come
immagine di x tramite la funzione derivata seconda di h, che chiameremo
DDh; per far questo usiamo il comando unapply
> DDh:=unapply(%,x);

DDh := x → 6 x − 4
Adesso possiamo valutare la derivata seconda nei due punti stazionari. Nel
primo punto si ha
> DDh(staz[1]);

8
perciù si tratta di un massimo. Nel secondo punto stazionario si ha
> DDh(staz[2]);
−8
che ci conferma che il punto 2 è di minimo per h. Vediamo il grafico
(numerico) di h fornito da Maple:
> plot(h(x),x=-3..5,-10..10);

10
8
6
4
2

–3 –2 –1 0 1 2 3 4 5
–2 x
–4
–6
–8
–10
3.3 3.3 Uno studio di funzione

Esaminiamo le caratteristiche del grafico di una funzione in modo dettagliato.


Consideriamo la funzione
> f:=x->x^3*(x+1)/(x^2+2);

x3 (x + 1)
f := x →
x2 + 2
Proviamo a farci disegnare il grafico da Maple:
> plot(f(x),x=-10..10);

100

80

60

40

20

–10 –8 –6 –4 –2 0 2 4 6 8 10
x

Pare che in 0 ci sia un minimo. Ma vediamo di effettuare uno studio delle


qualità delle proprietà della funzione in modo completo. Partiamo con il
calcolo dei limiti:
> limit(f(x),x=-infinity);


> limit(f(x),x=+infinity);

Studiamo il segno di f:
> solve(f(x)>=0,x);

RealRange(−∞, −1), RealRange(0, ∞)

pertanto f è negativa tra -1 e 0, positiva altrove. Per studiare la monotonia


calcoliamo la derivata di f
> diff(f(x),x);
x2 (x + 1) x3 2 x4 (x + 1)
3 2
+ 2 −
x +2 x +2 (x2 + 2)2

che si puù semplificare un po’:


> simplify(%);

x2 (2 x3 + 8 x + x2 + 6)
(x2 + 2)2

Cerchiamo i punti stazionari


> staz:=solve(diff(f(x),x)=0,x);

47
1 (1/3) 6 1
staz := 0, 0, − %1 + (1/3)
− ,
6 %1 6
1 (1/3) 47 1 1 1 √ 1 (1/3) 47 1
%1 − − + I 3 (− %1 − ),
12 12 %1(1/3) 6 2 6 6 %1(1/3)
1 (1/3) 47 1 1 1 √ 1 (1/3) 47 1
%1 − − − I 3 (− %1 − )
12 12 %1(1/3) 6 2 6 6 %1(1/3)

%1 := 253 + 18 518
Si leggono proprio male! Prima di tentare di scrivere meglio i punti stazionari
vediamo cosa si puù dire riguardo alla monotonia fornendo a Maple solo il
fattore che determina il segno della derivata
> solve(2*x^3+8*x+x^2+6>=0,x);
 
47
 1 √ 6√ 1 
RealRange − (253 + 18 518)(1/3) + − , ∞
6 (253 + 18 518)(1/3) 6

ancora una volta qualcosa di poco leggibile. Proviamo a riscrivere i punti


stazionari:
> s1:=evalf(staz[1]);

s1 := 0.
> s2:=evalf(staz[2]);
s2 := 0.
> s3:=evalf(staz[3]*1.);
s3 := −.7212304534
> s4:=evalf(staz[4]);
s4 := .1106152263 − 2.036497585 I
> s5:=evalf(staz[5]);
s5 := .1106152263 + 2.036497585 I
Valutiamo f nel terzo punto stazionario:
> f(s3);

−.04149894724

Proviamo ora ad utilizzare la derivata seconda per classificare i punti stazionari


> DDf:=unapply(diff(f(x),x,x),x);

x (x + 1) 6 x2 14 x3 (x + 1) 4 x4 8 x5 (x + 1)
DDf := x → 6 2
+ 2 − 2 2
− 2 2
+
x +2 x +2 (x + 2) (x + 2) (x2 + 2)3

Nei punti stazionari si ottiene:


> evalf(DDf(staz[1]));
0.
> evalf(DDf(staz[3]));
.7926818053

Il punto terzo punto stazionario è pertanto di minimo locale. Per classificare il


primo punto stazionario abbiamo bisogno di calcolare la derivata terza:
> DDDf:=unapply(diff(f(x),x,x,x),x);

x+1 18 x 54 x2 (x + 1) 42 x3 96 x4 (x + 1) 24 x5
DDDf := x → 6 + − − + +
x2 + 2 x2 + 2 (x2 + 2)2 (x2 + 2)2 (x2 + 2)3 (x2 + 2)3
48 x6 (x + 1)

(x2 + 2)4
> evalf(DDDf(staz[1]));

3.

L’origine è dunque un punto di flesso.

Avendo capito che i punti stazionari sono certamente compresi nell’intervallo


[-1, 1], proviamo a tracciare un secondo grafico numerico di f, questa volta
restringendo il range da considerare
> plot(f(x),x=-1.2..1);
0.6

0.5

0.4

0.3

0.2

0.1

–1 –0.5 0 0.5 1
x

Lo studio di funzione consente di guidare il modo di tracciare anche il grafico


numerico molto meglio rispetto al fuorviante grafico numerico tracciato
all’inizio.

3.4 3.4 Integrali

Possiamo calcolare sia integrali indefiniti che definiti. Ad esempio, calcoliamo


una primitiva della funzione
> f:=x->x*exp(x+1);

f := x → x e(x+1)

usando il comando int:


> int(f(x),x);

e(x+1) (x + 1) − 2 e(x+1)

Verifichiamo i calcoli derivando


> diff(%,x);

e(x+1) (x + 1) − e(x+1)

e semplificando
> simplify(%);

x e(x+1)
ottenendo la conferma della correttezza del calcolo dell’integrale.

Nota: anche se non sappiamo se il programma ha fornito una primitiva


corretta ci possiamo senz’altro fidare delle derivate fornite da Maple. Si tratta
di un conto puramente meccanico che un programmatore puù insegnare ad un
elaboratore con poche righe di istruzioni in un qualsiasi linguaggio di
programmazione.

Per calcolare un integrale definito è sufficiente indicare, oltre alla variabile,


l’intervallo di integrazione
> Int(f(x),x=0..2);
Z 2
x e(x+1) dx
0
> value(%);
e3 + e

Consideriamo ora una classico esempio di funzione le cui primitive non


possono essere scritte a partire da funzioni elementari utilizzando operazioni
algebriche o composizione di funzioni:
> g:=x->exp(-x^2);
2
g := x → e(−x )

calcoliamone l’integrale generalizzato nell’intervallo tra 0 e più infinito


> int(g(x),x=0..+infinity);

1√
π
2
che è corretto. Se vogliamo calcolare lo stesso integrale tra 0 e 1, ad esempio,
Maple ovviamente non puù far molto:
> int(g(x),x=0..5);

1 √
erf(5) π
2
dove erf ( x ) = 2/sqrt(Pi) * int ((exp(-xˆ2), t = 0..x ). Quindi Maple si mangia
la coda, e non poteva che

essere cosı̀. Possiamo perù chiedere una valutazione numerica dell’integrale:


> evalf(value(%));
.8862269255
4 4. Funzioni di più variabili e grafici

4.1 4.1 Limiti e derivate

Vediamo molto velocemente come quanto visto per le funzioni di una sola
variabile reale si estenda al caso di due variabili; l’estensione a più variabili
risulterà poi del tutto ovvia. Cominciamo definendo una funzione nelle
variabili x e y:
> f:=(x,y)->x^2*y-3*y/x;

3y
f := (x, y) → x2 y −
x
Proviamo a calcolare due limiti (facili)
> limit(f(x,y),{x=2,y=3});

15
2
> limit(f(x,y),{x=0,y=3});
undefined
Se tentiamo con altre funzioni facciamo presto a mettere in difficoltà Maple.
La funzione
> g:=(x,y)->x^2*y^2/(x^2*y^2+(x-y)^2);

x2 y 2
g := (x, y) →
x2 y 2 + (x − y)2
non ha limite in (0,0), Maple non risponde:
> limit(g(x,y),{x=0,y=0});

x2 y 2
limit( , {x = 0, y = 0})
x2 y2 + (x − y)2
Ma anche nel caso di una funzione con limite 0 in (0,0) Maple si arena
> limit(x^3/(x^2+y^2),{x=0,y=0});

x3
limit( , {x = 0, y = 0})
x2 + y 2
Non ci sono ovviamente problemi nel calcolo delle derivate parziali:
> diff(g(x,y),x);

x y2 x2 y2 (2 x y2 + 2 x − 2 y)
2 −
x2 y 2
+ (x − y) 2 (x2 y2 + (x − y)2 )2
> simplify(diff(g(x,y),y));
x3 y (x − y)
2
(x2 y2 + x2 − 2 x y + y2 )2
Ed ecco una derivata seconda mista
> simplify(diff(g(x,y),x,y));

x2 y2 (6 x y − 3 x2 + x2 y2 − 3 y2 )
2
(x2 y2 + x2 − 2 x y + y2 )3

Per valutare in un punto la derivata parziale seconda appena calcolata


definiamo la funzione
> DDXY:=unapply(%,(x,y));

x2 y2 (6 x y − 3 x2 + x2 y2 − 3 y2 )
DDXY := (x, y) → 2
(x2 y2 + x2 − 2 x y + y2 )3

che ora possiamo valutare dove ci interessa, ad esempio in (1,-1):


> DDXY(1,-1);

−22
125

4.2 4.2 Grafici

Le possibilità grafiche sono uno dei punti forti dei programmi tipo Maple.
Analizziamo prima alcune possibilità non ancora esplorate riguardo alle
funzioni di una sola variabile. Passeremo poi alle funzioni di due variabili.

4.2.1 4.2.1 Alcune potenzialità grafiche per funzioni di una sola vari-
abile

> plot(sin(x),x=0..2*Pi,title="funzione seno");


funzione seno
1

0.5

0 1 2 3 4 5 6
x

–0.5

–1

Possiamo anche tentare una compressione dell’asse delle x per avere un’idea
del comportamento della funzione per valori molto grandi dell’argomento
> plot(sin(x),x=0..infinity);

0 infinity
x

Ma attenzione all’interpretazione delle proprietà geometriche del grafico.


Guardate cosa accade del grafico della funzione logaritmo in base e (che è una
funzione concava!):
> plot(ln(x),x=0..infinity);
infinity

0 infinity
x

-infinity

Per utilizzare potenzialità grafiche disponibili solo a domanda, chiediamo a


Maple di caricare il modulo plots:
> with(plots);

Warning, the name changecoords has been redefined

[animate, animate3d , animatecurve, arrow, changecoords, complexplot, complexplot3d ,


conformal, conformal3d, contourplot, contourplot3d , coordplot, coordplot3d ,
cylinderplot, densityplot, display, display3d , fieldplot, fieldplot3d, gradplot,
gradplot3d , implicitplot, implicitplot3d, inequal , listcontplot, listcontplot3d,
listdensityplot, listplot, listplot3d, loglogplot, logplot, matrixplot, odeplot , pareto,
pointplot, pointplot3d, polarplot, polygonplot, polygonplot3d ,
polyhedra supported, polyhedraplot, replot, rootlocus, semilogplot, setoptions,
setoptions3d , spacecurve, sparsematrixplot, sphereplot, surfdata, textplot,
textplot3d , tubeplot]

Possiamo ora utilizzare tutti i comandi elencati sopra. Per esempio possiamo
utilizzare le coordinate polari
> polarplot(1,theta=0..2*Pi);
1

0.5

–1 –0.5 0.5 1

–0.5

–1

Per un confronto tra coordinate cartesiane e polari prendiamo la curva di


equazioni parametriche x=t, y=t in coordinate cartesiane
> plot([t,t,t=-2*Pi..2*Pi]);

–6 –4 –2 0 2 4 6
–2

–4

–6

e in coordinate polari, vale a dire interpretando la prima coordinata come la


distanza dall’origine e la seconda coordinata come angolo rispetto al semiasse
positivo delle ascisse
> polarplot([t,t,t=-2*Pi..2*Pi]);
1
–6 –4 –2 2 4 6
0
–1

–2

–3

–4

Veniamo ora ad un grafico in scala semilogaritmica


> logplot(10^x,x=0..10);

1e+10
1e+09
1e+08
1e+07
1e+06
1e+05
.1e5
.1e4
.1e3
.1e2
1. 2 4 6 8 10
x

e ad una curva definita mediante una equazione ben nota


> implicitplot(x^2+y^2=1,x=-1..1,y=-1..1);
1

y 0.5

–1 –0.5 0 0.5 1
x

–0.5

–1

Quest’ultimo comando è particolarmente utile quando si hanno curve ”meno


note” che Maple traccia

senza protestare
> implicitplot(exp(x^2*y)-exp(y)=sin(4*x),x=-2..2,y=-5..5);

y
2

–1.5 –1 –0.5 0 0.5 1 1.5 2


x
–2

–4
4.2.2 4.2.2 Grafici per funzioni di due variabili

Vediamo alcuni esempi di grafici in tre dimensioni ottenuti con il comando


plot3d e come tracciare le curve di livello.
> plot3d(x^2+y^2,x=-4..4,y=-4..4,style=patch,color=x,grid=[50,50],orien
> tation=[160,100],axes=boxed,title=‘paraboloide‘);

paraboloide

30
25
20
15
10
5
–4 2 0
–2 y –2 –4
0 0
4 2 x

> contourplot(x^2+y^2,x=-5..5,y=-5..5,contours=25);

y
2

–4 –2 0 2 4
x
–2

–4
> plot3d(y^2-x^2,x=-4..4,y=-4..4,style=contour,contours=50,grid=[50,50]
> ,orientation=[200,60],color=black,axes=boxed,title=‘sella‘);

sella

15
10
5
0
–5 4
–10 2
–15 0 x
4 –2
2 0
y –2 –4
–4

> densityplot(x^2+y^2,x=-5..5,y=-5..5);

4
y
2

–4 –2 0 2 4
x
–2

–4
5 5. Algebra delle matrici

Esaminiamo ora alcune delle possibilità che Maple offre nel calcolo matriciale.
Anzitutto vi sono due pacchetti che possiamo richiamare per operare sulle
matrici e, più in generale, su probelmi di algebra lineare: linalg eLinearAlgebra .
Qui esamineremo solo alcune delle possibilità offerte dal primo che andiamo a
caricare:
> with(linalg);

Warning, the protected names norm and trace have been redefined and
unprotected

[BlockDiagonal , GramSchmidt, JordanBlock , LUdecomp, QRdecomp, Wronskian, addcol,


addrow, adj , adjoint, angle, augment , backsub, band , basis, bezout , blockmatrix,
charmat, charpoly, cholesky, col, coldim, colspace, colspan, companion, concat,
cond , copyinto, crossprod, curl, definite, delcols, delrows, det, diag, diverge,
dotprod, eigenvals, eigenvalues, eigenvectors, eigenvects, entermatrix, equal,
exponential , extend , ffgausselim, fibonacci , forwardsub, frobenius, gausselim,
gaussjord, geneqns, genmatrix , grad, hadamard , hermite, hessian, hilbert,
htranspose, ihermite, indexfunc, innerprod, intbasis, inverse, ismith, issimilar,
iszero, jacobian, jordan, kernel, laplacian, leastsqrs, linsolve, matadd , matrix ,
minor, minpoly, mulcol, mulrow, multiply, norm, normalize, nullspace, orthog,
permanent, pivot, potential, randmatrix , randvector , rank , ratform, row, rowdim,
rowspace, rowspan, rref , scalarmul, singularvals, smith, stackmatrix, submatrix ,
subvector, sumbasis, swapcol, swaprow, sylvester, toeplitz, trace, transpose,
vandermonde, vecpotent, vectdim, vector, wronskian]

Definiamo anzitutto due vettori di 3 componenti:

> v:= vector(3,[1,2,3]);w:=vector(3,[5,6,7]);


v := [1, 2, 3]
w := [5, 6, 7]

Possiamo ora effettuare tutte le operazioni tra vettori.

Partiamo con la somma:


> v+w;

v+w

Per vedere esplicitamente il risultato dobbiamo valutare l’espressione con


l’istruzione evalm:
> evalm(%);
[6, 8, 10]

Ecco invece la moltiplicazione per uno scalare


> evalm(3*w);

[15, 18, 21]

Il prodotto scalare, o prodotto interno, si scrive invece


> innerprod(v,w);

38

Passiamo alle matrici. Definiamo una matrice 2 per 3 e chiamiamola A:

> A := matrix( 2, 3, [[1,3,2], [-5,14,9]]);


 
1 3 2
A :=
−5 14 9

una matrice 3 per 3 di nome B:

> B := matrix( 3, 3, [[1,-1,1], [0,20,-8], [2,0,2]]);


 
1 −1 1
B :=  0 20 −8 
2 0 2

e una seconda matrice 2 per 3 di nome C:


> C := matrix( 2, 3, [[0,5,2], [1,2,-1]]);
 
0 5 2
C :=
1 2 −1

e facciamo un po’ di operazioni tra matrici:

> evalm(A+C);
 
1 8 4
−4 16 8
> evalm(2*A);
 
2 6 4
−10 28 18

Per l’operazione di moltiplicazione tra matrici (righe per colonne) dobbiamo


usare il simbolo &* :
> evalm(A&*B);
 
5 59 −19
13 285 −99

La trasposta e l’inversa richiedono solo l’utilizzo dei corrispondenti termini


inglesi:
> transpose(A);
 
1 −5
 3 14 
2 9

> BINV:=inverse(B);
 5 1 −3 
 2 8 4 
 
 1 
BINV :=  −1 0 
 2 
 
−5 −1 5
2 8 4
Ha fatto bene i conti? Controlliamo:
> evalm(B&*BINV);
 
1 0 0
 0 1 0 
0 0 1

OK!

Ancora, possiamo calcolare determinante e rango:


> det(B);
16
> rank(A);
2

Naturalmente ci vengono segnalati gli errori nell’impostare i calcoli. Ad


esempio non è possibile moltiplicare B per A:
> evalm(B&*A);

Error, (in linalg[multiply]) non matching dimensions for vector/matrix


product

Data la matrice A ed il vettore dei termini noti


> b:= vector(2,[1,2]);

b := [1, 2]

il sistema Ax=b si risolve con l’istruzione linsolve:


> x:=linsolve(A,b);
 
5 1 7 29
x := + t 1 , t 1, − t1
19 19 19 19
(in questo caso i vettori soluzione sono infiniti e si ottengono al variare di t1
nell’insieme dei numeri reali).

Possiamo ottenere il valore della prima componente del vettore soluzione


> x[1];

5 1
+ t1
19 19
che in corrispondenza di un fissato valore del parametro
> _t[1]:=1;
t 1 := 1

diviene
> x[1];
6
19
Vediamo ora come ottenere la matrice inversa della matrice B in base alla
definizione: l’inversa, se esiste, risolve l’equazione tra matrici BX=I dove I è la
matrice identità. Definiamo la matrice identità come una matrice diagonale :
> ID:=diag(1,1,1);
 
1 0 0
ID :=  0 1 0 
0 0 1
Quindi risolviamo il sistema

> BINVbis:=linsolve(B,ID);
 5 1 −3 
 2 8 4 
 
 1 
BINVbis :=  −1 0 
 2 
 
−5 −1 5
2 8 4
che è l’inversa trovata prima da Maple, possiamo farlo controllare a Maple:
> evalm(BINV-BINVbis);
 
0 0 0
 0 0 0 
0 0 0
la loro differenza è zero quindi coincidono.

6 6. Introduzione alla programmazione

6.1 6.1 Procedure

6.1.1 6.1.1 Introduzione

Spesso nella risoluzione dei problemi accade di dovere eseguire più volte una o
più istruzioni in un ordine stabilito. Si supponga ad esempio di dover calcolare
il montante di una operazione finanziaria oppure un tasso di interesse: per
risolvere diversi problemi del genere cambiano i dati, ma le formule rimangono
sempre le stesse. Sarebbe quindi opportuno evitare di dovere riscrivere le
formule ogni volta, ma memorizzarle una volta per tutte e riutilizzarle quando
servono (risparmiando tempo e fatica). Questa opportunità è offerta dalle
procedure, vediamo come realizzarla.

6.1.2 6.1.2 Un esempio di procedura

Supponiamo di dover calcolare il montante M di un capitale C in regime di


interesse semplice, dopo t anni e con tasso d’interesse annuo i :

M = C*(1 + i*t)

I dati da considerare in ingresso ed in uscita sono, rispettivamente:

• dati in ingresso: C (capitale iniziale), t (durata in anni) e i (tasso di


interesse annuo)

• dato in uscita: M (montante)

Dichiarazione di un procedura
Per poter riutilizzare più volte la formula senza avere la necessità di riscriverla
ogni volta, possiamo dichiarare una procedura che esegua la formula del calcolo
del montante comunque vengano specificati i dati in ingresso.

A tale scopo occorre specificare:

• un nome da assegnare alla sequenza di calcoli da effettuare (il nome della


procedura)

• un ”avviso” per MAPLE che si tratta di una procedura

• quali sono i dati in ingresso

• come calcolare il risultato

La dichiarazione di una procedura che consenta il calcolo del montante è:

> montante_IntSempl := proc(C, t, i)


> C*(1+i*t)
> end proc;
montante IntSempl := proc(C, t, i) C ∗ (1 + i ∗ t) end proc

dove, nell’ordine, sono specificati:

• ”montante IntSempl”: è il nome che abbiamo scelto per la procedura ed


è seguito dall’operatore di assegnazione (:=); è buona regola utilizzare dei
nomi significativi che ci aiutino a ricordare ”cosa fa” la procedura;

• ”proc” è una parola chiave: serve ad avvisare MAPLE che si tratta di una
procedura;

• di seguito sono specificati (tra parentesi tonde e separati da virgole) i


dati in ingresso che sono detti parametri (o argomenti) formali della
procedura; nel nostro esempio gli argomenti sono 3: il capitale C, il tempo
t ed il tasso di interesse i. Anche in questo caso la scelta dei nomi e
dell’ordine degli argomenti è libera;
• la formula che calcola il montante.

Per indicare la fine della dichiarazione della procedura si scrive end oppure
end proc. Se nella dichiarazione non ci sono errori di sintassi, MAPLE
riscrive la procedura (in blu) dopo l’end finale.

Esecuzione di una procedura

Una volta dichiarata una procedura, per eseguirla basta scriverne il nome
seguito dai valori che intendiamo assegnare agli argomenti: un’istruzione di
questo genere è detta chiamata della procedura ed i valori passati sono
detti parametri (o argomenti) attuali della chiamata.

Ad esempio, per calcolare il montante corrispondente a C = 1000 euro, t = 10


anni e i = 4% annuo, è sufficiente scrivere la chiamata avente 1000, 10 e 0.04
come argomenti attuali:
> montante_IntSempl(1000, 10, 0.04);

1400.00

Il valore stampato 1400.00 è il montante richiesto e viene restituito dalla


procedura perchÈ è il risultato dell’ultima istruzione eseguita (quella prima
dell’end).

Per effettuare un’altra esecuzione, ad esempio con C = 3500 euro , t = 9 anni


e i = 5% annuo, basta scrivere un’altra chiamata:
> montante_IntSempl(3500, 9, 0.05);

5075.00

Alcune raccomandazioni: è vero che il numero e l’ordine degli argomenti


formali lo scegliamo noi arbitrariamente, ma una volta fatte, queste scelte
vanno rispettate quando si effettuano le chiamate. Ad esempio, la chiamata:
> montante_IntSempl(9, 3500, 0.05);

1584.00

dà un risultato diverso rispetto alla chiamata precedente: giustamente, perchÈ


pur trattandosi degli stessi valori, gli argomenti attuali sono scritti in ordine
diverso. Infatti, nella dichiarazione della procedura si era deciso che il primo
argomento fosse il capitale, e perciù nell’ultima chiamata viene calcolato il
montante di un capitale di 9 euro dopo 3500 anni al tasso del 5%. Dunque:
l’ordine degli argomenti attuali deve corrispondere all’ordine degli argomenti formali.

Vediamo ora cosa accade se togliamo un argomento attuale dalla chiamata:


> montante_IntSempl(1000, 10);

Error, (in montante_IntSempl) montante_IntSempl uses a 3rd argument,


i, which is missing

è data una segnalazione d’errore perchÈ nella dichiarazione della procedura gli
argomenti formali erano 3, mentre in questa chiamata gli argomenti attuali
sono solo 2 (in questo caso MAPLE non sa quanto vale il tasso i); dunque:

il numero degli argomenti attuali deve corrispondere al numero degli argomenti formali.

Una chiamata di procedura restituisce un risultato (lo stesso che viene


stampato) che puù essere assegnato ad una variabile: ad esempio la chiamata
> montante_IntSempl(1200,5,0.03);

1380.00

restituisce il valore 1380 che puù essere assegnato ad una variabile:


> montante := montante_IntSempl(1200,5,0.03);

montante := 1380.00

se quindi scriviamo il nome della variabile è visualizzato il dato in essa


memorizzato:
> montante;
1380.00

Una procedura puù anche essere priva di argomenti, ad esempio:


> prova := proc()

> print("ciao a tutti")

> end;

prova := proc() print(“ciao a tutti”) end proc

la procedura ha come unica istruzione una stampa (print) che si limita a


stampare la stringa (= sequenza di simboli alfanumerici) racchiusa tra doppi
apici.
Anche se non ci sono argomenti le parentesi nella chiamata vanno messe:
> prova();

“ciao a tutti”

6.1.3 6.1.3 Un altro esempio di procedura

Operiamo questa volta di operare in regime di interesse composto, in tal caso,


noti il capitale iniziale C, la durata t dell’impiego ed il tasso d’intersse annuo
i, il montante M è dato da:

M = C*(1 + i)ˆt

Supponiamo in particolare di volere determinare, dati il montante, la durata t


ed il tasso di interesse i, il capitale iniziale e l’interesse corrispondenti, ovvero:

C = M / (1 + i)ˆt

I=M-C.

In questo caso i dati del problema sono:

• dati in ingresso: M (montante), t (durata in anni) e i (tasso di interesse


annuo)

• dati in uscita: C (capitale iniziale) e I (interesse)

La differenza sostanziale rispetto al caso precedente è che in questo caso i dati


in uscita sono 2 e non uno solo.

Proviamo a dichiarare la procedura come segue:


> capInter_IntComp := proc(M, t, i)

> M/(1+i)^t;

> M-C

> end;

capInter IntComp := proc(M, t, i) M (i + 1)t ; M − C end proc
nessuna segnalazione d’errore, ma ciù non significa che la procedura (quando
eseguita) fornisca i risultati corretti; infatti, se proviamo ad effettuare una
chiamata della procedura (con M = 2000 euro, t = 3 anni e i = 11 %):
> capInter_IntComp(2000,3,0.11);

2000 − C

C’è qualcosa che non va: la procedura dovrebbe stampare 2 numeri e invece
stampa un’espressione con una C di troppo: come mai ? L’espressione
rappresenta il montante (che è 2000, giusto) e corrisponde all’ultima istruzione
(prima dell’end), ma al posto della variabile C dovrebbe esserci il valore del
capitale calcolato nell’istruzione che precede. Già, ma noi non abbiamo
specificato che il risultato di tale istruzione sia memorizzato in C; per farlo
aggiungiamo una assegnazione nella seconda riga e torniamo a dichiarare la
procedura:
> capInter_IntComp := proc(M, t, i)

> C := M/(1+i)^t;

> M-C;

> end;

Warning, ‘C‘ is implicitly declared local to procedure


‘capInter_IntComp‘

capInter IntComp := proc(M, t, i) local C; C := M (i + 1)t ; M − C end proc

La nuova dichiarazione dà una segnalazione di ”Warning” (è un tipo di errore


non grave che consente comunque l’esecuzione della procedura), tale
segnalazione ci avverte che la variabile C è definita implicitamente, ovvero è
utilizzata nella procedura senza essere variabile di input e senza che Maple sia
stato avvisato in altro modo del suo utilizzo. Evidentemente Maple preferisce
una dichiarazione esplicita delle variabili utilizzate. La riscrittura della
procedura fatta da Maple ci suggerisce infatti quali sono le sue preferenze;
d’accordo, copiamo e riproviamo:
> capInter_IntComp := proc(M, t, i) local C;
> C:=M/(1+i)^t;

> M-C

> end;

capInter IntComp := proc(M, t, i) local C; C := M (i + 1)t ; M − C end proc

La segnalazione di Warning è scomparsa; rifacciamo la chiamata:


> capInter_IntComp(2000,3,0.11);

537.617237

Benino: questo è il valore corretto dell’interesse, ma dov’è il valore del capitale


(la procedura nelle nostre intenzioni dovrebbe avere 2 valori in uscita ) ?
La risposta è: l’output fornito automaticamente è un solo numero; infatti in
Maple una procedura, salvo indicazioni diverse, restituisce un solo numero
ovvero il risultato dell’ultima istruzione.

Per visualizzare il valore del capitale è sufficiente aggiungere un’istruzione di


stampa:
> capInter_IntComp := proc(M, t, i) local C;

> C:=M/(1+i)^t;

> print(C);
> M-C

> end;

capInter IntComp := proc(M, t, i) local C; C := M (i + 1)t ; print(C) ; M − C end proc

nessuna segnalazione d’errore; proviamo ad eseguire:


> capInter_IntComp(2000,3,0.11);

1462.382763
537.617237

ora ci siamo, i due valori sono rispettivamente il capitale (stampato con


l’istruzione print) e l’interesse (fornito come output automaticamente essendo
stato calcolato con l’ultima istruzione della procedura).

Un modo, di più chiara leggibilità, per ottenere entrambi i valori è quello di


stabilire esplicitamente qual’è l’output della procedura utilizzando l’istruzione
return, la cui sintassi è return(espressione). Cambiamo allora nuovamente la
dichiarazione della procedura:
> capInter_IntComp := proc(M, t, i) local C;

> C:=M/(1+i)^t;

> return(C,M-C);

> end;

capInter IntComp :=

proc(M, t, i) local C; C := M (i + 1)t ; return C, M − C end proc

Cosı̀ la chiamata della procedura fornisce come output un vettore di due


numeri:
> capInter_IntComp(2000,3,0.11);

1462.382763, 537.617237

A tale output possiamo anche assegnare un nome, ad esempio


> risultato:=capInter_IntComp(2000,3,0.11);

risultato := 1462.382763, 537.617237


In questo modo i numeri ottenuti all’interno della procedura possono essere
utilizzati come fossero due variabili qualsiasi all’esterno della procedura stessa;
ad esempio con
> risultato[1]+risultato[2];
2000.000000

ricalcoliamo il montante M.

Ancora un’osservazione circa i ”;” (”punti e virgola”): nell’ultima versione la


procedura ha 3 istruzioni (calcolo di C, stampa di C e calcolo dell’interesse)
ed il ”;” c’è dopo le prime due istruzioni ma non dopo la terza. La ragione sta
nel fatto che il ”;” serve a separare 2 istruzioni successive; quindi è facoltativo
metterlo dopo l’ultima istruzione (quella prima dell’end) perchÈ l’end non è
considerata un’istruzione, mentre è obbligatorio negli altri casi e se manca è
segnalato un errore. Se ad esempio togliamo il ”;” dopo la prima istruzione:
> capInter_IntComp := proc(M, t, i) local C;
> C:=M/(1+i)^t;

> print(C);

> M-C

> end;

capInter IntComp := proc(M, t, i) local C; C := M (i + 1)t ; print(C) ; M − C end proc

è restituito un errore di sintassi e la dichiarazione della procedura non è stata


accettata da MAPLE.

6.2 6.2 Istruzioni condizionali


6.2.1 6.2.1 L’istruzione if-then-else
Supponiamo di voler calcolare il periodo di tempo per cui deve essere investito
un capitale C in modo da ottenere il montante M se gli interesse sono
calcolati al tasso annuo i con capitalizzazione composta. Una procedura che
calcola la durata dell’investimento è ad esempio:
> tempo_IntComp := proc(M, C, i)

> log[1+i](M/C);
> end proc;

tempo IntComp := proc(M, C, i) logi+1 (M C) end proc

([i+1] indica la base del logaritmo).

Quindi, se M = 8000 Ä, C = 5000 Ä e i = 4 %, la durata dell’impiego, in


anni, deve essere:
> tempo_IntComp(8000,5000,0.03);
15.90063174

Proviamo un’altra chiamata della procedura:


> tempo_IntComp(8000,0,0.03);

Error, (in tempo_IntComp) numeric exception: division by zero

Errore: cos’è successo? Rispetto alla chiamata precedente il capitale (che è il


secondo argomento attuale) è uguale a zero, ma nella procedura si divide per il
capitale C e quindi occorrerebbe controllare che C non sia nullo. Meglio
ancora sarebbe controllare che il capitale utilizzato nei calcoli sia positivo: per
C minore o uguale a zero sarebbe simpatico stampare un messaggio di errore.
Per effettuare questo controllo si puù utilizzare un’istruzione condizionale che
lavori nel seguente modo:

- se C <= 0 allora:

- stampa un messaggio di errore

- altrimenti:

- calcola il tempo di impiego del capitale

Per realizzare questo controllo utilizziamo l’istruzione


if-then-else di Maple. Si tratta in realtà di un’istruzione presente con analoga sintassi in tutti i
> tempo_IntComp := proc(M, C, i)
> if C <= 0 then

> print("il capitale dev’essere positivo")

> else

> log[1+i](M/C)
> end if

> end proc;

tempo IntComp := proc(M, C, i)



if C ≤ 0 then print(“il capitale dev’essere positivo”) else logi+1 (M C) end if
end proc
Se ora rifacciamo la chiamata con capitale nullo otteniamo:
> tempo_IntComp(8000, 0, 0.03);

“il capitale dev’essere positivo”


altrimenti:
> tempo_IntComp(8000, 1500, 0.03);

56.63207933

In generale la sintassi dell’istruzione condizionale if-then-else è la seguente:

if espressione boolean then

sequenza 1 di istruzioni MAPLE

else

sequenza 2 di istruzioni MAPLE

end if

e lavora nel seguente modo:

- valuta l’espressione boolean (un’espressione boolean è un’espressione il cui


risultato puù essere soltanto VERO

oppure FALSO; nell’esempio l’espressione boolean era: C <= 0)

- se il risultato dell’espressione boolean è VERO allora:

- esegui la sequenza 1 di istruzioni MAPLE

- altrimenti:

- esegui la sequenza 2 di istruzioni MAPLE

Si sarebbe anche potuto scrivere la procedura nel seguente modo: se C è


maggiore di zero allora calcola la durata, altrimenti stampa un messaggio; in
tal caso la procedura diventa:
> tempo2_IntComp := proc(M, C, i)
> if C > 0 then

> log[1+i](M/C)

> else

> print("il capitale dev’essere positivo")


> end

> end ;

tempo2 IntComp := proc(M, C, i)



if 0 < C then logi+1 (M C) else print(“il capitale dev’essere positivo”) end if
end proc
e lavora sostanzialmente nello stesso modo della procedura precedente
tempo IntComp; proviamo come esempio le chiamate con gli stessi argomenti:
> tempo2_IntComp(8000, 1500, 0.03);

56.63207933
> tempo2_IntComp(8000, 0, 0.03);

“il capitale dev’essere positivo”

Si osservi che nell’ultima procedura la fine dell’istruzione if-then-else è stata


segnalata da end (il primo) anzichÈ da end if e, analogamente, end proc è
stata sostituita da end (quello dell’ultima riga). In realtà infatti per Maple le
parole proc ed if (e altre che utilizzeremo tra poco) indicano a Maple l’inizio
di un particolare gruppo di istruzioni e sono come delle ”parentesi aperte”:
ciascun end è come una ”parentesi chiusa” corrispondente all’ultima
”parentesi aperta”.

In altri linguaggi di programmazione la ”parentesi aperta” è indicata


esplicitamente dalla parola begin, in altri ancora anzichÈ le parole begin - end
si utilizzano proprio una parentesi graffa aperta e una parentesi graffa chiusa.

6.2.2 6.2.2 L’istruzione if

Riprendiamo l’esempio della sezione precedente: se si desidera fare il controllo


che C sia non nullo, ma non interessa la stampa del messaggio, allora si puù
utilizzare l’istruzione if:
> tempo3_IntComp := proc(M, C, i)

> if C > 0 then

> log[1+i](M/C)

> end if
> end;

tempo3 IntComp := proc(M, C, i) if 0 < C then logi+1 (M C) end if end proc

in questo caso se C <= 0 non viene stampato alcun messaggio:


> tempo3_IntComp(8000,0,3.5);

In generale la sintassi dell’istruzione condizionale if è la seguente:

if espressione boolean then

sequenza di istruzioni MAPLE

end if
e lavora nel seguente modo:

- valuta l’espressione boolean (nell’esempio è C <> 0)

- se il risultato dell’espressione boolean è VERO allora:

- esegui la sequenza di istruzioni MAPLE

6.2.3 6.2.3 Espressioni boolean

Nell’esempio della sezione 2.2 (calcolo del tempo di impiego di un capitale C al


tasso di interesse composto i per ottenere un montante M) si è inserito un
controllo che C sia maggiore di zero:
> tempo3_IntComp := proc(M, C, i)
> if C > 0 then

> log[1+i](M/C)

> end if

> end;

tempo3 IntComp := proc(M, C, i) if 0 < C then logi+1 (M C) end if end proc

ma se esaminiamo il campo di esistenza dell’espressione log[i+1](M/C)


(supponendo il tasso di interesse i costante) ci rendiamo conto che il controllo
C > 0 non è sufficiente, occorre anche che M/C (l’argomento del logaritmo)
sia > 0 ovvero, in altri termini, il montante M dev’essere positivo, cioÈ si deve
avere:

M>0eC>0

evidentemente questa è un’espressione boolean (puù solo essere o VERA o


FALSA) quindi, per realizzare il controllo, basta inserire l’espressione in
un’istruzione if salvo sostituire la congiunzione e con la corrispondente and
dell’inglese (l’oppure si sostituisce invece con or):
> tempo4_IntComp := proc(M, C, i)

> if M > 0 and C > 0 then

> log[1+i](M/C)
> end if

> end;

tempo4 IntComp :=

proc(M, C, i) if 0 < M and 0 < C then logi+1(M C) end if end proc
Gli operatori or (somma logica) e and (prodotto logico) sono detti
operatori boolean e lavorano in modo simile agli usuali operatori aritmetici
+ e *, salvo che se scriviamo x + y, le variabili x ed y devono rappresentare
dei numeri, mentre se scriviamo x or y, le variabili x ed y devono assumere
solo i valori true (VERO) oppure false (FALSO).

La descrizione completa degli operatori or e and è data dalle loro tabelle di


verità in cui sono forniti i risultati per tutti i possibili valori degli operandi.

L’opertore or dà come risultato FALSO solo se entrambi gli operandi sono
falsi, quindi la sua tabella di verità è:

x y x or y

false false false

false true true

true false true

true true true

invece l’opertore and dà come risultato VERO solo se entrambi gli operandi
sono veri e la sua tabella di verità è:

x y x and y

false false false

false true false

true false false

true true true

un altro operatore boolean è il not (negazione logica), la cui tabella di


verità è:

x not x

false true

true false

Gli operatori boolean or, and e not insieme con i valori false e true
costituiscono un’algebra (analoga a quella usuale sui numeri reali) detta
algebra di Boole.
Nell’algebra di Boole si possiamo valutare espressioni in cui si utilizzano solo
gli operatori boolean e le variabili possono assumere solo i valori true e false;
espressioni di questo tipo sono dette espressioni boolean. Un esempio di
espressione boolean è:

x or y and (x or y and not x)

Naturalmente per valutare un’espressione boolean dobbiamo sapere in quale


ordine si devono valutare gli operatori; ad esempio per valutare l’espressione

x or y and not x

qual’operatore da valutare per primo ? E’ l’or, l’and o il not ? L’ordine di


valutazione (o più precisamente la priorità degli operatori bobolean) è:
not, and, or (cosı̀ come nell’algebra sui numeri reali la priorità è: elevamento
a potenza, prodotto, somma).

6.3 6.3 Istruzioni iterative


6.3.1 6.3.1 L’istruzione while

Nella risoluzione di un problema puù accadere che un gruppo di istruzioni


debba essere ripetuto finchÈ continua a verificarsi una determinata condizione.
Consideriamo ad esempio il seguente problema: si investe un capitale C in
un’operazione finanziaria al tasso di interesse annuo i (capitalizzazione
composta) e si desiderano calcolare tutti i montanti dopo 1 anno, dopo 2 anni,
eccetera, finchÈ il montante non abbia raggiunto un certo valore Mfin.
Desideriamo cioè calcolare e stampare gli importi dei montanti:

C*(1+i)ˆ1, C*(1+i)ˆ2, C*(1+i)ˆ3, . . .C*(1+i)ˆn

continuando finchÈ continua a valere la condizione C*(1+i)ˆn < Mfin .

I dati del problema sono in questo caso:

• dati in ingresso: C (capitale iniziale), i (tasso di interesse annuo) e Mfin


(importo finale del montante)

• dati in uscita: i montanti dopo 1 anno, 2 anni, 3 anni, ... finchÈ C*(1+i)ˆn
< Mfin
Per effettuare la stampa dobbiamo perciù riutilizzare sempre la stessa formula
ma per valori diversi del numero di anni, che indicheremo con n; i passi da
eseguire sono perciù:

- inizializza n (numero di anni) ad 1


- finchÈ C*(1+i)ˆn < Mfin esegui:
- stampa C*(1+i)ˆn
- aumenta n di 1

Si tratta ora di tradurre questi passi in istruzioni MAPLE tenendo conto che:

• inizializzare n ad 1 significa assegnare ad n il valore 1;

• il comando ”finchÈ ... esegui” si traduce con l’istruzione ”while ... do”
di Maple; anche con questa istruzione sarà necessario indicare la fine delle
istruzioni da ripetere con end do (oppure anche semplicemente con end);

• per aumentare n di 1 si utilizza l’operazione di assegnazione ”n := n + 1”


il cui effetto è quello di assegnare alla variabile n un nuovo valore uguale
a quello che aveva prima aumentato di 1.

Ecco dunque la procedura che esegue quanto richiesto:

> montanti_IntComp := proc(C, i, Mfin) local n;


> n:=1;
> while C*(1+i)^n < Mfin do
> print(C*(1+i)^n);
> n:= n + 1;
> end do
> end;

montanti IntComp := proc(C, i, Mfin)


local n;
n := 1 ; while C ∗ (i + 1)n < Mfin do print(C ∗ (i + 1)n ) ; n := n + 1 end do
end proc
Si osservi che la variabile n è dichiarata locale per evitare la solita fastidiosa
segnalazione di Warning descritta in sez. 6.1.3.

Vediamo ad esempio quali sono i montanti anno dopo anno che consentono ad
un capitale C = 1000 Ä di raddoppiare al tasso annuo del 4 %:
> montanti_IntComp(1000, 0.04, 2000);

1040.00
1081.6000
1124.864000
1169.858560
1216.652902
1265.319018
1315.931779
1368.569050
1423.311812
1480.244285
1539.454056
1601.032219
1665.073507
1731.676448
1800.943506
1872.981246
1947.900496
18

L’ultimo numero stampato è il valore di n al termine della procedura (infatti


l’istruzione che aumenta n è l’ultima della procedura) e rappresenta il numero
di anni necessari per raggiungere Mfin = 2000 Ä. Si osservi che le istruzioni
all’interno del while sono state ripetute 17 volte, ciù si esprime dicendo che ci
sono state 17 iterazioni del ciclo while.

In generale l’istruzione while ha la seguente sintassi:

while espressione boolean do

sequenza di istruzioni MAPLE

end do

e impone a Maple le seguenti operazioni:


- valuta l’espressione boolean (nell’esempio è ”C*(1+i)ˆn < Mfin”)

- se il risultato dell’espressione boolean è VERO allora:

- esegui la sequenza di istruzioni MAPLE (detta ”corpo” dell’istruzione while)

- ripeti dall’inizio (valuta ..eccetera)

- altrimenti termina

Attenzione! Puù accadere, per errore, di scrivere come condizione per


l’esecuzione del corpo dell’istruzione while una espressione boolean sempre
vera: questo avviene ad esempio, se nella condizione dell’istruzione while della
procedura montanti IntComp si sostituisce

C*(1+i)ˆn < Mfin con - C*(1+i)ˆn < Mfin

In tal caso ripetendo la chiamata

montanti IntComp(1000, 0.04, 2000);

l’espressione boolean dell’istruzione while è sempre vera e il corpo


dell’istruzione viene continuamente ripetuto (per arrestare l’elaborazione
cliccare sul pulsante con l’indicazione di STOP). In questi casi si dice che si ha
un ciclo infinito o loop infinito.

6.3.2 6.3.2 L’istruzione for

Spesso quando alcune istruzioni devono essere ripetute più volte si conosce
preventivamente il numero esatto di ripetizioni richieste. In questi casi
conviene utilizzare l’istruzione for anzichè la while.

Partiamo anche in questo caso da un problema: supponiamo di voler calcolare


il fattoriale del numero n (ci dimentichiamo per un attimo che in Maple il
fattoriale di un numero n si calcola semplicemente scrivendo n!).

Costruiamo anche qui una procedura che contenga la nuova istruzione.

Abbiamo in questo caso:

• dato in ingresso: n
• dato in uscita: il fattoriale di n

Una procedura che calcola il fattoriale di un numero è:

> fattoriale := proc(n) local m, fatt;


> fatt:=1;
> if n>0 then
> for m from 1 to n do
> fatt := fatt*m;
> end do;
> end if;
> return(fatt)
> end;

fattoriale := proc(n)
local m, fatt;
fatt := 1 ; if 0 < n then for m to n do fatt := m ∗ fatt end do end if ; return fatt
end proc

Che possiamo richiamare per calcolare il fattoriale di 6:

> fattoriale(6);
720

La sintassi dell’istruzione for (nella sua forma più semplice) è:

for variabile indice from valore iniziale to valore finale do

sequenza di istruzioni MAPLE

end do

e lavora nel seguente modo:

- variabile indice := valore iniziale

- finchÈ variabile indice <= valore finale esegui:

- esegui la sequenza di istruzioni MAPLE

- variabile indice := variabile indice + 1


Un esempio più elaborato di utilizzo dell’istruzione for

Supponiamo di voler calcolare l’integrale definito:

noti gli estremi di integrazione a e b. Non esiste in questo caso alcun modo di
scrivere una primitiva della funzione integranda utilizzando composizioni di
funzioni elementari, possiamo perù calcolare un valore approssimato
dell’integrale applicando la definizione: approssimiamo cioè l’area
rappresentata dall’integrale con l’area di un plurirettangolo.

I dati del problema sono perciù:

• dati in ingresso: a e b (estremi dell’intervallo di integrazione) e m (numero


delle parti uguali in cui si intende suddividere l’intervallo di integrazione)

• dato in uscita: valore dell’integrale

Di seguito sono descritti i passi da eseguire per ottenere una soluzione del
problema:

- inizializzare a zero una variabile (area) in cui memorizzare la somma delle


aree dei rettangoli che costituiscono il

plurirettangolo

- inizializzare una variabile (delta) con il valore (b - a)/m (è la lunghezza di


ciascuna delle m parti in cui viene suddiviso l’intervallo [a,b])

- inizializzare con a (estremo sin. dell’intervallo di integrazione) una variabile


(x) che rappresenti il generico punto

x = a + n * delta al variare di n = 1, 2, , ..., m

- per n = 1, 2, , ..., m esegui:

- calcola il nuovo valore di x aggiungendo delta al valore attuale di x


- calcola il nuovo valore di area aggiungendo l’area del rettangolo di base
delta ed altezza exp(xˆ2), al valore

attuale di area

- restituisci il valore di area (area del plurirettangolo) calcolato

che tradotto in istruzioni MAPLE diventa:


> integrale := proc(a,b,m) local n, area, x, delta;

> area := 0;

> delta := (b - a) / m;

> x := a;
> for n from 1 to m do

> x := x + delta;

> area := area + delta*exp(x^2);

> od;
> return(evalf(area))

> end;

integrale := proc(a, b, m)
local n, area, x, δ;
area := 0 ;

δ := (b − a) m ;
x := a ;
for n to m do x := δ + x ; area := area + δ ∗ exp(x2 ) end do ;
return evalf(area)
end proc
Osservazioni:

• il comando evalf (espressione) restituisce il valore di un’espressione (reale)

• al solito le variabili che non sono argomenti formali della procedura (n,
area, x e delta) sono dichiarate come variabili locali per evitare la seg-
nalazione di Warning

• l’istruzione for incrementa automaticamente la variabile n


Proviamo a fare qualche chiamata: integrando nell’intervallo [1,3] con m =
1000:
> integrale(1,3,1000);

1451.199053

... con m = 2000:


> integrale(1,3,2000);

1447.136700

... e con m = 3000:


> integrale(1,3,3000);

1445.784397

si osservi che il valore approssimato dell’integrale diminuisce, infatti


l’approsimazione è fatta per eccesso dato che il valore x è l’estremo destro dei
sotto-intervalli e che la funzione integranda è strettamente crescente. Per
ottenere un’approsimazione per difetto basta far variare n da 0 ad m - 1.

Naturalmente a Maple di calcolare l’integrale utilizzando il comando int di


Maple:
> evalf(int(exp(x^2),x=1..3));

1443.082472

You might also like