Calcolatore (2) - Programmazione

(clicca per una versione in cui si considerano i primi linguaggi di programmazione)

#1  Alle calcolatrici non programmabili possiamo far eseguire solo singole operazioni di:
•  addizione, moltiplicazione, … e calcolo di altre funzioni per cui hanno programmi incorporati
•  immagazzinamento o estrazione di dati dalle memorie-utente.

    A un calcolatore (o computer o macchina calcolatrice programmabile) [ calcolatore 1] possiamo far gestire l'esecuzione di tutto un algoritmo: esso infatti accetta come informazioni provenienti dall'esterno:
•  non solo dati e specifici comandi,
•  ma anche programmi che gli indicano l'ordine con cui dovrà utilizzare i programmi incorporati per elaborare i dati che gli verranno forniti dall'esterno.

#2  Che cosa deve essere in grado di fare un computer per eseguire un programma fornito dall'utente, cioè per tradurlo in una sequenza di operazioni-macchina?

    Consideriamo ad esempio il calcolo della ripartizione percentuale di una serie di dati. Usando una CT possiamo procedere in questo modo:

 (1)batto 100            (#)
 (2)batto
 (3)batto  totale
 (4)batto faccio calcolare il fattore di proporzionalità per cui moltiplicare i dati
 (5)batto lo faccio mettere nella memoria
 (6)batto  dato
 (7)batto
 (8)batto
 (9)batto faccio calcolare la percentuale di dato rispetto a totale
(10)  ritorno a (6)   vado a introdurre un nuovo dato

    Come si vede, è l'utente che deve gestire l'esecuzione dell'algoritmo (#), cioè comandare alla CT man mano quale operazione compiere.
    I calcolatori sono invece in grado di "leggere" e tradurre automaticamente in una sequenza di operazioni-macchina (calcoli, memorizzazioni, …) un programma che illustri l'intero procedimento, cioè una descrizione dell'algoritmo (#) fatta in un opportuno linguaggio "comprensibile" dal calcolatore.
    Molti computer tascabili (o pocket computer) e tutti i calcolatori di maggiori dimensioni sono in grado di eseguire il seguente programma (##) scritto in linguaggio Basic:

 10 INPUT Tl'utente deve battere totale
 20K = 100/T                                        (##)
 30INPUT Dl'utente deve battere dato
 40PRINT D*K
 50GOTO 30

    È facile comprendere il significato di questo programma, che ha la forma di una sequenza di istruzioni numerate. PRINT in inglese significa "stampa"; GOTO deriva dall'inglese "go to", che significa "vai a". La parola INPUT, che abbiamo già usato [ funzione 1], indica qualcosa che entra in una macchina (energia, informazioni, …); in questo caso INPUT viene usato per dire al calcolatore di attendere che l'utente batta un numero. A destra è illustrato un esempio d'impiego del programma:  il "?" è un prompt attraverso il quale l'utente viene sollecitato a battere un input; battuto il totale (1500) e un dato (200) viene calcolata la prima percentuale, battuto un altro dato (300) viene calcolata la seconda percentuale, e così via.

  ? 1500
  ? 200
   13.33333
  ? 300
   20
  ? 100
   6.666667
  ?

#3  Per poter eseguire un programma come (##) un pocket computer deve essere in grado di memorizzare il testo del programma, cioè, nel caso di (##), la seguente sequenza di caratteri, dove con"ø" e con "" abbiamo indicato lo spazio bianco (pressione della barra spaziatrice) e l'"a capo", caratteri normalmente invisibili:

10øINPUTøT20øK=100/T30øINPUTøD40øPRINTøD*K50øGOTOø30

    Come le usuali CT memorizzano i numeri sotto forma di sequenze di bit, così un pocket computer memorizza sotto forma di una sequenza di bit anche il testo del programma, utilizzando uno specifico codice.
    Deve, inoltre, essere in grado (quando l'utente gli comanda, con un opportuno tasto, di eseguire il programma) di leggere (la sequenza di bit con cui ha codificato) il programma e decidere, man mano, quale operazione eseguire: una memorizzazione, un richiamo dalla memoria, un calcolo o una visualizzazione (operazioni che nelle CT non programmabili vengono comandate direttamente da tastiera), o un trasferimento dell'esecuzione a un altro punto del programma.
    Per fare tutto ciò, il pocket computer deve avere:
•  un "programma incorporato" per codificare il "programma battuto dall'utente",
•  un dispositivo di memorizzazione in cui registrare il programma codificato,
•  almeno 26 memorie-utente (memoria A, memoria B, …, memoria Z) da associare alle diverse lettere dell'alfabeto e
•  un ulteriore "programma incorporato" per tradurre il programma codificato nell'azionamento dei vari dispositivi di calcolo, memorizzazione, ….

#4  Esistono versioni più sofisticate del linguaggio Basic e molti altri linguaggi di programmazione in cui, tra l'altro, si possono usare come variabili non solo lettere ma nomi composti da più caratteri e in cui non è necessario scrivere in testa a ogni riga di programma un numero che indichi l'ordine in cui va eseguita. Poiché richiedono dei programmi di traduzione più complicati, oltre a una maggiore capacità di memorizzazione (possono impiegare un numero molto più alto di variabili), esse vengono impiegate solo su personal computer o su calcolatori di dimensioni maggiori.
    Noi useremo due linguaggi particolari, d'uso gratuito e diffusi su tutti i tipi di computer.
    Se clicchi qui si apre una finestra in cui è incorporato un programma scritto in Javascript. Gli input e gli output sono inseriti in diverse finestrelle invece che elencati uno sotto l'altro.
    Se invece clicchi qui trovi come scaricare R, una delle applicazioni matematiche più usate, e che avremo modo di impiegare parecchie volte. Vediamo, ora, uno dei modi in cui eseguire con essa il calcolo descritto sopra.  Basta che copi le righe seguenti e, aperto R, ve le incolli: 
tot <- 1500; perc <- 100/tot
d <- 150; d*perc 
Ottieni: 
[1] 10 
Poi con il tasto "freccia su" richiami l'ultima riga, con i tasti "freccia a destra" e "freccia a sinistra" ti posizioni a destra di "150", con il tasto "backspace" cancelli "150" e batti "250", e poi batti "a_capo"; ottieni; 
d <- 250; d*perc 
[1] 16.66667 .

    Un computer (personal computer o di dimensioni maggiori), a differenza del pocket computer di cui abbiamo parlato prima, non ha un unico programma traduttore "incorporato", ma è in grado di tradurre in operazioni-macchina un programma scritto in un qualunque linguaggio di programmazione, a patto che gli venga fornito in "input" anche un opportuno programma traduttore.
    La CPU di un computer può eseguire direttamente solo un programma che le arrivi sotto forma di una sequenza di bit che, a gruppi, rappresentino direttamente le operazioni-macchina da effettuare. Il linguaggio (che ha come alfabeto i simboli 0 e 1) in cui vengono scritti questi programmi viene detto linguaggio macchina.
    I linguaggi di programmazione come i Basic o come il più sofisticato R non descrivono direttamente singole operazioni-macchina, ma, come abbiamo visto, • impartiscono comandi più comlessi (a cui corrispondono più comandi del linguaggio-macchina), • usano come caratteri quasi tutti i simboli della tastiera e • indicano i comandi con nomi che ne richiamano il significato; per questo vengono detti linguaggi evoluti (o di alto livello). Per usare un linguaggio evoluto in genere non si dota il computer solo di un programma traduttore ma di un programma in linguaggio macchina più articolato, che funge da vero e proprio ambiente di programmazione, cioè un programma che contiene come sottoprogrammi: 
  un programma redattore (editor) per registrare sotto forma di byte i caratteri battuti dall'utente, ad esempio registrare col nome "percent.bas" il testo del programma (###); in genere è presente anche un help, che richiama uso e significato dei comandi, propone esempi, … .
   Un editor è una applicazione per leggere/elaborare testi (come NotePad/BloccoNote in Windows e SimpleText in Mac) che registra i documenti codificando i vari caratteri (lettere, cifre, virgole, spazi bianchi, e altri simboli) attraverso byte, ossia sequenze di 8 bit (i caratteri codificabili in questo modo sono 256; infatti le diverse sequenze di 8 cifre che riesco a costruire con 0 e 1 sono 2·2·2·2·2·2·2·2 = 28 = 256).
    Il codice impiegato è chiamato ASCII (pronuncia: aski). Ad esempio "P" è codificato con 01010000 (che interpretato come numero in base 2 corrisponde in base dieci a 16+64 = 80), l'"a capo" con 00001101 (che in base dieci diventa 1+4+8 = 13); si dice che 01010000, o più frequentemente che 80, è il codice ASCII di "P". [codice simile all'ASCII, usatissimo, è l'UTF-8; in R la codifica/decodifica è visionabile coi comandi "utf8ToInt" e "intToUtf8"; ad esempio utf8ToInt("P"); intToUtf8(80); intToUtf8(13) danno come uscite 80, "P" e "\r".  Clicca QUI per una tabella che descrive il codice ascii]
 
  un programma traduttore per tradurre la sequenza di bit costruita dall'editor, cioè il programma in linguaggio evoluto, in una sequenza di bit che sia la versione in linguaggio macchina del programma. Nel caso dei Basic abbiamo una finestra di lista per la descrizione del programma e una finestra di output per le uscite; nel caso di R tutto avviene in un'unica finestra.

#5  In un ambiente di programmazione la traduzione in linguaggio macchina può essere avviata operando con il mouse su un menu a cascata o premendo una opportuna combinazione di tasti.  Nel caso di R per la traduzione ed esecuzione basta un "a capo".
    In altri casi si tratta di un comando (Compile o Make EXE o …) che ordina la traduzione del programma in linguaggio macchina e la sua registrazione sul disco fisso o su un altro supporto di memorizzazione. La versione in linguaggio macchina può essere avviata successivamente, anche al di fuori dell'ambiente di programmazione. Questo tipo di traduzione, che comporta la creazione e registrazione di un programma autonomo (un file eseguibile), viene detta compilazione.  I programmi "originali", in linguaggio evoluto, vengono detti programmi sorgenti.

#6  Nello stendere un programma in un linguaggio evoluto dobbiamo tener presenti delle regole di scrittura che garantiscano che il testo battuto sia effettivamente traducibile in linguaggio macchina. L'insieme di queste regole di scrittura viene detto sintassi.
    Anche nella lingua naturale esistono delle regole sintattiche. Ad esempio uno dei modi in cui si può comporre una frase in italiano è: articolo+nome+verbo dove articolo, nome e verbo devono essere raccordati in numero (sing./plu.) e, eventualmente, in genere (m/f), e rispettare altre eventuali condizioni (es.: davanti ai nomi maschili singolari se iniziano con z, x, gn, pn, ps, s seguita da consonante o i seguita da vocale si può mettere uno non un; negli altri casi si può mettere un, non uno).   Ma si tratta di regole che spesso presentano eccezioni e su cui spesso esistono opinioni contrastanti (ad es.qualcuno sostiene che davanti a pn - pneumatico, pneumotorace, … - occorre, o si può, usare un). In realtà non si tratta di "regole" ma di modelli che usiamo per orientarci nella produzione/interpretazione dei messaggi verbali.
    Poi, anche se ci esprimiamo in modo un po' sgrammaticato, in genere ci capiamo allo stesso (di fronte al cartello «attendi - lo cane morzica» non abbiamo difficoltà a interpretarlo come «Attenti: il cane morsica»).
    Nel caso dei linguaggi di programmazione le regole sintattiche sono invece definite senza ambiguità ed eccezioni (per questo si parla di linguaggi formali) e devono essere rispettate rigorosamente: se il linguaggio di programmazione contiene l'istruzione print che comanda la stampa di ciò che viene scritto dopo di essa e si è scritto prlnt (una "l" al posto della "i") il programma traduttore non può meccanicamente individuare l'operazione che l'utente voleva indicare.
    L'help indica le regole sintattiche da rispettare per costruire i programmi. Ecco nel caso di R una parte dell'help relativa alle assegnazioni, come l'istruzione perc <- 100/tot (in Basic le assegnazioni avevano la forma K = 100/T).

Assignment Operators
Description
    Assign a value to a name.
Usage
    x <- value
    value -> x
    x = value
Arguments
    x       a variable name
    value   a value to be assigned to x.

    Mentre "usage" e "arguments" illustrano la sintassi, "description" spiega in breve la semantica delle assegnazioni, cioè come esse vengono tradotte in linguaggio macchina (ossia il loro "significato; nel caso del linguaggio comune la semantica si riferisce al significato di parole e frasi, qui a quello di istruzioni e programmi). Una spiegazione più dettagliata nel caso delle assegnazioni di valori numerici è presente alla voce struttura di un termine: vengono associati dei registri di memorizzazione alle variabili che compaiono nella assegnazione e poi vengono man mano calcolati i valori intermedi utilizzando eventualmente altri registri di lavoro, fino al calcolo del risultato finale e la sua memorizzazione nel registro associato alla variabile a cui punta la freccia.
[nella descrizione precedente "x" e "value" fungono da variabili sintattiche, cioè sono nomi che indicano generiche espressioni del linguaggio]

    Anche tra gli "errori" esiste una distinzione tra quelli sintattici e quelli semantici. Facciamo due semplici esempi, riferendoci al linguaggio R, ma è facile trasferirli a qualsiasi altro linguaggio.

f = function(x) x/(sqrt(4)-2)
f(0)
#NaN (Not a Number)

if(0 > 1) "a" else "b"
#"b"

    La prima riga a sinistra è scritta rispettando le regole sintattiche del linguaggio; infatti appena premo "invio" non compare alcun messaggio che segnali la presenza di errori "sintattici": il programma riesce a leggere e ad interpretare l'istruzione. Ma nella seconda riga, in cui comando di calcolare il valore di f per un certo dato (0 o un numero qualunque), viene segnalato un errori "semantico" (un "errore in corso di esecuzione"): il programma nell'eseguire le azioni comandate si trova di fronte al calcolo di un termine indefinito.
    Nel caso a destra non vi sono né errori sintattici né errori semantici: il computer dà come uscita "b" senza visualizzare alcun messaggio. La condizione 0>1 è scritta correttamente (non presenta errori sintattici) e il computer riesce a darle un significato, cioè a determinare che è una condizione "falsa" (non presenta errori semantici)

    Vi sono anche le assegnazioni stringa:  una stringa è una sequenza di caratteri,  un termine stringa è   una costante stringa  (ossia una sequenza di caratteri racchiusa tra virgolette),  una variabile a cui sia stato assegnato un termine stringa  oppure  una espressione costruita a partire da costanti e variabili stringa mediante concatenazioni (l'operazione di concatenazione in Basic è indicata con "+", in R col comando "paste").
    Esempio: in R  x <- paste("2","3",sep="")  assegna ad x il valore "23",  y <- paste("pippo",x,sep="")  assegna a y il valore "pippo23".

#7  In R (come abbiamo visto negli esempi riportati) più istruzioni possono stare sulla stessa riga se separate da ";". Un'istruzione può essere spezzata su più righe; più istruzioni possono essere accorpate se racchiuse da una coppia di parentesi graffe. Le istruzioni di "input" sono realizzabili mediante il comando "scan".

Esercizi:    testo  e  soluzione,     testo   e   soluzione

    Per altri esempi (in R e in JS) ed altro software rinviamo al link programmi apribili accessibile da .

#7  I primi calcolatori programmabili (di enormi dimensioni) risalgono agli anni immediatamente successivi alla II guerra mondiale.  Comunque l'idea di computer fu messa a fuoco da Alan Turing, nel 1936, 15 anni prima delle realizzazione pratica dei primi modelli di computer:  egli formalizzò il concetto generale di algoritmo e mise a punto il primo linguaggio di programmazione. Vedi qui per approfondimenti.

    I primi personal computer [ calcolatore 1] fanno la comparsa dopo il 1975, ma un computer di piccole dimensioni fu messo a punto dalla Olivetti già nel 1964 (il P101).  A fianco è raffigurato un modello di HP85 (1979), il primo personal computer di piccole dimensioni (con incorporata una stampante, un lettore/registratore di dati e programmi su cassette magnetiche) ad avere una grossa diffusione in tutto il mondo.
    Qualche anno dopo (1984) si sviluppano (prima in ambito Mac e, da un certo punto in poi, soprattutto, in ambito Windows) personal computer che utilizzano il mouse.
    Successivamente (in Italia a partire dal 1986) si diffonde l'uso di Internet e, poi, la possibilità di impiegare software via rete, in modo interattivo.
 
    Dopo si sviluppano gli schermi sensibili al tatto, i cellulari diventano, per vari aspetti, dei piccoli personal computer, …
    Si sono diffusi negli ultimi anni anche i tablet, delle specie di piccoli personal computer senza "tastiera fisica" (hanno lo schermo sensibile al tatto). Sono comodi per leggere testi e scriverne (almeno per chi non ha problemi di dislessia), fare foto o filmati, ascolare brani musicali, …, ma non per fare cose più significative.  Per dirla con Dan Gookin,  "se nella vita digitale vi sentite solo di passaggio, allora potete cavarvela con uno smartphone o un tablet e non aver mai bisogno di un PC;  se però avete bisogno di creare qualcosa, allora vi serve un computer" (da PCs For Dummies).

 altri collegamenti     [nuova pagina]     Considerazioni Didattiche