Appunti di informatica by Carlo

facilePrimi elementi:
diagrammi di flusso, algoritmi, programmi ...

gif(Aggiornamento dell'articolo al 16/02/2011)

Figura 4

Fino ad ora ho scritto alcuni articoli su aspetti e temi riguardanti l’informatica ma non sono partito dal principio e forse direi anche di averlo fatto a ragion veduta cercando prima di interessarvi un po’ all’argomento.
In genere, prima di descrivere come è fatta una automobile nei suoi più intimi particolari, è sempre bene far provare un po’ l’ebbrezza della velocità, l’utilità del mezzo, come si guida ed infine elencare le possibili future evoluzioni. Allo stesso modo qui, dopo avervi descritto alcuni aspetti e, allo stesso tempo consapevole di quello che sapete già sull’uso e sulla praticità dell’elaboratore, inizierò a parlarvi del suo funzionamento e del modo con il quale noi diamo ad esso insiemi di istruzioni (i programmi) per far eseguire a lui operazioni complesse. Vi insegnerò un po’ alla volta a programmare facendo in modo che voi possiate far eseguire alla macchina istruzioni da voi progettate; vedrete che a poco alla volta vi sentirete voi i padroni del mezzo e, come dice il sottotitolo di questo sito, non vi spaventerete più di fronte ai diversi problemi che per gran parte di voi, per ora solo utilizzatori, a volte potrebbero sembrare grossi e limitativi. Insomma voglio dire cioè che se vi si incepperà “la macchina”, non tirerete più giù “le madonne”, ma opererete in modo opportuno per risolvere via, via i vari problemi.
Prima di iniziare a parlare sull’argomento, vi descriverò in modo schematico e sommario attraverso un disegno come è fatto un elaboratore. In genere dobbiamo dire che i dati vengono immessi attraverso una unità di entrata: “input” (tastiera), elaborati da una unità di elaborazione attraverso un programma che risiede in memoria poi, finita l’elaborazione, i dati vengono inviati ad una unità di uscita: “output” (monitor, stampante ecc.).
Nella realtà un vero elaboratore è molto più complesso ed è forse troppo limitativo descriverlo solo con questo disegno. Devo ricordare che accanto ad elementi di input e output vi sono anche elementi di imput/output cioè che svolgono contemporaneamente entrambe le funzioni cioè i dischi esterni ( Dvd e CD riscrivibili, pen-drive ecc. ecc.) o interni (hard disk). Come elementi di solo input dobbiamo includere il mouse e il joistik dove presente ecc. ecc. L’unità di elaborazione è rappresentata dal microprocessore, anche se unità aggiuntive sono quasi sempre presenti: coprocessori grafici e matematici ecc. ecc. Lo schema esposto nell’illustrazione dovrebbe comunque dare una indicazione precisa del funzionamento della macchina.
E’ comunque evidente dallo schema, che un computer è la prima macchina non progettata per eseguire un’unica funzione (ad esempio una tenaglia, un martello, un televisore, una automobile) ma infinite funzioni; basta caricare in memoria un programma, ad esempio word, per scrivere, o paint per disegnare, media player per sentire musica o vedere filmati, photoshop per elaborare fotografie ecc. ecc.
E’ quindi chiaro che un programma è una sequenza di istruzioni elementari, a volte anche notevolmente complessa, eseguibili dalla macchina per trasformare i dati iniziali di input in risultati finali di output. Quando noi carichiamo in memoria e facciamo eseguire un programma (ad esempio word), quest’ultimo si mette in attesa di un input (immissione di caratteri), lo elabora (ad esempio una formattazione) e lo presenta in uscita con un output (stampa a video o su carta).
Lo scopo di questi articoli, non è quello di insegnarvi ad usare word o photoshop, ma di mettervi in grado di progettare voi stessi semplici programmi da far eseguire alla macchina.
I processi (insieme in sequenza di istruzioni) sono rappresentati e descritti utilizzando un linguaggio di programmazione e l’insieme combinato di più processi costituiscono il programma. I processi la cui esecuzione richiede un tempo finito, vengono detti algoritmi.
Un algoritmo deve ubbidire a tre proprietà fondamentali:

1° ogni istruzione deve essere ben definita nei suoi effetti cioè senza ambiguità;
2° ogni istruzione rappresenta una azione elementare eseguibile in un intervallo di tempo finito;
3° il processo descritto dal programma deve terminare dopo un numero finito di passi.

Gli algoritmi qui descritti sono pensati per un particolare esecutore : l’elaboratore elettronico. Per semplicità gli algoritmi vengono descritti con i così detti schemi a blocchi o diagrammi di flusso. E’ più facile in questo modo poi trasformare tali schemi in istruzioni rappresentate e descritte da uno specifico linguaggio di programmazione.
Per non considerare la programmazione solo connessa con una macchina (elaboratore) consideriamo come primo esempio un algoritmo pensato per l’esecutore umano (figura 4). Si deve progettare un particolare algoritmo che, attraverso una descrizione a parole, descrivi il funzionamento di un distributore automatico di sigarette dal costo di euro 1,50 al pacchetto che deve essere alimentato da 8 monete da euro 0,20.
Ormai, e siamo nel 2010, non si trovano quasi più distributori di sigarette, oggigiorno è più facile trovare distributori di preservativi, ma vi assicuro che il funzionamento della macchina è lo stesso, cambia solo il prodotto. Il riferimento alle sigarette, è dovuto essenzialmente al fatto che ahimè nel lontano [19 (…)  :-)] quando studiavo io questi esempi, il riferimento era proprio questo.
Il modo per rappresentare il processo è questo:

