Capitolo 7. Test delle unità di codice

7.1. Immergersi

Nei capitoli precedenti, ci si è “tuffati” immediatamente nell'analisi del codice, cercando poi di capirlo il più velocemente possibile. Ora che avete immagazzinato un po' di Python, faremo un passo indietro e analizzeremo ciò che si fa prima di scrivere il codice.

In questo capitolo scriveremo una serie di funzioni utili per convertire da numeri arabi a numeri romani e viceversa. Molto probabilmente avete già visto dei numeri romani, anche se spesso non li avete riconosciuti. Potete averli visti nella nota di copyright di vecchi film e spettacoli televisivi (“Copyright MCMXLVI” invece di “Copyright 1946”), oppure nelle targhe di dedica di biblioteche e università (“fondata MDCCCLXXXVIII” invece di “fondata 1888”). Potete averli visti in sommari e riferimenti bibliografici. È un sistema di rappresentare numeri che effettivamente risale all'antico Impero Romano (da cui il nome).

Nei numeri romani, ci sono sette caratteri che sono ripetuti e combinati in vari modi per rappresentare i numeri:

  1. I = 1
  2. V = 5
  3. X = 10
  4. L = 50
  5. C = 100
  6. D = 500
  7. M = 1000

Ecco alcune regole generali per costruire numeri romani:

  1. Il valore del numero è la somma dei valori dei caratteri. I è 1, II è 2, e III è 3. VI è 6 (letteralmente, “5 e 1”), VII è 7 e VIII è 8.
  2. I “caratteri di decina” (I, X, C, e M) possono esere ripetuti fino a tre volte. Alla quarta, si deve sottrarre uno dal piu vicino “carattere di quintina” (V, L, D). Non si può rappresentare 4 come IIII;, lo si deve rappresentare con IV (“1 in meno di 5”). 40 è scritto come XL, 41 come XLI, 42 come XLII, 43 come XLIII ed infine 44 come XLIV (“10 in meno di 50, più uno in meno di 5”).
  3. Similmente, arrivati al 9, si deve sottrarre dal carattere di decina immediatamente superiore: 8 è VIII, ma 9 è IX (“uno in meno di dieci”), non VIIII (giacché il carattere I non può essere ripetuto quattro volte). 90 è XC, 900 è CM.
  4. I caratteri di quintina non possono essere ripetuti. 10 è sempre rappresentato come X, mai come VV. 100 è sempre C, mai LL.
  5. I numeri romani sono sempre scritti dal più grande al più piccolo e letti da sinistra a destra. per cui l'ordine dei caratteri è molto importante. DC è 600; CD è un numero completamente diverso (400, “100 meno di 500”). CI è 101; IC non è neppure un numero romano valido (perché non si può sottrarre 1 direttamente da 100; 99 si deve scrivere XCIX, “10 in meno di 100 e poi 1 in meno di 10”).

Queste regole conducono ad alcune interessanti osservazioni:

  1. C'è solo un modo corretto di rappresentare una quantità come numero romano.
  2. Il viceversa è anche vero: se una sequenza di caratteri è un valido numero romano, essa rappresenta una quantità univoca (i.e. può essere letto in una sola maniera)
  3. C'è un numero finito di numeri arabi che possono essere espressi come numeri romani, specificatamente da 1 a 3999. I romani avevano diversi modi di esprimere quantità più grandi, per esempio mettendo una barra su un numero per indicare che la sua quantità doveva essere moltiplicata per 1000, ma non tratteremo questi casi. Per lo scopo di questo capitolo, i numerali romani vanno da 1 a 3999.
  4. Non c'è modo di rappresentare lo 0 in numeri romani (Incredibilmente, gli antichi romani non avevano il concetto di 0 come numero. I numeri servivano a contare quello che si aveva; come si fa a contare quello che non si ha?).
  5. Non c'è modo di rappresentare quantità negative in numeri romani.
  6. Non c'è modo di rappresentare decimali o frazioni con i numeri romani.

Dato tutto questo, cosa si può chiedere ad una libreria di funzioni per convertire da numeri romani a numeri arabi e viceversa?

roman.py requisiti

  1. La funzione toRoman dovrebbe restituire la rappresentazione in numeri romani di qualsiasi numero arabo da 1 a 3999.
  2. La funzione toRoman dovrebbe andare in errore per un intero fuori dall'intervallo da 1 a 3999.
  3. La funzione toRoman dovrebbe andare in errore con un numero non intero.
  4. La funzione fromRoman dovrebbe accettare in input un valido numero romano e restituire il numero arabo corrispondente.
  5. La funzione fromRoman dovrebbe andare in errore con un numero romano non valido.
  6. Se si prende un numero arabo, lo si converte in numero romano e poi lo si riconverte in numero romano, si dovrebbe riavere il numero di partenza. Vale a dire fromRoman(toRoman(n)) == n per tutti i numeri da 1 a 3999.
  7. la funzione toRoman dovrebbe sempre restituire un numero romano formato da lettere maiuscole.
  8. La funzione fromRoman dovrebbe accettare solamente numeri romani (i.e. dovrebbe andare in errore con un input espresso a lettere minuscole).

Ulteriori letture

  • Questo sito fornisce ulteriori informazioni sui numeri romani, incluso un affascinante resoconto su come i Romani ed altre civiltà li usavano nella vita reale (breve resoconto: in modo approssimativo ed inconsistente).