Capitolo 5

Primi problemi in Pascal.

indice


Problema 1:dato un numero intero calcolare a+1 e 2(a+1)
Problema 2: dati tre numeri a, b, c calcolare a+(b+c) (a+b)+c (a+c)+b
Problema 3: determinare l'area del quadrato
Problema 4: date le misure dei lati indicare il tipo di triangolo
Problema 5: dati tre numeri determinare la somma dei quadrati dei due più piccoli
Problema 6: dati n numeri contare i positivi ed i negativi
Problema 7: dati n numeri contare i pari ed i dispari
Problema 8: date n lettere maiuscole contare le vocali e le consonanti
Problema 9: calcolare l'età media degli alunni di una classe
Problema 10: dire se un numero n è primo
Problema 11: dati n numeri stampare il massimo
Problema 12: calcolare il fattoriale di un numero
Problema 13: calcolare la radice di un numero
Problema 14: calcolare la radice di un numero reale usando il metodo di Newton
Problema 15: risolvere una equazione di secondo grado
Problema 16: determinare in quanti modi diversi si può cambiare una banconota da 1000
Problema 17: determinare il vincitore di una gara di slalom



Problema 1: dato un numero intero a calcolare a+1 e 2*(a+1).

L'obiettivo, i risultati e i dati sono chiaramente espressi nel testo, così come la legge che lega i risultati ai dati: dato a, calcolare a+1 e 2*(a+1). Formalizzando avremo:

RISULTATI: a+1, 2*(a+1)

DATI: a

ALGORITMO

BEGIN

leggi a
primo_calcolo:=a+1;
secondo_calcolo:=2*(a+1);
scrivi primo_calcolo, secondo_calcolo

END.

Il programma completo sarà:

PROGRAM esempio1( INPUT, OUTPUT );

VAR

a,
primo_calcolo, secondo_calcolo : INTEGER;
 

{ programma principale }

BEGIN

WRITE( ' Inserisci valore in ingresso = ' );
READLN( a );
primo_calcolo := a + 1;
secondo_calcolo := 2 * primo_calcolo;
WRITELN( ' valore in ingresso = ', a );
WRITELN( ' valore in ingresso + 1 = ',primo_calcolo );
WRITELN( ' 2 * (valore in ingresso + 1) = ', secondo_calcolo );

END.

Se la rappresentazione degli INTEGER è a 16 bit risultati non corretti si presentano inserendo come valore in ingresso numeri in valore assoluto maggiori di 16382.

Se il numero è maggiore di 32767 il programma genera un errore immediato.
Di particolare interesse è il caso in cui il valore in ingresso è 32767:
 

a=32767; a+1= -32768; 2*(a+1)=0.

Se la rappresentazione degli INTEGER è a 32 bit risultati non corretti si presentano inserendo in ingresso valori maggiori di 1073741823.

Se il numero è maggiore di 2147483647 il programma genera un errore immediato.

Di particolare interesse è il caso in cui il valore in ingresso è 2147483647:

a=2147483647, a+1= -2147483648 e 2 * (a+1)= 0.

Problema 2: dati tre numeri a,b,c calcolare a+(b+c), (a+b)+c, (a+c)+b

Anche in questo caso risultati, dati e legge sono chiaramente espressi nel testo. Avremo allora:

RISULTATI: (a+b)+c , a+(b+c) , (a+c)+b

DATI a, b, c numeri real

ALGORITMO

BEGIN

leggi a, b, c
calcola: a+(b+c); (a+b)+c; (a+c)+b;
scrivi risultato;

END.

Il programma sarà:

PROGRAM esempio2( INPUT, OUTPUT );

VAR

a, b, c : REAL;

BEGIN { programma principale }
 

READLN( a, b, c );
WRITELN( '(a+b)+c = ', (a+b)+c );
WRITELN( 'a+(b+c) = ', a+(b+c) );
WRITELN( '(a+c)+b = ', (a+c)+b );

END.

Provando il programma con le seguenti terne di valori

1e30 -1e30 1e5 ; 1e20 1e5 -1e20; 1e30 1e10 -1e30;

si otterranno differenze di risultato notevoli.

Problema 3: determinare l'area del quadrato.

L'obiettivo è espresso chiaramente dal testo del problema: calcolare l'area di un quadrato. Per questo è necessario conoscere la misura del lato. Il risultato sarà la misura dell'area.

La legge che lega dati e risultati è conosciuta: area = lato * lato. Riassumendo:

RISULTATI: misura dell'area.

DATI: la misura del lato.

LIMITI: la misura del lato deve essere un numero positivo.

ALGORITMO:

BEGIN

