Alcuni
programmi di esempio
Utilizzando
i costrutti introdotti fino ad ora, proviamo a realizzare
un programma che calcoli la somma dei primi 100 numeri
interi:
public
class SommaNumeri {
public static void main(String argv[]) {
int i =0;
int somma = 0;
while(i <= 100) {
somma = somma +
i;
i = i + 1;
}
System.out.print("La somma
dei primi 100 numeri e' ");
System.out.println(somma);
}
}
In
questo esempio vengono utilizzate due variabili: 'i'
e 'somma'. La prima variabile viene inizializzata a
zero, e viene incrementata di un'unità ad ogni
iterazione del ciclo. La seconda variabile, anch'essa
inizializzata a zero, serve ad accumulare il valore
cercato: dopo il primo ciclo essa vale 1, dopo il secondo
3, dopo il terzo 6 e così via. Il ciclo termina
non appena i supera il valore 100.
Si
vuole ora modificare il programma in modo che calcoli,
oltre alla somma dei primi 100 interi, la somma dei
primi 50 numeri pari. Un modo per distinguere i numeri
pari da quelli dispari è quello di considerare
il resto della divisione per due: se è uguale
a 0, il numero è pari, in caso contrario è
dispari.
public
class SommaNumeriPari {
public
static void main(String argv[]) {
int i =0;
int somma = 0;
int sommaPari = 0;
int resto = 0;
while(i <= 100) {
somma = somma +
i;
resto = i % 2;
if(resto == 0) {
sommaPari
= sommaPari + i;
}
i
= i + 1;
}
System.out.print("La somma
dei primi 100 numeri e' ");
System.out.println(somma);
System.out.print("La somma
dei primi 100 numeri pari e' ");
System.out.println(sommaPari);
}
}
Ad
ogni ciclo viene calcolato il resto della divisione
per due del numero i; se è uguale a zero, il
valore di 'i' viene sommato a quello della variabile
'sommaPari':
if(resto
== 0) {
sommaPari
= sommaPari + i;
}
Si
vuole ora mettere in atto un'ulteriore modifica al programma
di esempio, per fare in modo che calcoli, oltre alla
somma dei primi 100 interi e dei primi 50 numeri pari,
la somma dei primi 50 numeri dispari. Ovviamente dobbiamo
inserire una nuova variabile, 'sommaDispari', per accumulare
il risultato; quindi dobbiamo aggiungere la clausola
'else' all'istruzione 'if' introdotta precedentemente:
if(resto
== 0) {
sommaPari
= sommaPari + i;
}
else {
sommaDispari
= sommaDispari + i;
}
Le
due istruzioni verranno eseguite alternativamente: nei
cicli pari viene eseguita la prima, nei cicli dispari
la seconda. Ecco il codice completo dell'esempio:
public
class SommaNumeriPariEDispari {
public static void main(String argv[]) {
int i =0;
int somma = 0;
int sommaPari = 0;
int sommaDispari = 0;
int resto = 0;
while(i <= 100) {
somma = somma +
i;
resto = i % 2;
if(resto == 0) {
sommaPari
= sommaPari + i;
}
else {
sommaDispari
= sommaDispari + i;
}
i = i + 1;
}
System.out.print("La somma
dei primi 100 numeri e' ");
System.out.println(somma);
System.out.print("La somma
dei primi 100 numeri pari e' ");
System.out.println(sommaPari);
System.out.print("La somma
dei primi 100 numeri dispari e' ");
System.out.println(sommaDispari);
}
}
Cicli
while nidificati
All'interno
di un ciclo while possiamo inserire qualunque istruzione,
compreso un altro ciclo while: in questo caso il ciclo
più interno verrà rieseguito per intero
ad ogni passo del ciclo più esterno. Il programma
seguente calcola la tabellina del 10, e la stampa sullo
schermo:
public
class Tabelline {
public static void main(String argv[]) {
int i = 0;
int j = 0;
while(i <= 10) {
while(j <= 10)
{
int
prodotto = i*j;
System.out.print(prodotto);
System.out.print("\t");
j =
j + 1;
}
System.out.println();
i = i + 1;
j = 0;
}
}
}
Il
ciclo più esterno ha il compito di stampare le
righe: ad ogni passo, esso avvia un altro ciclo in modo
da stampare un valore per ogni colonna. Tra un valore
e l'altro viene stampato un carattere di tabulazione,
in modo da ottenere una formattazione precisa dei dati.
L'uso
dei cicli nidificati è una tecnica di programmazione
importantissima, che presenta delle ovvie difficoltà
a chi si avvicina alla programmazione per la prima volta.
Il tema verrà ripreso e sviluppato nei prossimi
capitoli: per il momento è sufficiente aver chiara
la possibilità di comporre qualunque tipo di
combinazione di istruzioni, ricorrendo addirittura a
strutture nidificate.
Quanti
programmi posso scrivere con le nozioni appena apprese?
I
costrutti descritti fino ad ora sono solo una piccola
parte di quelli offerti dal linguaggio Java, tuttavia
essi permettono di realizzare un gran numero di programmi.
Dopo aver preso confidenza con gli esempi, si può
tentare di realizzare qualcosa di diverso: con un po'
di fantasia è possibile individuare migliaia
di possibilità. Ci si può domandare quali
siano i limiti di questo mini linguaggio, così
semplice e primitivo. Quanti programmi è possibile
scrivere? Che tipo di applicazioni si possono realizzare?
La risposta, per certi versi sconcertante, è
che questo piccolo linguaggio permette di realizzare
qualunque programma si desideri, compreso Word, Excel,
un compilatore Java o il vostro sistema operativo preferito.
Nel
1966 due matematici italiani, Corrado Bohm e Giuseppe
Jacopini, dimostrarono formalmente che qualunque programma
per calcolatore poteva essere riscritto usando un linguaggio
dotato solamente di variabili intere, assegnamento,
ciclo while e costrutto condizionale, un linguaggio
del tutto equivalente a quello appena descritto. Il
teorema di Bohm Jacopini fu un argomento decisivo nel
dibattito sull'abolizione del salto incondizionato "goto",
un costrutto presente nei linguaggi di allora che rendeva
il codice estremamente difficile da capire.
Un
interpretazione superficiale del teorema di Bhom Jacopini
sembrerebbe suggerire l'inutilità di ulteriori
costrutti nei linguaggi di programmazione. Tale affermazione
equivarrebbe ad asserire l'inutilità dell'automobile,
dal momento che è possibile raggiungere qualunque
destinazione a piedi. Per quanto questo linguaggio sia
tecnicamente sufficiente per realizzare programmi anche
molto complessi, è chiaro che oltre un certo
livello, l'impresa andrebbe al di la delle capacità
umane.
L'importanza
di questo asserto risiede nel fatto che esso definisce
in modo chiaro e rigoroso un insieme di nozioni che
costituiscono, a tutti gli effetti, la base di qualunque
linguaggio di programmazione. Nei prossimi capitoli
affronteremo lo studio di costrutti più avanzati:
tipi di dati numerici, vettori, stringhe, metodi, classi
ed oggetti. Ogni nuovo strumento permetterà di
realizzare programmi più brevi e più comprensibili
di quelli che si possono scrivere con il semplice linguaggio
descritto in questo capitolo. La possibilità
di creare strumenti nuovi attraverso un uso sapiente
di quelli esistenti è senza dubbio uno degli
aspetti più affascinanti della scienza del calcolo:
questo processo induttivo è la chiave principale
del rapido sviluppo dell'informatica.
Esercizi
- Margherita
Elettronica
Ogni
margherita ha un numero di petali che varia casualmente
tra 30 e 50. E' risaputo che la presenza o l'assenza
di un petalo può avere delle grosse conseguenze
sulle nostre aspirazioni sentimentali.
Creare
un programma MargheritaElettronica, con una variabile
"numeroPetali" calcolata con la seguente
formula:
int
numeroCasuale = (int)(21 * Math.random());
int numeroPetali = 30 + numeroCasuale;
Il
programma, mentre conta ad uno ad uno i petali, stampa
alternativamente le scritte "m'ama" e "non
m'ama".
Importante:
prima di eseguire il programma, pensare intensamente
alla persona amata.
- Shining
A
voler essere precisi, le scritte che compaiono sui
fogli nel film Shining sono state realizzate seguendo
pattern compositivi differenti dal semplice incolonnamento.
Si chiede di costruire, utilizzando in modo corretto
i cicli while, un programma che stampi su schermo
una sequenza di frasi con il seguente schema:
Il
mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Il mattino ha l'oro in bocca
Suggerimento: ricorrere a due cicli while. Ad ogni
passo del ciclo più esterno si esegua un ciclo
while di questo tipo.
numeroSpazi
= 0;
while(numeroSpazi < maxSpazi) {
System.out.print(" ");
numeroSpazi++;
}
Ad
ogni iterazione, il ciclo più esterno incrementa
la variabile 'maxSpazi': se il suo valore è
maggiore di 10, la riporta a zero.
-
Shining
2
Dopo
aver rivisto il film Shining, costruire programmi
che riproducano alcuni dei pattern presenti nel
film.
-
Sistema Operativo
Riprodurre
il sistema operativo preferito, utilizzando solo i
costrutti presenti in questo capitolo.
Invito
all'approfondimento
Rapidità,
precisione e capacità di eseguire in modo instancabile
operazioni ripetitive sono qualità importantissime
per un calcolatore. Se presenti in un essere umano,
tali caratteristiche tendono a conferire una connotazione
maniacale. Il cinema ricorre spesso a questa associazione,
come nel già citato Shinig o in Rain Man, dove
un Dustin Hoffmann da Oscar fornisce una straordinaria
rappresentazione delle eccezionali capacità di
calcolo di alcuni soggetti autistici, abbinata ad una
desolante incapacità di relazione sociale.
Curiosamente
il mondo del cinema tende a rappresentare con tinte
fosche anche lo scenario inverso: per divenire davvero
pericolosa, una macchina deve prima assumere qualità
umane. La voce suadente di HAL 9000, protagonista indiscusso
del colossale 2001 Odissea nello spazio, non serve soltanto
a comunicare rotte astrali e guasti agli impianti, ma
anche a mentire, per mettere in pratica un diabolico
piano congegnato grazie alla sofisticata euristica che
lo accomuna ad un essere senziente. Matrix e la saga
di Terminator sono due esempi più recenti di
film realizzati non solo per sbancare al botteghino,
ma anche per indurre a riflettere sul desiderio di creare
macchine dotate di una quale forma di intelligenza.
Dove
si situa, ai giorni nostri, il confine reale tra intelligenza
umana ed intelligenza artificiale? Un computer capace
di fornire una diagnosi attraverso l'analisi dei sintomi
di un paziente può essere definita "esperto",
grazie alla sua capacità di confrontare in pochi
attimi il caso in esame con milioni di altri simili,
memorizzati all'interno di un archivio elettronico.
Ma un simile "sistema esperto" non sarà
mai in grado di cogliere le sottili sfumature nella
voce di un paziente o di percepire le sue emozioni:
la capacità di cogliere questi parametri, così
difficili da quantificare e da classificare, è
la qualità umana che può distinguere un
buon medico da un medico straordinario.
Ma
se mai un giorno qualcuno dovesse riuscire a dotare
una macchina di coscienza e volontà, speriamo
solo si ricordi di plasmare la sua creazione secondo
le tre leggi della robotica di Asimov, la prima delle
quali recita "Un robot non può arrecare
danno agli esseri umani, nè permettere che degli
esseri umani ricevano danno a causa del suo mancato
intervento"
Conclusioni
Questo
mese abbiamo consolidato le nozioni apprese il mese
scorso. Attraverso l'analisi di esempi di complessità
crescente, abbiamo cominciato a farci un'idea di come
ragiona una macchina. Il mese prossimo approfondiremo
il tema dei tipi di dati primitivi, ed introdurremo
i vettori, o array, uno dei più importanti strumenti
per la gestione della memoria.
Esempi
allegati
Gli esempi completi qui descritti posson essere scaricati
tramite il seguente link
|