In questo articolo è descritta la traduzione inglese, opera di Ada Lovelace nel 1843, di un lavoro pubblicato l'anno precedente dal matematico, ingegnere e all'epoca ufficiale del genio militare Luigi Menabrea. L'articolo di Menabrea e le note che Ada Lovelace aggiunse alla traduzione contengono alcuni tra i primi programmi per calcolatore pubblicati.
I due protagonisti.
Luigi
Federico Menabrea (1809-1896) studiò ingegneria e
matematica all'università di Torino; divenne quindi
ufficiale del genio militare.
Fu uno dei pochi studiosi che
apprezzarono l'opera di Charles Babbage, alla quale
dedicò un articolo pubblicato nel 1842 in lingua
francese nella rivista Bibliothèque Universelle
de Genève, contenente alcuni semplici esempi di
programmi per calcolatore, forse i primi in assoluto ad
essere pubblicati in una rivista scientifica. Nel 1843
l'articolo fu tradotto in inglese, con il titolo A
Sketch of the Analytical Engine Invented by Charles
Babbage, da Augusta Ada Lovelace, figlia del celebre
poeta Lord Byron, e pubblicato nel volume 3 della rivista
Scientific Memoirs edita da Richard e John Taylor.
Nel 1848 Menabrea partecipò alla prima guerra di
indipendenza come ufficiale del genio; nel 1859, durante
la seconda guerra di indipendenza, aveva il comando del
genio militare. Successivamente Menabrea intraprese con
successo la carriera politica: fu ministro della marina e
ministro dei lavori pubblici (1861-1864); nel 1866 fu
nominato plenipotenziario per la firma del trattato di
Praga che portò all'annessione di Venezia
all'Italia; tra il 1867 e il 1869 fu primo ministro
(durante il suo governo Giuseppe Garibaldi fu arrestato in
seguito al fallito tentativo di liberazione di Roma,
terminato con la sconfitta dei garibaldini a Mentana). In
seguito fu ambasciatore a Londra e a Parigi. Nel 1870
pubblicò, in collaborazione con J. L. F. Bertrand,
un importante contributo alla teoria della meccanica,
concernente il principio del lavoro minimo;
in questo articolo è presentata
quella che è ritenuta la prima dimostrazione
corretta di tale principio.
Augusta Ada Lovelace (1815-1852), figlia di Lord Byron, nacque
pochi mesi prima della separazione dei genitori. Fu affidata
alla madre, che predilesse per lei l'istruzione
matematico-scientifica al posto della più tradizionale
istruzione letteraria. Nel 1834 Ada incontrò Charles
Babbage. Nel 1835 sposò William King. Alcuni anni dopo
William divenne conte di Lovelace e Ada assunse il titolo di
contessa di Lovelace. Nel 1840 Ada iniziò un'attiva
collaborazione con Babbage. Nel 1841 Babbage tenne a Torino un
seminario avente per argomento l'Analytical Engine. L'anno
seguente Luigi Menabrea scrisse l'articolo descrivente il
progetto di Babbage che fu pubblicato nel 1842 nella rivista
Bibliothèque Universelle de Genève. Ada ne
curò la successiva traduzione in inglese. Nella sua
autobiografia Babbage descrive così ciò che
accadde.
Poco tempo dopo la comparsa della memoria [di Menabrea] nella "Bibliothèque Universelle de Genève", la Contessa di Lovelace mi informò che aveva tradotto la memoria di Menabrea. Le chiesi perché non aveva ella stessa scritto un lavoro originale su un soggetto del quale aveva una così intima conoscenza? A questa domanda Lady Lovelace rispose che tale idea non le era venuta in mente. Io allora suggerii che avrebbe potuto aggiungere alcune note alla memoria di Menabrea; un'idea che fu immediatamente adottata.
Discutemmo insieme i vari esempi che potevano essere introdotti: ne suggerii diversi, ma la scelta fu interamente sua. Suo fu anche il lavoro algebrico sui differenti problemi, eccettuato quello relativo ai numeri di Bernoulli, che mi ero offerto di fare per evitare a Lady Lovelace questa fatica. Tale lavoro mi fu rimandato indietro da lei per correzioni, poiché si era accorta di un grave errore che avevo commesso.
Le note della Contessa di Lovelace assommano a circa tre volte la lunghezza dell'articolo originario. L'autore è pienamente entrato in quasi tutti i più difficili e astratti problemi connessi con il soggetto.
Queste due memorie [quella di Menabrea e le note di Ada] prese insieme fornisco, a coloro che sono capaci di comprenderne il ragionamento, una dimostrazione completa che lo sviluppo e le operazioni dell'analisi posso adesso essere eseguiti dalla macchina. [Traduzione mia dall'originale inglese pubblicato in http://www-history.mcs.st-andrews.ac.uk/history/Mathematicians/Lovelace.html].
L'articolo di
Menabrea.
Menabrea descrive all'inizio
dell'articolo il primo calcolatore progettato da Babbage e
chiamato Difference Engine. In maniera sintetica ed
efficace, Menabrea ne descrive il principio di
funzionamento, le possibilità di applicazione
pratica e le limitazioni intrinseche. Passando alla
spiegazione dell'Analytical Engine, nato secondo
Menabrea per superare le limitazioni del Difference
Engine, Menabrea individua subito le sue caratteristiche
fondamentali:
A questo punto Menabrea descrive le possibilità offerte dall'Analytical Engine. Per comprendere i successivi esempi di programmi offerti da Menabrea e da Ada Lovelace è necessario seguire la breve spiegazione che Menabrea fornisce dei principi di funzionamento di questo calcolatore. Ecco come Menabrea descrivere il metodo utilizzato nel calcolatore per rappresentare i numeri.
Immaginiamo una pila o una colonna verticale consistente di un numero indefinito di dischi circolari, tutti attraversati nei loro centri da un asse comune, attorno al quale ciascuno di essi può eseguire un movimento rotatorio indipendente. Se lungo il bordo di questi dischi sono scritte le dieci cifre che costituiscono il nostro alfabeto numerico, noi possiamo, disponendo opportunamente una serie di queste cifre nella stessa colonna, esprimere un qualsiasi numero. E' sufficiente a questo scopo che il primo disco rappresenti le unità, il secondo le decine, il terzo le centinaia, e così via. In genere, se abbiamo una serie di colonne di dischi, designate come V0, V1, V2, V3, V4, ecc., noi possiamo chiedere, per esempio, di dividere il numero scritto nella colonna V1 per quello nella colonna V4, e di ottenere il risultato nella colonna V7. [Questa citazione, come tutte le seguenti, è tratta da L. F. Menabrea, A Sketch of the Analytical Engine Invented by Charles Babbage, traduzione inglese e note di Ada Lovelace, reperibile in http://www.fourmilab.ch/babbage/sketch.html (traduzione italiana mia)].
Menabrea fa subito notare che per eseguire l'operazione di divisione appena descritta è necessario impartire due distinti ordini alla macchina:
attraverso il primo essa è predisposta per eseguire una divisione, e attraverso il secondo sono indicate le colonne sulle quali operare, e anche la colonna sulla quale rappresentare il risultato.
Ne consegue che
le disposizioni che devono essere comunicate alle varie parti della macchina possono essere distinte in due classi principali:
Primo, quella relativa alle Operazioni.
Secondo, quella relativa alle Variabili.
Le Operazioni indicano alla macchina quale delle quattro operazioni aritmetiche deve essere eseguita; le Variabili indicano quale sono le due colonne contenenti i numeri sui quali operare e in quale colonna deve essere posto il risultato. L'Analytical Engine dispone, continua Menabrea nella sua spiegazione, di uno speciale apparato chiamato fabbrica (mill), nel quale sono effettivamente eseguite le operazioni aritmetiche.
Per quel che riguarda le operazioni stesse, esse sono eseguite da uno speciale apparato, che è designato con il nome di fabbrica, e che contiene esso stesso un certo numero di colonne, simili a quelle delle variabili. Quando due numeri devono essere combinati insieme, la macchina [...] trasferisce i numeri nella fabbrica. Quindi, essendo stato l'apparato disposto in maniera opportuna per l'operazione richiesta, quest'ultima è eseguita e, quando completata, il risultato stesso è trasferito nella colonna delle Variabili che è stata indicata. Quindi la fabbrica è la porzione della macchina che lavora, e le colonne delle Variabili costituiscono il luogo dove i risultati sono rappresentati e immagazzinati.
La macchina, prosegue Menabrea, può
assumere le necessarie disposizioni