1. leggi la misura del lato
2. calcolo dell'area: area=lato*lato
3. scrivi la misura dell'area 

END.

Le variabili utilizzate sono:

VAR
 

lato:REAL; { misura del lato: deve essere positiva}
area:REAL; { misura dell'area }
 

Nei dati si precisa che la misura del lato deve essere positiva. Poiché sarà cura dell'operatore fornire questo dato, è buona norma verificarne la correttezza.

Soluzione 1.

L'algoritmo potrebbe essere così modificato:

BEGIN

leggi lato
IF lato 0 THEN BEGIN
area:=lato*lato;
scrivi area
END
ELSE errore nei dati

END.

L'algoritmo è sufficientemente preciso: dobbiamo solo chiarire cosa significa errore nei dati. Potremmo far sì che il programma fornisca all'operatore un messaggio di chiarimento per il cattivo funzionamento (non calcolerà l'area): ad esempio scrivendo 'errore nei dati'.

Il programma definitivo sarà:

PROGRAM quadrato( INPUT, OUTPUT );

VAR

lato:REAL; { misura del lato: deve essere positiva}
area:REAL; { misura dell'area }

BEGIN

1. READLN( lato );
IF lato 0 THEN BEGIN
area:=lato*lato;
WRITELN( area )
END
ELSE WRITELN( 'errore nei dati.' )

END.

Osservazione: Il programma prevede l'intervento dell'operatore che dovrà fornire il dato iniziale: ma come farà l'operatore a capire quando inserire il dato? Deve essere il programma a segnalarlo, ad esempio modificando la linea 1 così:

1 WRITE( 'Inserisci la misura del lato ' );
READLN( lato );

 

Soluzione 2.

L'algoritmo proposto risolve il problema iniziale. Però se l'operatore che interagisce con l'esecutore sbaglia ad inserire i dati, ad esempio digitando un numero negativo, non ha la possibilità di correggersi. Si potrebbe pensare di modificare l'algoritmo in modo che se il dato è errato venga nuovamente richiesto.

BEGIN

WRITE('Inserisci la misura del lato ' );
READLN( lato );
1 WHILE lato <= 0 DO BEGIN
WRITELN ('Misura errata.');
WRITE('Inserisci la misura del lato ' );
READLN( lato )
END;
area:=lato*lato;
WRITELN( area )

END.

Il controllo 1 fa si che l'esecutore continui a richiedere la misura del lato sino a quando non verrà inserito un numero positivo. Solo a questo punto si proseguirà con il calcolo dell'area.

Esercizi 1.

1.1. Modificare il controllo 1 nella soluzione 2 del problema 3 utilizzando un ciclo REPEAT.

1.2. Calcolare l'area del rettangolo.

1.3. Determinare l'area della circonferenza inscritta e di quella circoscritta ad un quadrato.

1.4. Determinare l'area del triangolo equilatero inscritto e di quello circoscritto ad una circonferenza.

1.5. Utilizzando la funzione succ() e il confronto risolvere i seguenti problemi:

a- Somma di due numeri interi positivi.

b- Sottrazione tra due numeri interi positivi.

c- Prodotto tra due numeri interi positivi.

Problema 4: date le misure dei tre lati indicare il tipo di triangolo.

L'obiettivo del problema è chiaro: è necessario classificare dei triangoli in base alle misure dei lati. Dalla geometria euclidea sappiamo che un triangolo con tre lati uguali viene detto equilatero, con soli due eguali isoscele, altrimenti è scaleno.

RISULTATI: messaggio che indichi il tipo di triangolo.

DATI: le misure dei tre lati.

LIMITI: le misure dovranno essere numeri positivi. Ma dalla geometria sappiamo che non tutte le terne di numeri positivi possono essere le misure di lati di triangoli. In particolare deve valere la seguente condizione:

Siano a, b, c tre numeri. Se a+bc e b+ca e a+cb allora a, b, c possono essere le misure dei lati di un triangolo.

Le variabili utilizzate sono:

VAR

a, b, c:REAL; { misure dei lati }

ALGORITMO.

BEGIN

1 leggi a, b, c
IF ((a=b) AND (b=c)) THEN
WRITELN( 'triangolo equilatero.' )
ELSE IF ((a=b) OR (a=c) OR (b=c)) THEN
WRITELN( 'triangolo isoscele.' )
ELSE WRITELN( 'triangolo scaleno.' )

END.

Restano da definire i controlli sui dati in input. La linea 1. può essere modificata così:

REPEAT

WRITE( 'a = ' );
READLN( a );

UNTIL (a0);

REPEAT

WRITE( 'b = ' );
READLN( b );

UNTIL (b0);

REPEAT

WRITE( 'c = ' );
READLN( c );

UNTIL (c0);

Ma tutto questo non basta. E' necessario controllare anche che siano misure di lati di triangoli. Si possono racchiudere i tre cicli precedenti in un nuovo ciclo:

REPEAT

REPEAT

....

....

UNTIL ...

...

...

UNTIL ((a+b)c) AND ((a+c)b) AND ((b+c)a)

Esercizi 2.

2.1. Modificare l'algoritmo precedente inserendo opportune istruzione di segnalazione in caso di errore.

2.2 Dire se tre numeri a,b,c possono essere i lati di un triangolo rettangolo.

2.3 Leggere n numeri crescenti.

2.4 Dati 3 numeri visualizzarli ordinati.

2.5 Calcolare il massimo tra 3 numeri.

Problema 5: Dati 3 numeri visualizzare la somma dei quadrati dei due più piccoli.

L'obiettivo, i dati e il risultato del problema sono espressi chiaramente nel testo.

RISULTATI: somma dei quadrati dei due numeri più piccoli

DATI: a, b, c tre numeri

ALGORITMO:

Soluzione 1

Ricordando gli esercizi precedenti una prima soluzione potrebbe essere la seguente:

BEGIN

leggi a, b, c
IF (a=b) AND (a=c) THEN WRITELN( 'La somma è ', c*c + b*b );
IF (ba) AND (b=c) THEN WRITELN( 'La somma è ', a*a + c*c );
IF (ca) AND (cb) THEN WRITELN( 'La somma è ', a*a + b*b );

END.

Per verificare la correttezza di questo algoritmo è necessario controllare che siano contemplati tutti i casi possibili. Estendere questo algoritmo ad una quantità n di valori è complesso.

Soluzione 2

Una soluzione diversa è far sì che a sia il numero più grande. Si può procedere così:

BEGIN

leggi a, b, c
IF a<b THEN scambia a con b;
IF a<c THEN scambia a con c;
WRITELN( 'La somma è ', b*b + c*c );

END.

In questo caso l'algoritmo è facilmente estendibile ad un numero n qualunque di valori.

Problema 6: dati n numeri interi contare quanti sono positivi e quanti negativi.

L'obiettivo da raggiungere risulta anche in questo caso chiaro. I risultati saranno il numero dei positivi e il numero dei negativi. Bisogna però fare alcune considerazioni per quanto riguarda i dati. Nel testo non è indicato il valore di n. E' chiaro comunque che i numeri da inserire saranno in generale più di 1. Se è possibile per l'operatore sapere prima quanti saranno i numeri su cui dovrà operare l'esecutore potremmo risolvere il problema così:

Soluzione 1.

RISULTATI:
 

c_pos = contatore numeri positivi
c_neg = contatore numeri negativi
 

DATI:

x = valore da analizzare
n = quantità valori da analizzare

VAR

i, { conta la quantità di numeri inseriti }
n, { quantità di numeri da anallizzare }
c_pos,c_neg:INTEGER; { contatori dei positivi e dei negativi }
x :REAL; { valore da analizzare }

ALGORITMO.

BEGIN

c_pos:=0; c_neg:=0;
1. leggi n
FOR i:=1 TO n DO BEGIN
READLN( x );
IF (x = 0) THEN c_pos:=c_pos+1
ELSE c_neg:=c_neg+1
END;
WRITELN( 'Positivi = ', c_pos );
WRITELN( 'Negativi = ', c_neg )

END.

La definizione di 1 è lasciata al lettore.

Soluzione 2.

Se l'operatore non conosce a priori il numero degli elementi da elaborare è necessario modificare l'algoritmo precedente. Ad esempio:

BEGIN

c_neg:=0; c_pos:=0;
REPEAT
READLN( x );
IF (x = 0) THEN c_pos:=c_pos+1
ELSE c_neg:=c_neg+1;
WRITE( 'Altri valori? ' );
READLN( continua );
UNTIL continua='N';
WRITELN( 'Positivi = ', c_pos );
WRITELN( 'Negativi = ', c_neg )

END.

dove continua è una variabile di tipo CHAR.

Problema 7: dati n numeri positivi contare i pari e i dispari.

A prima vista il testo sembra analogo al precedente. Si deve contare quanti tra n numeri positivi sono pari e quanti dispari. Ma potremmo modificare l'ingresso dei dati in questo modo:

VAR

c_pari, c_dispari, { contatori per i pari e i dispari }
x :INTEGER; { contenitore per i numeri }

ALGORITMO

BEGIN

c_pari:=0; c_dispari:=0;
REPEAT
1. leggi x
IF x=0 THEN
2 IF pari x THEN c_pari:=c_pari+1
ELSE c_dispari:=c_dispari+1;
UNTIL x=-1;
WRITELN('Pari = ',c_pari);
WRITELN('Dispari = ',c_dispari)

END

Con questo algoritmo uno dei valori che deve essere scartato perchè negativo viene utilizzato come segnale per fine lavoro. Per avvertire l'operatore è sufficiente sostituire 1. con:

WRITE('Inserisci il numero positivo: -1 per finire ');
READLN( x );

Ci rimane ancora da chiarire cosa significa pari x. Un numero è pari se il resto della divisione per 2 è zero. Allora la condizione nella 2. diventerà:

IF (x MOD 2) = 0 THEN

 

Problema 8: date n lettere maiuscole contare le vocali e le consonanti.

Il problema è analogo a quelli visti in precedenza: l'obiettivo è chiaramente definito così come i risultati e i dati. Abbiamo bisogno di due contatori, uno per le vocali ed uno per le consonanti. Il numero delle lettere da esaminare è conosciuto a priori. Le lettere valide per l'esame sono solo quelle maiuscole. Formalizzando:

RISULTATI:

c_voc = numero vocali
c_cons = numero consonanti
 

DATI:

n = numero lettere
x = lettera da esaminare

VAR

c_voc, c_cons, { contatori per le vocali e le consonanti }
n, { quantità di lettere da analizzare }
i:INTEGER; { contatore per le lettere già analizzate }
x:CHAR; { carattere inserito }

ALGORITMO

BEGIN

c_voc:=0; c_cons:=0;
1. leggi n
i:=0;
WHILE i<=n DO BEGIN
2. leggi x
3 IF maiuscolo x THEN BEGIN
4 IF vocale x THEN c_voc:=c_voc+1;
ELSE c_cons:=c_cons+1;
i:=i+1
END
END;
WRITELN( 'Vocali = ', c_voc );
WRITELN( 'Consonanti = ', c_cons )

END.

Nel programma precedente il dato letto non viene conteggiato se non è valido.

I punti 1. e 2. sono lasciati al lettore. Il punto 3. richiede di verificare se il carattere in x è maiuscolo. Poiché i caratteri maiuscoli sono tutti consecutivi nella tabella ascii il controllo sarà:

IF (x='A') AND (x<='Z') THEN

Lo stesso controllo non può essere utilizzato per il 4 perchè le vocali non sono consecutive nella tabella ascii. Bisognerà allora controllare tutte e cinque le possibilità:

IF (x='A') OR (x='E') OR (x='I') OR (x='U') OR (x='O') THEN

 

Esercizi 3.

3.1. Dati n caratteri contare i simboli di punteggiatura.

3.2. Date n lettere contare le maiuscole e le minuscole.

3.3. Contare i ragazzi e le ragazze di una classe

3.4. Data una sequenza di numeri contare quanti sono divisibili per 2, quanti per 3, quanti per 5.

3.5. Dire di quante cifre binarie è composta la rappresentazione di un intero positivo.

3.6. Contare quante volte la cifra 2 è presente nella rappresentazione decimale di un numero.

3.7. Dire di quante cifre di una generica base b 0 è formata la rappresentazione in base b di un numero intero positivo.

Problema 9: calcolare l'età media degli alunni di una classe.

Per raggiungere l'obiettivo, cioè calcolare l'età media è necessario conoscere la somma dell'età di ogni singolo alunno e il numero degli alunni della classe. L'età media sarà allora:

eta_media= (somma età dei singoli alunni) / numero_alunni

Per calcolare la somma dell'età è necessario utilizzare una variabile, inizializzata a 0, che dovrà essere incrementata dell'età degli alunni, man mano che si legge. Il risultato del problema sarà l'età media. Per i dati potrebbero essere fatte scelte diverse. E` chiaro che è necessario conoscere le singole età ma per questo si potrebbe avere la data di nascita oppure conoscere direttamente l'età. E` evidente che l'algoritmo sarà diverso in base alle scelte che faremo. Supponiamo che il nostro input sia un numero indicante l'età espressa in anni.

RISULTATI: media

DATI: n_alunni, eta

VAR

accumulatore, { accumulatore per la somma delle età }
n_alunni, { numero degli alunni da esaminare }
eta, { età di ogni singolo alunno }
i:INTEGER; { contatore degli alunni già esaminati }
media :REAL; { media delle età }

ALGORITMO

BEGIN

accumulatore:=0
leggi n_alunni
FOR i:=1 TO n_alunni BEGIN
leggi eta
accumulatore:=accumulatore+eta
END;
media:=accumulatore/n_alunni;
WRITE( 'La media è: ', media )

END.

Lasciamo l'ulteriore sviluppo dell'algoritmo al lettore ricordando che sia l'età, sia il numero degli alunni devono essere numeri interi positivi.

Esercizi 4.

4.1. Calcolare l'età media dei ragazzi e delle ragazze di una classe.

4.2. Determinare l'età della ragazza e del ragazzo più giovane di una classe.

4.3. Indicare la data di nascita del ragazzo più vecchio di una classe.

4.4. Trovare le medie dei numeri pari e dei numeri dispari in una sequenza di n numeri.

 

Problema 10: dire se un numero n è primo.

Un numero naturale n è primo se e solo se è divisibile solo per se stesso e per 1. Un metodo per verificare se n è primo consiste allora nel provare a dividerlo per tutti i numeri compresi tra 2 e n-1 alla ricerca di un divisore. Se non esiste allora n è primo.

RISULTATI: messaggio 'primo' 'non primo'

DATI: n

ALGORITMO:

Soluzione 1

BEGIN

leggi n
i:=1;
REPEAT
i:=i+1
UNTIL (n MOD i)=0;
IF i=n THEN WRITELN( 'primo' )
ELSE WRITELN( 'non primo ' )

END.

Soluzione 2

Il precedente algoritmo svolge, nel caso di numeri primi, n divisioni. Ma si può osservare che non tutte sono necessarie. Ad esempio dopo aver controllato la divisibilità per 2 tutti i multipli di 2 si possono automaticamente escludere. Inoltre è sufficiente controllare i numeri sino alla radice quadrata di n poichè non possono esistere due numeri maggiori di radice di n il cui prodotto è n. Il nuovo algoritmo sarà:

PROGRAM primi( INPUT, OUTPUT );

VAR
n, i, radice :INTEGER;
primo:BOOLEAN;

BEGIN

REPEAT
WRITE( 'n = ' );
READLN( n )
UNTIL n0;
primo:=TRUE;
IF (n MOD 2) = 0 THEN primo:=FALSE;
i:=3;
radice:=trunc(sqrt(n));
WHILE (i<=radice) AND primo DO BEGIN
primo:=(n MOD i)<0;
i:=i+2
END;
IF primo THEN WRITELN( 'primo' )
ELSE WRITELN( 'non primo' )

END.

N.B. sqrt è una funzione del Pascal che calcola la radice quadrata.

Esercizi 5.

5.1. Calcolare i primi N numeri multipli di M.

5.2. Determinare il primo numero primo maggiore di N.

5.3. Scomporre in fattori primi un numero n.

5.4. Calcolare la radice intera di un numero n 0 senza usare la funzione sqrt().

5.5. Determinare il M.C.D. tra due numeri.

5.6. Determinare il m.c.m. tra due numeri.

Problema 11: dati n numeri stampare il valore massimo.

Come negli esempi precedenti l'obiettivo del problema è già indicato esplicitamente: determinare il valore massimo tra n numeri. Anche il risultato è facilmente deducibile: il numero più grande.

Per quanto riguarda i dati, detto che sono dei numeri qualsiasi, resta da definire se si sa a priori quanti sono. Supponiamo di si. Riepilogando:

RISULTATI: massimo

DATI:
n = numeri da esaminare
x = numero

VAR

i, { numero di valori già analizzati }
n :INTEGER; { numero massimo di valori da analizzare }
x, { valore da analizzare }
max:REAL; { massimo }

ALGORITMO

BEGIN

1. leggi n
FOR i:=1 TO n DO BEGIN
2 leggi x
3 IF xmax THEN max:=x
END
WRITELN('Il massimo è ', max)

END.

A prima vista sembra funzionare. E` necessario solo specificare 1. e 2. in modo analogo a quanto indicato negli esercizi precedenti. Ma se si osserva con maggior attenzione quanto scritto si può notare un errore alla 3. Infatti viene richiesto di svolgere un confronto tra quanto è contenuto in x e quanto è contenuto in max. Ma max non è ancora stato inizializzato! Si rischia di ottenere come risultato un numero che non è tra quelli da esaminare! Il metodo più semplice per ovviare al problema potrebbe essere quello di inizializzare la variabile max con un valore qualsiasi, magari 0. Ma attenzione, se i numeri da esaminare fossero solo numeri negativi il risultato del nostro algoritmo diventerebbe 0, chiaramente errato. Questo perchè noi non sappiamo nulla dei valori che dovranno essere esaminati.

Anche così quindi non va bene. Il numero con cui si deve inizializzare max deve essere o un numero piccolo, o un numero tra quelli che dovranno poi essere esaminati. Vediamo come:

BEGIN

1. leggi n
2. leggi max
FOR i:=2 TO n DO BEGIN
3. leggi x
IF xmax THEN max:=x
END;
WRITELN('Il massimo è ', max)

END.

Lo sviluppo di 1., 2., 3. è lasciata al lettore.

Esercizi 6

6.1. Trovare la media, il minimo e il massimo di n interi.

6.2. Dati n numeri interi determinare il massimo tra i numeri pari e tra i numeri dispari.

6.3. Determinare se in una sequenza di n numeri i numeri pari sono tutti minori dei numeri dispari.

Problema 12: calcolare il fattoriale di un numero intero positivo.

Il fattoriale di un numero intero positivo X, indicato con X!, è il prodotto dei numeri interi che vanno da 1 a X, cioè:
 

X! = X * (X - 1) * (X - 2) .. * 2 * 1

con la convenzione che 0! = 1

RISULTATI: fattoriale

DATI: numero

PROGRAM fatt( INPUT, OUTPUT );
VAR

numero,
fattoriale : INTEGER;
i : INTEGER;

BEGIN { programma principale }

{ legge il valore in ingresso controllando che sia positivo }
REPEAT
WRITE(' Inserisci valore in ingresso = ');
READLN(numero);
UNTIL numero = 0;
{ calcolo del fattoriale }
fattoriale:= 1;
FOR i:= 1 TO numero DO
fattoriale:= fattoriale * i;
{ stampa il risultato }
WRITELN(' il fattoriale di ',numero,' risulta ',fattoriale)

END.

Il programma è corretto ma sfortunatamente poco utile: con la rappresentazione degli INTEGER a 16 bit già 8! risulta scorretto, a 32 bit 13! .

nota

PROGRAM fatt1( INPUT, OUTPUT );
VAR

numero, i : INTEGER;
fattoriale : REAL;

{ programma principale }
BEGIN
{ identico al precedente }
END;

Questo esempio mostra come è possibile modificare il programma precedente per avere una stima di valori più grandi del fattoriale. Abbiamo però una perdita di informazione dovuta al tipo REAL. Ad esempio per 20! otteniamo 2.4329020082E+18 mentre il valore corretto è 2432902008176640000.

Anche con la modifica apportata il calcolo del fattoriale rimane limitato a numeri minori di 40 (o poco superiori).


Problema 13: calcolare i primi 10 termini della successione numerica

Xn+1= 200*Xn - (199 / 10) con X0=1/10.

Il problema ci chiede di calcolare i primi dieci termini della successione

An+1 = 200 * An - 199/10

con A0 = 1 / 10;

Si può immediatamente notare che

A1= 200 * A0 - 199/10 = 200 * (1 / 10) - 199/10 = 20 - 19.9= 0.1 = 1 /10

Questo implica che i dieci termini sono tutti uguali a 1/10.

RISULTATI: 10 numeri

DATI: non sono necessari dati in ingresso

ALGORITMO:

Per calcolare il termine n_esimo è necessario conoscere il termine n-1. Saranno necessarie allora due variabili, una per memorizzare il termine n_esimo, l'altra per contare i termini della successione calcolati. Il termine 0 sarà 1/10. Il programma sarà:

PROGRAM succ( INPUT, OUTPUT );
VAR

indice : INTEGER;
y : REAL;

{ programma principale }
BEGIN

y := 1 / 10;
FOR indice:= 1 TO 10 DO BEGIN
y := 200 * y - ( 199 / 10);
WRITELN( ' y = ', y )
END

END.

Il programma precedente se provato su un elaboratore produrrà risultati molto diversi da quelli che abbiamo previsto.

Esercizi 7.

7.1. Stampare i primi 50 termini della successione a segni alterni 1, -1.

7.2. Calcolare il termine n-esimo delle seguenti successioni:

a. Xn+1 = Xn + 1 b. Xn+1 = aXn + b

c. Xn+1 = Xn + Xn-1 d. Xn+1 = aXn + bXn-1 + c

7.3. Calcolare la somma dei primi n termini delle successioni dell'esercizio 7.2.

7.4 Calcolare la somma dei primi n elementi di indice pari e di indice dispari delle successioni dell'esercizio 7.2.

7.5. Data una sequenza di n numeri stabilire se è crescente o decrescente.

Problema 14: calcolare la radice di un numero reale usando il metodo di Newton.

Per calcolare la radice quadrata di un numero con Newton si applica la seguente formula:

Xn+1 = 1/2( Xn + a/Xn )

dove a è il numero di cui si vuole calcolare la radice. Il procedimento iterativo ha termine quando esiste un valore di n per cui Xn+1 = Xn. Poichè a livello teorico questo valore può non esistere, si approssima la soluzione cercando un n tale che |Xn+1 - Xn| < eps, dove eps è un numero piccolo. Il porre quindi eps a zero può portare ad un ciclo infinito.

RISULTATI: valore della radice

DATI: numero positivo

ALGORITMO:

PROGRAM radice ( INPUT,OUTPUT);
CONST

precisione = 1e-10; { valore di eps }

VAR

valore, x, y : REAL;

BEGIN

REPEAT
WRITE (' Inserisci il valore ');
READLN(valore)
UNTIL valore = 0;
y:= 1;
REPEAT
x:= y;
y:= ( x * x + valore) / (2 * x)
UNTIL abs (x - y) < precisione;
WRITELN (' risultato = ', y)

END.

Problema 15: risolvere una equazione di secondo grado.

Una equazione di secondo grado è determinata conoscendo i coefficienti a, b, c. Le soluzioni possono essere calcolate applicando la formula risolutiva. Nell'algoritmo che segue solo una delle soluzioni, e precisamente quella in valore assoluto maggiore, è calcolata con la formula risolutiva. La seconda si calcola ricordando che in una equazione del tipo:
 

ax^2 + bx + c =0

il rapporto c/a rappresenta il prodotto delle radici.

 

RISULTATI: x1, x2 = radici dell'equazione

DATI: a,b,c = coefficienti dell'equazione

PROGRAM equazione (INPUT,OUTPUT);
VAR

a, b, c, { coefficienti equazione }
x1,x2, { radici }
delta, radice_delta : REAL;

BEGIN

READLN (a,b,c);
IF (a < 0) THEN BEGIN
delta := (b * b - 4 * a * c);
IF delta =0 THEN BEGIN
radice_delta := sqrt(delta);
IF b < 0 THEN
x1 := (- b + radice_delta) / (2 * a)
ELSE
x1 := (- b - radice_delta) / (2 * a);
x2 := (c / a) / x1;
WRITELN('x1 = ',x1, ' x2= ',x2)
END ELSE
WRITELN('equazione non ammette radici reali ')
END ELSE
WRITELN ('equazione non di secondo grado')

END.

Il lettore è invitato a modificare l'algoritmo calcolando entrambe le radici con la formula risolutiva ed a verificare le radice ottenute da entrambi i programmi con i seguenti valori numerici:

a=1, b=1e15, c=1e10
a=1, b=1e15, c=1e5

L'algoritmo proposto nell'esempio è più preciso.

Prima di proseguire con un altro problema analizziamo con un esempio quello che è successo nel problema precedente. Alcuni errori riscontrabili nei risultati sono infatti inevitabili.

Esempio 1: Risolvere, in notazione scientifica con 5 cifre di mantissa, le seguenti equazioni di secondo grado:

1- 1111111 * X^2 - 2222200 * X + 1111111 = 0

2- 1111111 * X^2 - 2222222 * X + 1111111 = 0

3- 1111111 * X^2 - 2222298 * X + 1111111 = 0

si può immediatamente notare che:

la 1 non ammette soluzioni reali

la 2 ammette 2 radici reali coincidenti

la 3 ammette due radici reali distinte

Poiché i coefficienti delle tre equazioni, in notazione scientifica con 5 cifre di mantissa, coincidono si deve risolvere una sola equazione:

a1= (+, 0.11111, 7) * X^2 - (+, 0.22222, 7) * X + (+, 0.11111, 7) = 0

L'equazione a1 ci dice che tutte le equazioni del tipo

11111ab * X^2 - 22222cd * X + 11111ef = 0

con a, b, c, d, e, f cifre qualsiasi hanno la stessa soluzione:

X1 = X2 = 1

Questo è dovuto alla rappresentazione dei numeri real adottata. Per stabilire la precisione massima che si può ottenere con una particolare versione del Pascal si può utilizzare il seguente algoritmo:

PROGRAM macchina( INPUT, OUTPUT );
VAR

errore_relativo, errore_relativo1 : REAL;

BEGIN { programma principale }

errore_relativo := 1;
{ prima stima dell'errore relativo }
WHILE (1 + errore_relativo) 1 DO
errore_relativo := errore_relativo / 2;
{ calcolo più accurato dell'errore relativo }
WHILE (1 + errore_relativo) = 1 DO BEGIN
errore_relativo1 := errore_relativo;
errore_relativo := errore_relativo * 1.01
END;
{ stampa dei risultati }
WRITE(errore_relativo1);
WRITE(' < errore relativo < ');
WRITELN(errore_relativo)

END.

Un "calcolo esatto" è un calcolo in cui l'errore relativo risulta minore della precisione della macchina. E` importante tener presente che, per quanto piccolo possa risultare l'errore relativo iniziale, gli errori di propagazione, in un processo di calcolo mal condizionato, possono sempre portare a risultati inacettabili.

Esercizi 8.

8.1. Risolvere un'equazione di primo grado.

8.2. Risolvere un sistema lineare di due equazioni in due incognite.

8.3 Risolvere una disequazione di secondo grado.

 

Problema 16: determinare quanti modi diversi ci sono per cambiare una banconota da lire 1000 in monete da 50, 100, 200, 500.

L'obiettivo del problema è chiaro. Il risultato sarà il numero di modi diversi per cambiare la banconota da mille lire. Per quanto riguarda l'algoritmo possiamo pensare di utilizzare 4 accumulatori, uno per le banconote da 50, uno per quelle da 100, uno per quelle da 200 ed uno per quelle da 500. Si procederà quindi ad incrementare i 4 accumulatori con quattro cicli ed ogni qual volta la somma dei quattro e 1000 si incrementerà il contatore. Così:

PROGRAM scomponi (INPUT , OUTPUT);
CONST

valore= 1000;
VAR
a50, a100, a200 , a500, { accumulatori }
cont : INTEGER; { contatore }

BEGIN

cont:=0;
a500:= 0;
WHILE a500 <= valore DO BEGIN
a200:=0;
WHILE a500 + a200 <= valore DO BEGIN
a100:=0;
WHILE a500 + a200 + a100 <= valore DO BEGIN
a50:=0;
WHILE a500 + a200 + a100 + a50 <= valore DO BEGIN
{ se la somma = valore conteggia }
IF a500+a200+a100+a50=valore THEN
cont:= cont + 1;
a50:= a50 + 50 { incremento accumulatore a50 }
END;
a100:= a100 + 100{incremento accumulatore a100 }
END;
a200:= a200 + 200 { incremento accumulatore a200 }
END;
a500:= a500 + 500 { incremento accumulatore a500 }
END;
writeln(cont);

END.

 

Esercizi 9.

9.1. Determinare quali sono i modi diversi per cambiare una banconota da lire 1000 in monete da 50, 100, 200, 500.

Problema 17: si vuole un programma che permetta di indicare il vincitore e il tempo ottenuto in una gara di discesa libera.

Per prima cosa si deve individuare con precisione l'obiettivo che ci si propone. Il problema richiede di conoscere il vincitore di una gara sciistica e il tempo ottenuto: il vincitore può essere individuato in vari modi: noi supponiamo di utilizzare il numero di pettorale. Anche per i tempi vi possono essere diverse unità di misura. In prima istanza supponiamo che il tempo sia espresso in centesimi di secondo. Il vincitore sarà colui che avrà totalizzato il tempo più piccolo. Esiste ancora un problema grosso: gli ex equo. Come ci comportiamo se due persone ottengono lo stesso tempo? quale dei due sarà il vincitore? Per ora facciamo l'ipotesi molto limitativa che in caso di ex equo vinca la persona con numero di pettorale più piccolo. Agli atleti che non terminano la gare verrà assegnato un tempo di 30.000 centesimi di secondo.

I dati da inserire dovranno quindi essere tutti positivi e minori di 30.000. Si suppone che almeno un concorrente porti a termine la prova. Formalizzando:

RISULTATI: vincitore = pettorale del vincitore

t_min = tempo impiegato dal vincitore

DATI: concorrenti, numero di pettorale, tempo

LIMITI: le variabili di ingresso devono essere numeri interi positivi.

VAR

concorrenti,{ totale concorrenti partecipanti alla gara }
i, { concorrenti già scesi }
t_min, { tempo del vincitore }
vincitore, { pettorale del vincitore }
t, { tempo discesista }
p :INTEGER;{ pettorale discesista }

ALGORITMO

BEGIN

leggi concorrenti
t_min:=30000;
FOR i:=1 TO concorrenti DO BEGIN
leggi p, t
IF t<t_min THEN BEGIN
t_min:=t; vincitore:=p
END;
END;
WRITELN( 'Il vincitore è ', vincitore, ' con tempo ', t_min )

END.

In questo algoritmo abbiamo inizializzato la variabile t_min = 30000 perchè abbiamo indicato nelle ipotesi che esiste almeno una persona che porterà a termine la gara e quindi che avrà un tempo inferiore a 30000.

Esercizi 10.

10.1. Determinare l'alunno con media migliore in una classe.