1° inserire le 8 monete
2° tirare il cassetto corrispondente alla marca di sigarette desiderato
3° estrarre il pacchetto
4° richiudere il cassetto
5° ritirare il resto di euro 0,10.

Questa sequenza di istruzioni gode delle 3 proprietà elencate più sopra, e pertanto costituisce un algoritmo. Il diagramma di flusso corrispondente è quello della figura qui a destra rappresentata.
L’algoritmo può tuttavia essere migliorato e completato inserendo un test iniziale sul funzionamento della macchina; se quest’ultima è guasta oppure se il serbatoio contenente le sigarette della marca desiderata è vuoto è meglio rivolgersi al tabaccaio più vicino.
Le istruzioni di test vengono negli schemi a blocchi rappresentati da rombi con due uscite: “si” e “no” corrispondenti alle risposte (senza ambiguità) alle domande dei test. A noi sembrerà una limitazione questa mancanza di ambiguità, ma vi assicuro che si può ovviare a ciò aumentando in cascata il numero dei test arrivando via, via ad un risultato sempre più preciso:
 
Il blocco “inserire le monete” si può ulteriormente dettagliare con una combinazione di un blocco e di un test.
Tale insieme di istruzioni viene chiamato iterazione o loop. L’insieme delle operazioni viene ripetuto fino a quando il test viene completato e verificato.

Per quanto riguarda i loop, e per ridere un po’ sulla nostra natura, si può dire che nella vita di ciascuno di noi non si fa altro che passare da un loop ad un altro: non si può uscire da questa logica, il loop più esterno è il confine determinato dalla propria natura di uomo e dal proprio pensiero e … ad ognuno il suo loop !! Ogni ribellione è amaro in bocca e spreco di tempo, ma allegri, almeno il pensiero si può espandere !!

Passiamo ora ad un altro esempio, questa volta però pensato per un esecutore diverso (un elaboratore). Si voglia progettare un programma in grado di rappresentare un processo di moltiplicazione di due numeri interi positivi w e y e il risultato denotato con z. Si supponga che l’elaboratore possa eseguire solo somme e sottrazioni su due operandi e di fornire all’esterno valori interi. Lascio a voi il compito di seguire mentalmente il diagramma. La trasformazione del flusso in un linguaggio di programmazione potrebbe essere il seguente:

Prodotto
avvio
  leggi W
  leggi y
  Z = 0
  U = Y
prodotto Z = Z + W
  U = U - 1
  se U ≠ 0 salta a prodotto
  scrivi Z
  arresto

/*Programmino moltiplicazione scritto da Carlo Sala
26/03/2010*/
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
    double W;
    double Y;
    double Z;
    double U;
   do
{
cout << "\nInserisci un numero intero
 positivo (piu' invio) :  ";
cin >> W;
cout << "\nMoltiplicato per (piu' invio) :  ";
cin >> Y;
}
    while (W < 0 or Y < 0);
    Z = 0;
    U = Y;
    while (U > 0)
    {
        Z = Z + W;
        U = U - 1;
    }
    cout << "\nIl risultato e' :  "  << Z << endl << endl;
    system ("PAUSE");
    return EXIT_SUCCESS;
}

Naturalmente i veri linguaggi di programmazione sono differenti ma solo nei termini e nella sintassi, ma non nella logica !!
Ad esempio in C++ sarà:    (vedi anche qui ....)
Il programma così appunto si scrive e come vedete sono state aggiunte in testa e in coda alcune istruzioni per inizializzare la macchina. Vi esorto per comprendere il codice sopra evidenziato a comprare dei semplici manuali del linguaggio per imparare e approfondire l’argomento. (ai miei tempi c'erano i "Bigini". Ci sono ancora ??)
Queste semplici righe di codice verranno poi compilate da un programma apposito (il compilatore) che crea un file eseguibile dall’elaboratore. Nella sezione manuali e software di questo sito potete scaricare gratuitamente uno dei tanti compilatori C++ sul mercato. Qui invece potete scaricare l’esempio che è già stato da me compilato ed è eseguibile dopo averlo però scompattato. Il programmino non è però completo, se tenterete di inserire numeri non interi o negativi, si fermerà segnalandovi l’errore o dandovi risultati non coerenti. A breve il seguito …

Il programma  per estrema semplificazione non ha la solita interfaccia grafica tipica di windows ma quella dell'ormai datato MS-dos. Dopo aver inserito i dati premere invio per confermarli !

[ Ma non era più semplice con una macchinetta per i calcoli o usare la calcolatrice di windows ...? Forse sì ma dove stava la poesia ..... Avreste potuto poi dire: "L'ho fatto io !" ? No, no !!
(Beh ..), ma per ora l'ha fatto il Carlo   ]

Ma si andrà sempre più sul difficile ...!!

gif(Aggiunta del 05/03/2024)
Ottima playlist su YouTube del professore Fabrizio Camuso riguardante le strutture dati.

png