per eseguire una serie di passi senza
l'intervento dell'uomo utilizzando schede perforate, nella
stessa maniera in cui le schede perforate sono usate nel
telaio ideato da Jacquard. Nei tessuti si distinguono due
tipi di fili: la trama e l'ordito. Attraverso l'opportuno
intrecciarsi di questi fili è possibile realizzare
disegni sui tessuti. Questo lavoro era eseguito a mano
prima dell'invenzione del telaio meccanico di Jacquard,
nel quale i fili sono collegati a leve il cui movimento
è regolato attraverso l'uso di schede perforate: le
leve che si trovano in corrispondenza con la parte solida
della scheda sono obbligate a muoversi con la scheda
stessa, mentre quelle che si trovano in corrispondenza con
una delle perforazioni sono indipendenti dall'eventuale
movimento della scheda. L'intreccio dei fili è
quindi comandato dalle schede perforate; ad ogni azione
del telaio una nuova scheda occupa il posto della
precedente e comanda un diverso intreccio dei fili. Il
risultato è la creazione di figure anche complesse
sul tessuto. Menabrea ricorda che per alcuni disegni sono
necessarie non meno di ventimila schede. In maniera
analoga l'Analytical Engine può utilizzare le
schede perforate. La macchina dispone di due tipi
principali di schede:
in primo luogo, le schede delle Operazioni [Operation cards], per mezzo delle quali le parti della macchina sono disposte in modo da eseguire una determinata serie di operazioni, come addizioni, sottrazioni, moltiplicazioni e divisioni; secondariamente, le schede delle Variabili [cards of Variables], che indicano alla macchina le colonne nelle quali il risultato deve essere rappresentato.
In sintesi, le schede delle Operazioni
indicano quali sono le operazioni che la macchina deve
eseguire; le schede delle Variabili individuano le colonne
sulle quali agire (ogni operazione richiede due colonne di dati
sorgenti) e la colonna nella quale inserire il risultato.
Un terzo tipo di schede sarà successivamente indicato
come necessario da Menabrea: le schede dei numeri (cards of
numbers) che contengono le principali costanti matematiche
Questi sono determinati numeri, come quelli che esprimono il rapporto tra la circonferenza e il diametro, i Numeri di Bernoulli, ecc., che frequentemente si presentano nei calcoli. Per evitare la necessità di calcolarli ogni volta che devono essere utilizzati, certe schede possono essere combinate in maniera tale da fornire questi numeri pronti per l'uso [...].
Dopo aver spiegato i principi di funzionamento della macchina, Menabrea è pronto per illustrarli tramite un primo esempio: un programma che calcola la soluzione, rispetto alla variabile x, del sistema di due equazioni lineari
Tale soluzione è
Ecco come Menabrea descrive il programma per calcolare la soluzione indicata.
Continuiamo con il rappresentare mediante V0, V1, V2, ecc., le differenti colonne che contengono i numeri, e supponiamo che le prime otto colonne siano state scelte per esprimere i numeri rappresentati da m, n, d, m', n', d', n e n', il che implica che V0=m, V1=n, V2=d, V3=m', V4=n', V5=d', V6=n, V7=n'.
La serie delle operazioni comandate dalle schede, e i risultati ottenuti, possono essere rappresentati nella tabella seguente:
Cerchiamo di capire il significato della tabella presentata a Menabrea. Number of operations indica il numero successivo dei passi di esecuzione del programma. Operation-cards contiene le schede delle Operazioni, quelle che indicano quali sono le operazioni che la macchina eseguirà. Cards of the variables contiene le schede delle Variabili che individuano le varie colonne sulle quali la macchina agirà. Cards of variables è divisa in Columns on which operations are to performed, che riporta le colonne sorgenti, Column which receive results of operations, che riporta la colonna destinazione. Infine Progress of the operations riporta lo stato delle colonne contenenti i dati. In termini moderni la tabella nel suo complesso è la traccia passo-passo dell'esecuzione del programma. Da questa tabella è immediato risalire alle schede necessarie per scrivere effettivamente il programma. In prima approssimazione è richiesto un numero di schede pari al doppio dei passi; ogni passo individua infatti una scheda Operazioni e una scheda delle Variabili. In realtà il numero delle schede Operazioni può essere ridotto, come sottolinea Menabrea:
se richiesto, possiamo utilizzare solo tre schede operazioni; per realizzare ciò, è sufficiente introdurre nella macchina un apparato che consenta, per esempio, dopo la prima moltiplicazione, di trattenere la scheda relativa a questa operazione, e non le permetta di avanzare per essere rimpiazzata da un'altra, fino a quando questa operazione sia stata eseguita quattro volte.
Troviamo qui una prima descrizione della
nozione di ciclo di un programma, cioè la
possibilità di eseguire più volte una scheda o
una serie di schede; questo concetto sarà ripreso in
seguito sia da Menabrea sia da Ada Lovelace.
Subito dopo Menabrea presenta un secondo esempio di programma,
consistente in una piccola variazione del primo programma, nel
quale è calcolata anche la soluzione del precedente
sistema di equazioni lineari rispetto alla variabile y.
Non riporto la tabella di questo programma, poiché non
aggiunge molto al programma iniziale. Nel commento a questo
programma Menabrea nota che le colonne delle Variabili possono
essere considerate un deposito (store) di numeri. Segue
un ulteriore esempio, particolarmente semplice, avente lo scopo
di mostrare che
La macchina non è soltanto capace di eseguire quei calcoli numerici che dipendono da una formula algebrica nota, ma è anche adatta per quei calcoli analitici [relativi cioè all'analisi matematica] nei quali devono essere considerate una o più variabili.
Anche in questo caso Menabrea presenta un programma di esempio, che ometto di descrivere perché estremamente semplice e privo di sostanziali novità. Risulta invece interessante la conclusione che ne trae Menabrea.
Possiamo dedurre la seguente importante conseguenza di questi esempi, e cioè che, poiché le schede indicano solo la natura delle operazioni che devono essere eseguite, e le colonne delle Variabili i dati sui quali eseguirle, queste schede posseggono loro stesse tutta la generalità dell'analisi, della quale esse sono in realtà una mera traduzione.
Immediatamente dopo questa affermazione,
Menabrea spiega sinteticamente ma correttamente due concetti
fondamentali della programmazione: la possibilità di
eseguire due porzioni diverse di programma al verificarsi di un
certo evento, e la possibilità di eseguire un ciclo di
operazioni fino al verificarsi di una certa condizione. Si
tratta di un punto molto importante. Nei tre programmi fino a
questo punto presentati da Menabrea, tutte le istruzioni sono
eseguite in successione, nell'ordine nel quale compaiono.
Adesso Menabrea introduce altre due tecniche di programmazione:
il test di una condizione per decidere quale porzione di schede
eseguire, e il ciclo delle operazioni.
Relativamente al primo punto, Menabrea ne accenna in occasione
dello studio delle funzioni che presentano punti di
singolarità.
Ci sono certe funzioni che necessariamente cambiano di natura quando passano attraverso lo zero o l'infinito, o i cui valori non sono accettabili quando passano questi limiti. Quando questi casi si presentano, la macchina è capace, per mezzo di un campanello, di avvertire dell'avvenuto passaggio attraverso zero o infinito, e di fermarsi fino a quando l'operatore [attendant] la attiva nuovamente per qualsiasi processo sia desiderato che essa esegua. Se questo processo è stato previsto, allora la macchina, invece di suonare il campanello, si predisporrà per ricevere le nuove schede che hanno relazione con l'operazione che deve seguire il passaggio attraverso zero o infinito. Queste nuove schede possono seguire le prime, ma entrano in azione soltanto al verificarsi di una o l'altra delle due condizioni appena menzionate.
Se tratta di una descrizione, un poco pesante, del concetto di salto. Una serie di schede segue, dal punto di vista fisico, un'altra serie di schede, ma è eseguita solo al verificarsi di una certa condizione. Quando la macchina incontra un punto di singolarità smette di eseguire la prima serie di schede e passa ad eseguire la seconda serie di schede, letteralmente saltando in un'altra porzione di codice. Una piccola nota amena: già a quell'epoca era previsto il fastidiosissimo beep (o forse drin) al verificarsi di una condizione anomala. Segue un esempio dedicato al calcolo di un termine della forma abn, nel quale Menabrea utilizza esplicitamente un ciclo.
Consideriamo un termine della forma abn; poiché le schede non sono altro che una traduzione della formula analitica [relativa all'analisi], il loro numero in questo caso particolare è sempre lo stesso, qualunque sia il valore di n [...] supponiamo per il momento che n sia un numero intero. Ora, poiché l'esponente n indica che b deve essere moltiplicato per se stesso n volte, è sufficiente impiegare una sola scheda-operazione, e cioè quella che ordina la moltiplicazione. Ma poiché n è dato per ogni caso particolare che deve essere calcolato, è richiesto l'ulteriore requisito che la macchina limiti il numero delle moltiplicazioni in accordo al valore dato. Il processo può essere così eseguito. I tre numeri a, b e n saranno scritti in tre distinte colonne del magazzino; le indichiamo come V0, V1, V2; il risultato abn finirà nella colonna V3. Quando il numero n sarà stato introdotto nella macchina, uno scheda ordinerà ad un certo apparato di registrazione [registering-apparatus] di segnare (n-1), e nello stesso tempo eseguirà la moltiplicazione di a per b. Quando questa sarà completata, si troverà che l'apparato di registrazione ha sottratto una unità, e segnerà soltanto (n-2); mentre la macchina ordinerà adesso di nuovo la moltiplicazione del numero b scritto nella colonna V1 per il numero b2 scritto nella colonna V3, che darà b3. Un'altra unità è adesso sottratta dall'apparato di registrazione, e lo stesso processo è continuamente ripetuto finché esso segna soltanto zero. Allora il numero bn sarà trovato in V3, quando la macchina, seguendo il corso delle operazioni, ordinerà il prodotto di bn per a; e il calcolo richiesto sarà stato completato senza che ci sia stata alcuna necessità di far variare il numero delle schede-operazione con il valore di n.
In questo esempio è esattamente
descritto un ciclo con diminuzione della variabile di controllo
ed uscita dal ciclo all'azzeramento della variabile. L'uso di
questa tecnica consente, come bene indica Menabrea, di eseguire
calcoli usando un numero fisso di schede, indipendentemente dal
valore dei dati numerici pertinenti ad uno specifico
problema.
L'articolo di Menabrea volge alla fine. Menabrea si chiede
quale sarebbe l'utilità dell'Analytical Engine, ammesso
che sia possibile costruirlo. L'autore individua tre punti:
Inoltre, sottolinea Menabrea, molte promettenti teorie, a causa della loro notevole complessità matematica, rischiano di restare al di fuori della scienza per la mancanza del potere sufficiente per calcolare i risultati numerici.
Quindi l'idea di costruire un apparato capace di aiutare la debolezza umana in queste ricerche, è una concezione che, se realizzata, segnerebbe un'epoca gloriosa nella storia della scienza.
Le note di Ada Lovelace.
Le note
aggiunte da Ada Lovelace nella traduzione inglese dell'articolo
di Menabrea sono identificate con le lettere dell'alfabeto, da
A a G.
La nota A contiene una spiegazione
delle sostanziali differenze tra il Difference Engine e
l'Analytical Engine. L'aspetto che pare più
interessante, in termini moderni, della nota A, è
l'insistenza con la quale Ada Lovelace propone una scienza
delle operazioni, cioè una teoria formale, facente
parte della matematica, avente come proprio oggetto le
operazioni stesse. Come fa notare Ada, esiste una
intrinseca ambiguità nella notazione matematica,
che non distingue tra l'operazione, il risultato
dell'operazione e gli oggetti sui quali si opera. Posso
fare un esempio per chiarire il pensiero di Ada. La
scrittura 26 confonde tre diversi usi della
notazione matematica: le cifre 2 e 6 indicano i numeri due
e sei, ma anche l'operazione di elevazione a potenza e il
risultato di tale operazione. Questo tipo di
ambiguità deve essere risolto per la programmazione
dell'Analytical Engine, nel quale è essenziale
distinguere tra le operazioni, rappresentate dalle schede
delle Operazioni, che indicano quali attività
intraprendere, e i dati sui quali tali attività
agiscono, rappresentati dalle schede delle Variabili.
L'Analytical Engine, spiega Ada Lovelace, non agisce sui
numeri, bensì esegue delle operazioni astratte ed
indipendenti dal materiale numerico sottostante, al punto
che l'Analytical Engine
può agire su altre cose oltre ai numeri, se le relazioni fondamentali degli oggetti possono essere espresse tramite quelle della scienza astratta delle operazioni [...] Se si suppone, per esempio, che le relazioni fondamentali dei suoni della scienza dell'armonia siano suscettibili di tale espressione e adattamenti, la macchina potrebbe comporre brani musicali elaborati e scientifici di ogni grado di complessità ed estensione.
Ciò che vuol dire Ada Lovelace è molto semplice e profondo: l'Analytical Engine non è una macchina che esegue solo calcoli numerici, ma può eseguire qualunque tipo di operazioni, anche non numeriche. Per questo non è limitata ai soli calcoli, ma ha lo stesso potere dell'algebra e dell'analisi astratta, e quindi può legittimamente trattare di tutte quelle materie riconducibili all'algebra e all'analisi. L'esempio proposto da Ada, relativo alla possibilità che l'Analytical Engine componga musica se questa è riconducibile a schemi di operazioni, serve a colpire il lettore e a fargli comprendere che le possibilità dell'Analytical Engine hanno la stessa estensione della scienza astratta delle operazioni (in termini moderni, la macchina esegue algoritmi e non calcoli numerici). Per questo, prosegue Ada, l'Analytical Engine potrebbe essere utilmente utilizzato per studiare problemi concernenti i numeri immaginari, intrattabili da qualsiasi macchina calcolatrice. Inoltre, sempre secondo Ada, dovrebbe essere facile per l'Analytical Engine aggiungere ai risultati numerici anche dei risultati simbolici,
i quali risultati simbolici sono la necessaria e logica conseguenza delle operazioni eseguite su dati simbolici, così come lo sono i risultati numerici quando i dati sono numerici.
Non si possono non ammirare gli sforzi che Ada Lovelace compie per tracciare una distinzione netta e precisa tra l'esecuzione di un calcolo e il calcolo in se stesso. Si tratta tra l'altro di una distinzione resa difficile dalla notazione matematica che si presta ad aumentare la confusione. Continua Ada Lovelace:
La caratteristica distintiva dell'Analytical Engine, e quella che ha reso possibile sviluppare un meccanismo con così estese possibilità da rendere questa macchina la mano destra esecutiva [nel testo originale "executive", nel senso di puramente operativo, che esegue le istruzioni] dell'algebra astratta, è l'introduzione in esso del principio che Jacquard ha ideato per regolare, mediante schede perforate, i più complicati schemi nella fabbricazione dei broccati. E' in questo che risiede la distinzione tra le due macchine [tra il Difference e l'Analytical Engine]. Niente del genere esiste nel Difference Engine. Noi possiamo dire, in maniera appropriata, che l'Analytical Engine tesse schemi algebrici così come il telaio di Jacquard stesse fiori e foglie.
In questo senso l'Analytical Engine ha superato i limiti dell'aritmetica e non ha nulla in comune con le macchine calcolatrici. Per questo, precisa Ada Lovelace, l'Analytical Engine non è il successore del Difference Engine, né il suo progetto può essere considerato in qualche modo correlato o suggerito da quello del Difference Engine. Si tratta di due macchine completamenti differenti, basati su principi intermante diversi. Il Difference Engine è una macchina calcolatrice perfezionata, il cui unico scopo è tabulare un particolare tipo di funzione matematica. Al contrario l'Analytical Engine esegue calcoli astratti, non limitati all'aritmetica, ed è basato su una teoria astratta delle operazioni.
La nota B tratta del metodo
utilizzato per la memorizzazione dei dati numerici. Come
già spiegato da Menabrea, i numeri sono memorizzati in
colonne di dischi che rappresentato le unità, le decine,
le centinaia, e così via. Il modo di memorizzazione dei
numeri nell'Analytical Engine non differisce in maniera
sostanziale da quello utilizzato nel Difference Engine. Il
numero di cifre memorizzabili dipende dal numero di dischi che
costituiscono una colonna. Nel progetto dell'Analytical Engine
Babbage prevedeva la possibilità di utilizzare 20
dischi, per memorizzare numeri fino a 20 cifre. Un ulteriore
disco è utilizzato per registrare il segno del
numero.
La citazione seguente, tratta dalla nota B, mostra uno schema
di notazione suggerito da Ada Lovelace. Nelle colonne
V1, V2 e V3 sono memorizzati i
numeri positivi 5, 7 e 98. La colonna è V4
vuota e contiene ancora il valore iniziale 0. Sotto le colonne
vi è un quadrato che contiene
qualsiasi simbolo generale o combinazione di simboli che ci piace; si intende che il numero rappresentato nella colonna immediatamente sopra è il valore numerico di quel simbolo o combinazione di simboli. Per esempio, rappresentiamo le tre quantità a, n, x, e supponiamo inoltre che sia a=5, n=7, x=98. Avremo dunque:
![]()
E' importante notare che nella notazione
suggerita da Ada Lovelace, il quadrato posto alla fine della
colonna ha la funzione di un commento.
Ci ricorda cioè quale variabile
è rappresentata nella colonna in questione, ma non
ha alcuna funzione nella macchina stessa, né ha
alcun elemento fisico corrispondente. I nomi assegnati
alle colonne (V1, V2, ecc.) hanno
sia una funzione mnemonica sia la funzione di individuare
la colonna fisica: la variabile Vn identifica
infatti la n-esima colonna (in un certo senso di tratta di
un meccanismo simbolico per indirizzare in modo assoluto
le locazioni di memoria). Nel caso del segno, Ada propone
una rappresentazione simbolica, ma la macchina in
realtà registra un numero pari per il segno
positivo, dispari per il segno negativo (questo è
un esempio nel quale ad un valore numerico è
associato un significato non numerico). Usando questa
notazione, Ada mostra come si potrebbe rappresentare lo
stato della macchina prima che essa calcoli l'espressione
axn, dopo che le costanti numeriche sono
state inserite nelle colonne opportune:
Trattando delle schede perforate usate per programmare l'Analytical Engine, Ada svolge le seguenti osservazioni.
Le schede delle Operazioni determinano soltanto la successione delle operazioni in un modo generale. Esse infatti pongono l'intera porzione del meccanismo incluso nella fabbrica in una serie di stati differenti, che noi possiamo chiamare lo stato dell'addizione, o lo stato della moltiplicazione, ecc., rispettivamente. In ciascuno di questi stati il meccanismo è pronto per agire nella maniera peculiare a quello stato, su ogni coppia di numeri che si permette di entrare nella sua sfera di azione. Solo uno di questi stati operativi della fabbrica può esistere in un certo istante [...].
Troviamo qui una descrizione molto precisa del funzionamento della fabbrica, che sempre più possiamo identificare con l'unità logico-aritmetica di un moderno calcolatore. La fabbrica passa attraverso una serie di stati, ciascuno dei quali è caratterizzato in maniera univoca dall'operazione che sarà eseguita; in ogni istante la macchina si trova in uno e in un solo uno di questi stati. Le schede delle Operazioni programmano la macchina in modo da attraversare una serie definita di stati. L'analogia con la macchina di Turing appare evidente (è utile ricordare che la nozione di macchina di Turing sarà introdotta circa novanta anni dopo la pubblicazione di questo articolo). La breve nota C spiega che, a differenza del telaio di Jacquard, in cui il nastro di schede può solo avanzare, nell'Analytical Engine è stato introdotto un meccanismo che consente al nastro di schede di retrocedere, in modo da poter eseguire più volte una o più schede.
Il modo di applicazione delle schede, come usato nell'arte della tessitura, fu comunque trovato non essere sufficientemente potente per tutte le semplificazioni che era desiderabile ottenere in così vari e complicati processi come quelli richiesti in ordine di realizzare gli scopi di un Analytical Engine. Fu escogitato un metodo tecnicamente designato backing per far retrocedere le schede in determinati gruppi in accordo a determinate leggi. L'oggetto di questa estensione è di assicurare la possibilità di utilizzare ogni particolare scheda o insieme di schede un qualsiasi numero di volte successivamente nella soluzione di un particolare problema. Il fare o non fare uso di questa possibilità, in ogni caso particolare, dipenderà dalla natura delle operazioni che il problema sotto esame può richiedere.
In questa descrizione della nozione di ciclo, è importante sottolineare la prima frase, secondo la quale l'esecuzione delle istruzioni in modo puramente sequenziale non è sufficientemente potente per gli scopi dell'Analytical Engine. Si tratta di una considerazione del tutto corretta, perché esistono algoritmi non esprimibili mediante una successione lineare di istruzioni. L'uso dei cicli è ripreso nella successiva nota F.
La nota D contiene alcune precisazioni sulla notazione utilizzata per rappresentare i programmi. In primo luogo
In tutti i calcoli, le colonne delle Variabili usate possono essere divise in tre classi:
1°. Quelle nelle quali i dati sono registrati [variabili per i dati: Variables for Data].
2°. Quelle destinate a ricevere i risultati finali [variabili per i risultati: Variables for Results].
3°. Quelle destinate a ricevere quelle combinazioni intermedie e temporanee dei dati primitivi che non devono essere permanentemente mantenute, ma sono soltanto necessarie per lavorare, al fine di conseguire i risultati finali. Combinazioni di questo genere possono essere propriamente chiamati dati secondari. Essi sono in realtà passi successivi verso il risultato finale. Le colonne che li ricevono sono giustamente chiamate Variabili di lavoro [Working-Variable], poiché il loro ufficio è per sua natura puramente sussidiario ad altri scopi. Essi producono una classe intermedia e transiente di risultati, che unisco i dati originali con i risultati finali.
Riassumendo, Ada distingue tra:
Correttamente Ada sottolinea che talvolta le variabili per i risultati hanno una natura simile alle variabili di lavoro, poiché frequentemente le variabili per i risultati sono utilizzate per registrare i valori dei calcoli intermedi necessari per arrivare al risultato. Ada introduce inoltre un'aggiunta alla notazione utilizzata da Menabrea. Le variabili dispongono di due indici (esempio: 1V3).
Gli indici inferiori sono ovviamente soltanto indici di localizzazione [locality], e sono totalmente indipendenti dalle operazioni eseguite o dai risultati ottenuti, e il loro valore rimangono invariabili durante le esecuzioni dei calcoli. Gli indici superiori, comunque, sono di una differente natura. Il loro ufficio è di indicare ogni alterazione nel valore che una Variabile rappresenta; e naturalmente possono variare durante il progresso di un calcolo. Quando una Variabile ha solo zeri, essa è chiamata 0V; quando un valore appare in essa (sia che il valore sia posto lì arbitrariamente, o che appaia nel corso naturale di un calcolo), essa diventa 1V. Se questo valore cede il posto a un altro valore, la Variabile diventa 2V, e così via. Ogniqualvolta un valore è sostituito dallo zero, la Variabile diventa nuovamente 0V, anche se il momento prima fosse stato nV. Se assume ancora un nuovo valore, la Variabile diventa n+1V.
Quindi 0V3 indica la variabile associata alla colonna 3 non ancora inizializzata (contenente cioè solo zeri). Quando in questa colonna è inserito un numero, la variabile è scritta come 1V3. I vantaggi di questa scrittura, sostiene Ada Lovelace, sono molteplici. In particolare, un'espressione come m+1Vn = qVp + mVn è più chiara e consistente con le leggi dell'algebra della corrispondente espressione Vn = Vp + Vn che non fa uso degli indici superiori (quest'ultima è la notazione effettivamente utilizzate negli odierni linguaggi di programmazione).
La nota E contiene alcune considerazioni sulla complessità dei cicli che l'Analytical Engine è in grado di gestire. Parlando dello sviluppo di funzioni tramite serie di funzioni più semplici, Ada nota che i termini successivi di tale sviluppo seguono sempre la medesima regola e quindi possono essere calcolati dalla macchina mediante
un ciclo di un ciclo di un ciclo, ecc., di operazioni, una, due, tre, fino a n-1 volte, al fine di ottenere la n-esima funzione.
In una nota a piè di pagina, Ada spiega che
Un ciclo che include n altri cicli, successivamente contenuti uno dentro l'altro, è chiamato un ciclo di ordine n+1. Un ciclo può successivamente includere molti altri cicli, ed essere ancora del secondo ordine. Se una serie segue una certa legge per un certo numero di termini, e quindi un'altra legge per un altro numero di termini, ci sarà un ciclo di operazioni per ogni nuova legge; ma questi cicli non saranno contenuti uno dentro l'altro, ma semplicemente seguiranno uno dopo l'altro. Quindi il loro numero può essere infinito senza influenza l'ordine di un ciclo che include una ripetizione di una tale serie.
Ada prevede chiaramente in questo passo la
possibilità di annidare di cicli di operazioni e di
avere cicli che contengono al loro interno, in forma non
annidata ma successiva, altri cicli. Si capisce da queste
citazioni e dalla frequenza con la quale Ada parla dei cicli di
operazioni che ella aveva ben compreso l'importanza nella
programmazioni di struttura cicliche annidate, che ben si
prestano a risolvere problemi ricorrenti.
La maggior parte della nota E è dedicata allo sviluppo
di alcuni esempi di calcolo relativi a funzioni
trigonometriche; ometto la descrizione di questi esempi, a
causa sia della loro complessità matematica, sia
perché Ada non li sviluppa in maniera dettagliata.
Vedremo tra poco, trattando la nota G, un esempio altrettanto
complesso ma sviluppato da Ada in gran dettaglio, al punto che
possiamo ricavarne un programma
completo.
Nella nota F Ada mostra come l'uso dei cicli può ridurre in maniera drastica il numero di schede necessarie per risolvere un problema. L'esempio proposto consiste nel risolvere, mediante eliminazione delle variabili, un sistema di dieci equazioni lineari. Secondo Ada sarebbero necessarie 330 schede; con l'utilizzo dei cicli queste 330 schede si riducono a tre. Ancora più importante è la considerazione che questo ciclo di tre schede può essere usato per un qualsiasi sistema di n equazioni lineari, indipendentemente dal numero n.
La nota G contiene un esempio di programmazione piuttosto complesso: il calcolo dei numeri di Bernoulli. I numeri di Bernoulli Bn prendono il nome dal matematico Jacob Bernoulli e sono stati definiti dalla formula seguente (attualmente si utilizza una definizione diversa)
Talvolta si incontra anche questa formula:
Ada Lovelace utilizza la seguente formula per la definizione dei numeri di Bernoulli:
Attraverso alcuni passi matematici che ometto Ada arriva alla seguente formula equivalente che, nella numerazione della nota G, ha il numero (8):
I primi dieci numeri di Bernoulli sono riportati nella seguente tabella tratta da http://www.sosmath.com/tables/bernoulli/bernoulli.html.
Così Ada commenta la formula (8):
Ad un'attenta considerazione, ci accorgiamo che noi possiamo derivare da essa i valori numerici di tutti i Numeri di Bernoulli in successione, a partire proprio dal primo, ad infinitum, mediante le seguenti serie di calcoli:
1a Serie. - Sia n=1, e si calcoli (8) per questo valore di n. Il risultato è B1.
2a Serie. - Sia n=2. Si calcoli (8) per questo valore di n, sostituendo il valore di B1 appena ottenuto. Il risultato è B3.
3a Serie. - Sia n=3. Si calcoli (8) per questo valore di n, sostituendo i valori di B1, B3 prima ottenuti. Il risultato è B5. E così via, per ogni valore.
A questo punto Ada riporta una tabella che
illustra lo stato delle macchina durante il calcolo di
B7 (n=4). Per visualizzare questa tabella
nella sua interezza, fare clic
qui (la tabella è
estratta da
http://www.fourmilab.ch/babbage/sketch.html).
La tabella si presenta come traccia passo-passo di un programma
che utilizza la formula (8) per il calcolo dei numeri di
Bernoulli, quando n=4, e quindi il prossimo numero di
Bernoulli da calcolare è B7.
La prima parte della tabella proposta da Ada Lovelace è
visualizzata nella successiva Tavola 1. La tabella completa
continua in basso, con i restanti passi del programma (in
totale sono presenti 25 righe), e a destra, dove sono riportate
le 24 colonne dati (fare clic
qui per visualizzare la
tabella intera). La numerazione delle tavole (Tavola1, Tavola2,
ecc...) è mia e serve per facilitare il riferimento alle
varie porzioni della tabella; essa è infatti troppo
grande per essere visualizzata in una sola schermata, e quindi
la mostrerò in porzioni limitate, ciascuna delle quali
è pertinente ad una diversa sezione del programma per il
calcolo dei numeri di Bernoulli.
Per capire il programma è
ovviamente necessario conoscere i valori
iniziali delle variabili dati; tali valori sono riportati
nella porzione di tabella (Tavola 2) riportata qui
accanto. Le tre variabili dati V1,
V2 e V3 contengono inizialmente i
numeri 1, 2 e n rispettivamente. Nell'esempio
proposto da Ada Lovelace n vale 4; tuttavia il
programma presentato da Ada risulta sufficientemente
generale da non essere influenzato dal valore corrente di
n. Inizialmente n deve valere 1, come
d'altronde spiegato da Ada nel commento alla formula (8),
per il calcolo di B1.
Oltre a commentare la tabella proposta da Ada, in questo
articolo sarà fornita una versione moderna del programma
stesso, scritto in Java. Di fatto, la porzione di tabella
presentata nella Tavola 2 sta per i seguenti
passi:
V[1] = 1;
V[2] = 2;
V[3] = n;
E' opportuno notare che in un moderno
linguaggio di programmazione è obbligatorio definire il
tipo di dato rappresentato nelle variabili; in questo caso
l'array V sarà definito di tipo double. Niente di
ciò è presente nelle tabelle proposte da Ada e da
Menabrea; in realtà nei loro esempi le variabili sono
più simili alle locazioni di memoria utilizzate nei
primi programmi in Assembler, senza alcun tipo specifico
associato.
Torniamo alla Tavola 1 per ricavare la seguente porzione di
codice:
V[4] = V[2] * V[3];
V[5] = V[2] * V[3];
V[6] = V[2] * V[3];
V[4] = V[4] - V[1];
V[5] = V[5] + V[1];
V[11] = V[4] / V[5];
V[11] = V[11] / V[2];
V[13] = V[13] - V[11];
V[10] = V[3] - V[1];
Ciascuna delle nuove variabili deve disporre
di un'opportuna definizione e inizializzazione. Per esempio
nella riga 6 della Tavola 1, nell'istruzione V[13] = V[13] -
V[11] la variabile V[13] deve essere stata inizializzata a
zero, come si deduce dal valore dell'indice soprascritto. Dal
commento di Ada a questa istruzione, risulta che essa serve a
cambiare il segno di V[11]; in linguaggio di programmazione
contemporaneo, è più semplice scrivere V[13] = -
V[11].
In definitiva, le istruzioni corrispondenti alla prime sei
righe della Tavola1 calcolano il valore di
primo termine dello sviluppo di (8). A cosa serve la riga 7? Lo spiega Ada:
L'Operazione 7 sarebbe incomprensibile, se non si ricordasse che se noi eseguissimo il calcolo per n=1 invece che per n=4, l'Operazione 6 avrebbe completato il calcolo di B1 stesso, nel qual caso la macchina invece di continuare il proprio processo, dovrebbe porre B1 in V21; e quindi si sarebbe fermata o avrebbe iniziato le Operazioni 1, 2 ... 7 di nuovo per il valore di n(=2), al fine di iniziare il calcolo di B3; (avendo comunque avuto cura, prima di ricominciare, di rendere il numero in V3 uguale a due, aggiungendo una unità al precedente n=1 in quella colonna). Dunque l'Operazione 7 deve restituire un risultato uguale a zero (se n=1); o un risultato maggiore di zero, come nel caso presente [ricordo che Ada presenta il caso n=4]; e la macchina segue l'una o l'altra di queste due strade appena spiegate, a secondo dell'uno o dell'altro risultato dell'Operazione 7.
Quindi, dopo avere eseguito l'istruzione
V[10] = V[3] - V[1] si deve eseguire un test per verificare se
V[10] è uguale a zero; in caso affermativo in V[13]
troviamo il valore di B1 e tale valore è
inserito in una variabile opportuna (V[21]), dopodiché
si aggiunge 1 a V[3] e il controllo torna alla riga 1; se
invece V[10] è maggiore di zero il programma prosegue
con la successiva riga 8. Si noti la mancanza di una qualsiasi
simbologia per l'istruzione di salto condizionato; nell'esempio
presentato da Ada non esiste alcun modo per indicare un test su
una variabile, né per indicare un salto a fronte di una
condizione, né per indicare a quale istruzione cedere il
controllo. Non disponendo di queste possibilità, Ada
deve utilizzare una descrizione verbale per indicare un
semplice test per zero, il cui significato è comunque
sufficientemente chiaro.
Quindi possiamo ottenere la seguente porzione di
codice:
V[4] = V[2] * V[3];
V[5] = V[2] * V[3];
V[6] = V[2] * V[3];
V[4] = V[4] - V[1];
V[5] = V[5] + V[1];
V[11] = V[4] / V[5];
V[11] = V[11] / V[2];
V[13] = - V[11];
V[10] = V[3] - V[1];
if (V[10] == 0)
{ V[21] = V[13];
V[3] = V[3] + 1;
return;
}
Questo frammento di codice fornisce il primo
numero di Bernoulli. Ho provato ad eseguirlo (dopo averlo
completato con le necessarie definizione delle variabili e
delle classi come richiesto dallo specifico linguaggio di
programmazione usato) ed ho ottenuto il risultato B1
= - 1.5, in disaccordo con il valore corretto B1 =
0.166667. Infatti la riga 4 della Tavola 1 è errata:
l'istruzione corretta è V[11] = V[4] / V[5]
mentre nella tabella è indicato V[11] = V[5] /
V[4].
Ciò è ovvio dal commento associato alla riga 4.
Ada ha calcolato l'inverso del valore che voleva effettivamente
ottenere. Correggendo la svista, si ottiene un programma che
fornisce per B1 il valore corretto (come modulo)
-0.1666667; e il segno? Ada dice esplicitamente:
Nella tabella e nel diagramma precedenti noi non consideriamo il segno di nessuno dei B, ma solo il loro valore numerico. La macchina naturalmente troverà il segno corretto per ciascuno di essi, ma noi non entreremo in alcun dettaglio addizionale di questo tipo di calcolo, come invece avremmo voluto fare.
Si può pensare che Ada Lovelace non
abbia avuto a propria disposizione abbastanza spazio nelle note
per trattare il problema del segno dei numeri di Bernoulli, ma
ovviamente non è possibile ottenere un programma che
generi i numeri corretti se non si tiene conto del segno;
infatti, ignorando il segno, si andrebbe incontro ad errori
anche nel valore numerico dei numeri di Bernoulli. Per questo
nella nostra versione, pur cercando di restare fedeli alla
tabella di Ada, dobbiamo obbligatoriamente trattare
esplicitamente il segno. Ciò porta a sostituire
l'istruzione
V[21] = V[13];
con
V[21] = Math.abs(V[13]);
Adesso si ottiene il risultato corretto per B1 = 0.166667. La tabella proposta da Ada continua con le successive istruzioni; ci interessa al momento questo frammento:
Così Ada commenta queste istruzioni:
Le schede 8, 9, 10 generano
![]()
[...] La scheda 12 esegue lo stesso ufficio che la scheda 7 faceva nella sezione precedente: quindi, se n fosse stato 2, l'undicesima operazione avrebbe completato il calcolo di B3.
Possiamo aggiungere le istruzioni corrispondenti alle schede 8 - 12 nella precedente porzione di programma; otteniamo dunque:
V[4] = V[2] * V[3];
V[5] = V[2] * V[3];
V[6] = V[2] * V[3];
V[4] = V[4] - V[1];
V[5] = V[5] + V[1];
V[11] = V[4] / V[5];
V[11] = V[11] / V[2];
V[13] = - V[11];
V[10] = V[3] - V[1];
if (V[10] == 0)
{ V[21] = Math.abs(V[13]);
V[3] = V[3] + 1;
return;
}
V[7] = V[2];
V[11] = V[6] / V[7];
V[12] = V[21] * V[11];
V[13] = V[12] + V[13];
V[10] = V[10] - V[1];
if (V[10] == 0)
{ V[22] = Math.abs(V[13]);
V[3] = V[3] + 1;
return;
}
Eseguendo il programma finora ottenuto si calcolano i primi due numeri di Bernoulli:
Si noti che nella formula proposta da Ada i
numeri di Bernoulli hanno sempre indice dispari, e quindi il
numero B3 della formula (8) corrisponde al numero
B2 della tabella che elenca i numeri di Bernoulli;
ma questa è una differenza che non crea alcun
problema.
E' necessario un ulteriore commento al programma proposto da
Ada: questo programma viene attivato più volte con i
valori successivi di n = 1,2,3,4,5,..., in modo che ogni
volta sia calcolato il successivo numero di Bernoulli
Bn. Questo numero è memorizzato in una
memoria opportuna (V21, V22,
V23,...) dove rimane disponibile per le successive
elaborazioni. Quando il programma viene per esempio attivato
con n=5, le colonne V21 V22
V23 V24 contengono già i valori
corretti per B1 B2 B3
B4.
Ed ecco la successiva porzione della tabella di Ada:
Le istruzioni corrispondenti alle schede 13-22 eseguono il calcolo di B5. L'istruzione corrispondente alla scheda 23 esegue il medesimo compito di quelle corrispondenti alle schede 7 e 11 precedenti. Le istruzioni previste dalle schede 13-22 sono le seguenti:
int i = 0;
do
{ V[6] = V[6] - V[1];
V[7] = V[7] + V[1];
V[8] = V[6] / V[7];
V[11] = V[8] * V[11];
V[6] = V[6] - V[1];
V[7] = V[1] + V[7];
V[9] = V[6] / V[7];
V[11] = V[9] * V[11];
V[12] = V[22+i] * V[11];
V[12] = V[12] * Math.pow(-1,i-1);
V[13] = V[12] + V[13];
V[10] = V[10] - V[1];
if (V[10] == 0)
{ V[20+n] = Math.abs(V[13]);
V[3] = V[3] + 1;
return;
}
i++;
} while (V[10] > 0);
E' necessario un commento a questa porzione di programma. Alcune istruzioni non sono presenti nella tabella di Ada. In particolare Ada non fornisce alcuna indicazione su come il programma individua la colonna nella quale memorizzare i successivi numeri di Bernoulli. Sappiamo dall'esempio proposto che B1 sarà memorizzato in V21, B2 in V22 e così via. Possiamo immediatamente comprendere che Bn è memorizzato in V20+n ma questa istruzione non è presentata da Ada. In realtà, dietro questa semplice istruzione è presente un concetto che sembra assente sia nell'articolo di Menabrea sia nelle note di Ada: la possibilità di individuare un colonna dati mediante un numero memorizzato in un'altra colonna dati. I numeri registrati nelle colonne dati sono pensati come valori numerici o anche come elementi simbolici (quando per esempio una cifra è usata per indicare il segno del numero presente nella colonna stessa), ma in nessun caso è presa in considerazione la possibilità che essi rappresentino un'altra colonna dati. In definitiva nei programmi proposti manca una istruzione fondamentale: l'indirizzamento della memoria mediante riferimento al valore numerico presente in un'altra locazione di memoria. Questa mancanza è di natura diversa dalle altra mancanze segnalate. E' vero che non è presentata alcuna scheda di Operazioni per il test di una condizione, il salto condizionato o il ciclo, ma in questi casi si sopperisce a tale mancanza attraverso una descrizione verbale ma precisa del comportamento che dovrebbe assumere la macchina. Questo fatto suggerisce che Menabrea e Ada avevano presenti alcuni tipi di istruzioni fondamentali come il test, il salto e il ciclo, ma mancavano della nozione di indirizzamento della memoria tramite una variabile dati. Per questo l'istruzione
V[20+n] = Math.abs(V[13]);
deve essere considerate come una istruzione contemporanea, che non trova giustificazione negli esempi proposti da Ada e Menabrea, ma senza la quale il programma per il calcolo dei numeri di Bernoulli non potrebbe funzionare. Un'altra istruzione differente rispetto a quelle previste da Ada è
V[12] = V[22+i] * V[11];
Anche in essa è presente un
indirizzamento di memoria mediante l'utilizzo di un'altra
variabile (in questo caso la variabile i) che non
è presente nel programma di Ada; proprio per
sottolineare tale assenza, ho scelto di chiamare tali variabili
i o n, differenziandole anche nella
notazione dalle variabili V previste da Ada. Devo però
citare il seguente passo presente sempre nella nota G.
[...] l'Operazione 21 richiede sempre uno dei suoi fattori da una nuova colonna, e l'Operazione 24 mette sempre il proprio risultato in una nuova colonna. Ma poiché queste variazioni seguono la medesima legge ad ogni ripetizione (l'Operazione 21 richiedendo sempre il suo fattore da una colonna che precede immediatamente quella usata la volta precedente, e l'Operazione 24 ponendo sempre il proprio risultato nella colonna che precede immediatamente quella che aveva ricevuto il precedente risultato), esse [le variazioni di colonna] possono essere facilmente realizzate nella disposizione del gruppo ricorrente (o ciclo) delle schede delle Variabili.
In questo passo Ada cerca di determinare come individuare la colonna variabile sulla quale agire, il che mostra che aveva presente il problema; la soluzione proposta mi sembra però legata alla particolare disposizione delle schede delle variabili in questo caso specifico e non generale (in termini tecnici, l'offset utilizzato per individuare la colonna dati è una costante=1 e non una variabile). La seguente istruzione
V[12] = V[12] * Math.pow(-1,i-1);
risolve il problema lasciato aperto da Ada e
relativo al segno corretto dei numero di Bernoulli, agendo in
maniera opportuna sul segno dei coefficiente previsti nella
formula (8).
Le istruzioni precedenti sono racchiuse in un ciclo, da
ripetersi fino a quando la variabile V10 non si
annulla. Ciò è esplicitamente previsto da
Ada:
Si comprenderà che ogni unità aggiunta a n in B2n-1 produce una ulteriore ripetizione delle operazioni (13...23) per il calcolo di B2n-1.
Inoltre anche la porzione successiva (e conclusiva) della tabella (vedi la successiva Tavola 5) indica la necessità di una ripetizione delle operazioni da 13 a 23.
L'istruzione presente nella scheda 25
incrementa di una unità la variabile V3 (la
variabile n); dopodiché il programma è
pronto per calcolare il successivo numero di Bernoulli. Questa
istruzione è mantenuta in un ciclo esterno nella mia
realizzazione del programma proposto da Ada (fare clic
qui per scaricare il sorgente).
In definitiva il programma presentato da Ada Lovelace è
sostanzialmente corretto e, una volta completato con le
istruzioni proprie di un determinato linguaggio di
programmazione, consente effettivamente il calcolo dei numeri
di Bernoulli. E' inoltre un programma abbastanza complesso, sia
nella parte matematica sia nella programmazione. Le
difficoltà che l'autore deve aver affrontato sono
maggiori di quelle che possiamo percepire oggi, tenuto conto
che questo programma è stato pubblicato nel 1843, in
mancanza di una teoria dei computer e dei computer stessi.
Non si può concludere questo articolo senza prendere in considerazione una celebre affermazione di Ada Lovelace che apre la nota G.
E' desiderabile guardarsi contro la possibilità di idee esagerate che potrebbero sorgere circa le potenzialità dell'Analytical Engine. Nel considerare un qualsiasi nuovo soggetto, c'è frequentemente una tendenza, primo, di sopravvalutare ciò che noi troviamo essere già interessante o rimarchevole; e, secondariamente, per una sorta di naturale reazione, di sottovalutare il vero stato delle cose, quando noi scopriamo che le nostre aspettative hanno sorpassato ciò che era realmente sostenibile. L'Analytical Engine non ha alcuna pretesa di produrre alcunché. Può fare tutto quello che noi sappiamo come ordinargli di eseguire. [The Analytical Engine has no pretensions whatever to originate anything. It can do whatever we know how to order it to perform.] Può seguire un'analisi; ma non ha alcuna capacità di anticipare alcuna relaziona analitica o verità.
Mi limito a citare questa affermazione di Ada Lovelace, senza tentare alcun commento. Credo invece sia molto interessante citare e commentare quello che Ada scrive alcune righe dopo.
[...] è probabile che eserciti una influenza indiretta e reciproca sulla scienza stessa in un'altra maniera. Infatti, nel modo di distribuire e combinare le verità e le formule dell'analisi affinché diventino più facilmente e rapidamente comprensibili alla macchina, le relazioni e la natura di molti soggetti in questa scienza sono necessariamente posti sotto una nuova luce, e più profondamente investigati.
In questo passo Ada mostra una profonda comprensione delle problematiche inerenti la programmazione dei calcolatori. Secondo Ada, la necessità di rendere comprensibili le formule dell'analisi ad una macchina, produrrà degli studi più profondi sulla natura di queste relazioni, al punto di influenzare la matematica stessa. In effetti la nascita e la diffusione dei calcolatori sono stati accompagnati dallo sviluppo di nuovi settori della matematica, quali la teoria della complessità degli algoritmi, la teoria delle macchine di Turing, la teoria delle funzioni ricorsive, il lambda-calcolo, la teoria dell'informazione e la cibernetica. I calcolatori, lungi dall'essere solo un mero strumento per eseguire rapidamente e con sicurezza calcoli ripetitivi, hanno generato la necessità di uno sviluppo di nuovi settori della matematica, alcuni dei quali, senza i calcolatori, avrebbero uno scarso interesse teorico e pratico. Ciò non significa che le citate discipline matematiche siano nate al servizio dei calcolatori: per esempio la teoria delle funzioni ricorsive, il lambda-calcolo e la teoria delle macchine di Turing esistevano prima dello sviluppo dei calcolatori elettronici, ma interessavano solo un ristretto numero di logici e filosofi. Grazie ai calcolatori, sono diventati patrimonio comune di informatici e matematici.
Note bibliografiche.
La
traduzione inglese dell'articolo di Menabrea, con le note di
Ada Lovelace, è reperibile in
http://www.fourmilab.ch/babbage/sketch.html
Notizie biografiche su Menabrea e Ada Lovelace sono reperibili
in:
http://www-history.mcs.st-andrews.ac.uk/history/Mathematicians/Menabrea.html
http://www-history.mcs.st-andrews.ac.uk/history/Mathematicians/Lovelace.html
Nel sito della scuola Dagomari del Comune di Prato è
presente un museo virtuale del computer, con informazione e
immagini sulla storia del computer, relative anche al telaio di
Jacquard e a Charles Babbage:
http://www.scuole.prato.it/dagomari/museo/htm/ingresso.htm
I seguenti articoli pubblicati su Scientific American parlano
di Babbage e Ada Lovelace:
Redeeming Charles Babbage's Mechanical Computer, di
Doron D. Swade, febbraio 1993
Ada and the First Computer, di Eugene Eric Kim e Betty
Alexandra Toole, maggio 1999
L'autobiografia di Babbage:
Charles Babbage, Passages from the Life of a
Philosopher, a cura di Martin Campbell-Kelly, Pickering
& Chatto Ltd, 1994