2.6. I numeri dell’orologio Come produrre le tabelline delle 4 operazioni con le classi di resto modulo enne. Prerequisiti operatori: %, <, e ==. funzioni con parametri, struttura di selezione: if ..else, struttura di iterazione: while e istruzione break, funzione divmod() liste.
Argomenti trattati classi resto, visualizzazione di una matrice,
Problema Scrivere delle funzioni che visualizzino le tabelline delle quattro operazioni con i numeri modulo enne.
Soluzione Quanti sono i numeri? Domanda alla quale, fin dalle elementari, si impara a rispondere: “infiniti”! Infatti, a qualunque numero si arrivi basta aggiungere “1” per ottenerne un altro. Questo ragionamento fila se pensiamo che aggiungendo “1” ad un numero si ottenga sempre un numero nuovo non presente nelle sequenza di numeri già incontrati. Si possono pensare, invece, degli insiemi di numeri nei quali, ad un certo punto, aggiungendo “1” si ottenga di nuovo “0”: . In questo modo i numeri si avvolgono su sé stessi e si ottiene un insieme limitato di numeri. Nel caso precedente l’insieme è costituito da 6 numeri: {0, 1, 2, 3,4, 5}. Poiché questi numeri possono essere visti come tutti i possibili resti della divisione di un numero intero qualunque per 6, sono anche detti “classi di resto modulo 6”. Ora, si potrebbe pensare che un insieme di numeri così limitato possa risultare del tutto inutile, ma non è così. Questi insiemi finiti di numeri sono stati studiati dal grande matematico C.F. Gauss. È possibile definire alcune operazioni su questi insiemi di numeri. Le operazioni definite su questi numeri hanno delle proprietà molto interessanti tanto è vero che attualmente la crittografia e quindi tutto ciò che riguarda la sicurezza, nella nostra società, è basato su queste proprietà, oltre che sulle proprietà dei numeri primi e della scomposizione in fattori primi. Messa giù così, si potrebbe pensare che questa faccenda riguardi soltanto problemi molto più grandi di noi, invece noi usiamo tutti i giorni i numeri di questo tipo, precisamente quando guardiamo l’orologio o quando facciamo dei conti con le ore: 5 ore dopo le 9 della mattina sono le 2 del pomeriggio: 9+5=2. I numeri dell’orologio sono le classi di resto modulo 12 o modulo 24 a seconda di come abbiamo settato la nostra sveglia. Per ottenere il risultato di un’operazione in questi insiemi di numeri, possiamo eseguire l’operazione come avessimo a che fare con i normali numeri interi e poi dividere il risultato per il modulo ( nel caso delle ore: 12 (o 24)) e tenere il resto: 912+512=resto_della_divisione(9+5, 12) Cioè: se alla “classe di resto modulo 12” 9 aggiungo la “classe di resto modulo 12” 5 ottengo il resto della divisione tra la somma 9 + 5 e 12. A rileggere il testo in “simil italiano” mi pare così complicato! Che grande invenzione i simboli matematici!!! Veniamo a noi, vogliamo scrivere un programma che costruisca e stampi le tabelline delle operazioni con i numeri classe resto modulo enne. Prima di tutto precisiamo come può essere rappresentata all’interno di Python una tabella quadrata come la seguente: 2 3 4 1 2 3 4 3 2 Possiamo usare le liste: una lista di 3 numeri rappresenta una riga e tre liste rappresentano l’intera matrice: matrice=[[2, 3, 4], [1, 2, 3], [4, 3, 2]] Siccome la rappresentazione con i numeri ben schierati è più leggibile di una lista di liste, prima di procedere ci costruiamo una funzione che stampi per bene una matrice con un numero qualunque di righe e di colonne. In pseudocodice: def printmat(matrice):
- per ogni riga contenuta nella matrice:
- per ogni elemento contenuto nella riga:
- stampa l’elemento senza andare a capo
va a capo
Dato che i numeri delle matrici che costruiremo saranno sempre compresi tra 0 e 99, cioè avranno al massimo 2 cifre, per il comando stampa conviene usare la stringa di formattazione “%2s” che produce una stringa che contiene il numero formata sempre da due caratteri, eventualmente aggiungendo uno spazio prima se il numero è minore di 10. Tradotto in Python: def printmat(mat):
- “”“Stampa una matrice bidimensionale di numeri di una o due cifre
- allineando le colonne.”“”
- for riga in mat:
- for elemento in riga:
- print “%2s” % elemento,
Notare che la virgola che termina il primo comando print sta a significare: “stampa senza andare a capo”. Dopo aver salvato il file e averlo eseguito, proviamo il funzionamento: >>> m=[[2, 3, 4], [1, 2, 3], [4, 3, 2]] >>> printmat(m) 2 3 4 1 2 3 4 3 2 Ora che ci siamo forniti dello strumento per stampare una matrice di numeri concentriamoci sul problema: vogliamo scrivere una funzione che produca la tabellina (matrice) dei risultati delle operazioni con le classi modulo resto enne. Iniziamo dalla moltiplicazione. In pseudocodice: def matprod(mod):
predisponi una matrice vuota per mod volte:
predisponi una riga vuota per mod volte:
calcola il prossimo ele. della lista e agg. alla rigaaggiungi la riga alla matrice
restituisci la matrice
Proviamo a vedere un caso abbastanza semplice e poi a generalizzarlo:
x 0 1 2 3 0 0 0 0 0 1 0 1 1 3 2 0 2 0 2 3 0 3 2 1
Le formule per ottenerlo sono: x 0 1 2 3 0 0*0 mod 4 0*1 mod 4 0*2 mod 4 0*3 mod 4 1 1*0 mod 4 1*1 mod 4 1*2 mod 4 1*3 mod 4 2 2*0 mod 4 2*1 mod 4 2*2 mod 4 2*3 mod 4 3 3*0 mod 4 3*1 mod 4 3*2 mod 4 3*3 mod 4
Per ottenere il valore di una cella devo prendere l’intestazione della riga di quella cella (indice della riga), moltiplicarla per l’intestazione della colonna di quella cella (l’indice della colonna) e calcolare il resto della divisione per 4 se sto lavorando con le classi di resto modulo 4. Scegliamo un nome per gli indici delle righe: iy e un nome per gli indici delle colonne: ix (sarebbe andato altrettanto bene ir, ic o meglio indice_riga, indice_colonna) e raffiniamo l’algoritmo che produce la tabella della moltiplicazione: def matprod(mod):
predisponi una matrice vuota per iy che indica ogni riga:
predisponi una riga vuota per ix che indica ogni colonna:
aggiungi alla riga: ix*iy % modaggiungi la riga alla matrice
restituisci la matrice
Prova a tradurlo in Python prima di proseguire con la lettura... E confrontalo con: def matprod(mod):
“”“Produce la tabellina della molt. dei numeri Zmod. Metodo che utilizza l’iterazione for.”“” mat=[] for iy in range(mod):
riga=[] for ix in range(mod):
riga.append(ix*iy%mod)mat.append(riga)
return mat
Aggiungendo in fondo al programma le righe seguenti: def main():
printmat(matprod(12)) print
if __name__==”__main__”: main() ed eseguendo il programma, si dovrebbe ottenere quanto voluto. Cambiando l’argomento passato alla funzione si ottengono le tabelline della moltiplicazione delle diverse classi di resto modulo enne. Scrivere un programma che funziona è il primo passo. Il secondo è sistemare il codice in modo che sia più efficiente o più leggibile. Passiamo alla seconda fase. Il secondo ciclo for, quello più interno, produce una lista. Python ha un meccanismo di costruzione di liste (detto list comprehension) che permette di riassumere tutte le informazioni contenute nelle 4 righe:
riga=[] for ix in range(mod):
riga.append(ix*iy%mod)mat.append(riga)
- in un’unica riga:
- mat.append([ix*iy%mod for ix in range(mod)])
Chi programma Python ritiene che questo modo di programmare sia più “Pitonico”, più semplice e comprensibile. Ovviamente bisogna farci un po’ l’abitudine, come in tutte le cose. La funzione allora diventa: def matprod(mod):
“”“Produce la tabellina della molt. dei numeri Zmod. Metodo che usa l’iterazione for e la costr. di liste.”“” mat=[] for iy in range(mod):
mat.append([ix*iy%mod for ix in range(mod)])return mat
A questo punto i più scaltri avranno riconosciuto che il ciclo for, e l’istruzione che la precede, serve per costruire una lista, possiamo applicare ancora il meccanismo della list comprehension ed ottenere una funzione costituita da una sola riga: def matprod(mod):
“”“Produce la tabellina della molt. dei numeri Zmod. Metodo che usa la costruzione di liste.”“” return [[ix*iy%mod for ix in range(mod)] for iy in
range(mod)]
Un codice più compatto, spesso è più semplice da verificare e da correggere, ma son si deve mai sacrificare la chiarezza e la leggibilità per la sintesi: nella scala dei valori, la sintesi è importante, ma la leggibilità lo è di più!
Riassumendo Posso memorizzare una matrice rettangolare sotto forma di lista di liste. Posso scrivere una funzione che stampi in modo ordinato una matrice. Usando l’operatore “%” posso calcolare il resto di una divisione. In Python la costruzione di liste (list comprehension) permette di sostituire un ciclo for sintetizzando 4 righe in una.