1. Introduzione
Gli antichi romani svilupparono il proprio sistema numerico chiamato numeri romani. Il sistema utilizza lettere con valori diversi per rappresentare i numeri. I numeri romani sono ancora usati oggi in alcune applicazioni minori.
In questo tutorial, implementeremo semplici convertitori che trasformeranno i numeri da un sistema all'altro.
2. Numeri romani
Nel sistema romano, abbiamo 7 simboli che rappresentano i numeri :
- I rappresenta 1
- V rappresenta 5
- X rappresenta 10
- L rappresenta 50
- C rappresenta 100
- D rappresenta 500
- M rappresenta 1000
In origine, le persone rappresentavano un 4 con IIII o 40 con XXXX. Questo può essere abbastanza scomodo da leggere. È anche facile scambiare quattro simboli uno accanto all'altro per tre simboli.
I numeri romani usano la notazione sottrattiva per evitare tali errori. Invece di dire quattro per uno (IIII), si può dire che è uno in meno di cinque (IV).
Quanto è importante dal nostro punto di vista? È importante perché invece di aggiungere semplicemente numeri simbolo per simbolo, potrebbe essere necessario controllare il simbolo successivo per determinare se il numero deve essere aggiunto o sottratto.
3. Modello
Definiamo un enum per rappresentare i numeri romani:
enum RomanNumeral { I(1), IV(4), V(5), IX(9), X(10), XL(40), L(50), XC(90), C(100), CD(400), D(500), CM(900), M(1000); private int value; RomanNumeral(int value) { this.value = value; } public int getValue() { return value; } public static List getReverseSortedValues() { return Arrays.stream(values()) .sorted(Comparator.comparing((RomanNumeral e) -> e.value).reversed()) .collect(Collectors.toList()); } }
Si noti che abbiamo definito simboli aggiuntivi per aiutare con la notazione sottrattiva. Abbiamo anche definito un metodo aggiuntivo denominato getReverseSortedValues () .
Questo metodo ci permetterà di recuperare esplicitamente i numeri romani definiti in ordine decrescente di valori.
4. Dal romano all'arabo
I numeri romani possono rappresentare solo numeri interi compresi tra 1 e 4000 . Possiamo utilizzare il seguente algoritmo per convertire un numero romano in un numero arabo (iterando i simboli in ordine inverso da M a I ):
LET numeral be the input String representing an Roman Numeral LET symbol be initialy set to RomanNumeral.values()[0] WHILE numeral.length > 0: IF numeral starts with symbol's name: add symbol's value to the result remove the symbol's name from the numeral's beginning ELSE: set symbol to the next symbol
4.1. Implementazione
Successivamente, possiamo implementare l'algoritmo in Java:
public static int romanToArabic(String input) { String romanNumeral = input.toUpperCase(); int result = 0; List romanNumerals = RomanNumeral.getReverseSortedValues(); int i = 0; while ((romanNumeral.length() > 0) && (i 0) { throw new IllegalArgumentException(input + " cannot be converted to a Roman Numeral"); } return result; }
4.2. Test
Infine, possiamo testare l'implementazione:
@Test public void given2018Roman_WhenConvertingToArabic_ThenReturn2018() { String roman2018 = "MMXVIII"; int result = RomanArabicConverter.romanToArabic(roman2018); assertThat(result).isEqualTo(2018); }
5. Dall'arabo al romano
Possiamo usare il seguente algoritmo per convertire da numeri arabi a numeri romani (iterando i simboli in ordine inverso da M a I ):
LET number be an integer between 1 and 4000 LET symbol be RomanNumeral.values()[0] LET result be an empty String WHILE number > 0: IF symbol's value <= number: append the result with the symbol's name subtract symbol's value from number ELSE: pick the next symbol
5.1. Implementazione
Successivamente, possiamo ora implementare l'algoritmo:
public static String arabicToRoman(int number) { if ((number 4000)) { throw new IllegalArgumentException(number + " is not in range (0,4000]"); } List romanNumerals = RomanNumeral.getReverseSortedValues(); int i = 0; StringBuilder sb = new StringBuilder(); while ((number > 0) && (i < romanNumerals.size())) { RomanNumeral currentSymbol = romanNumerals.get(i); if (currentSymbol.getValue() <= number) { sb.append(currentSymbol.name()); number -= currentSymbol.getValue(); } else { i++; } } return sb.toString(); }
5.2. Test
Infine, possiamo testare l'implementazione:
@Test public void given1999Arabic_WhenConvertingToRoman_ThenReturnMCMXCIX() { int arabic1999 = 1999; String result = RomanArabicConverter.arabicToRoman(arabic1999); assertThat(result).isEqualTo("MCMXCIX"); }
6. Conclusione
In questo rapido articolo, abbiamo mostrato come convertire tra numeri romani e arabi.
Abbiamo usato un'enumerazione per rappresentare l'insieme di numeri romani e abbiamo creato una classe di utilità per eseguire le conversioni.
L'implementazione completa e tutti i test possono essere trovati su GitHub.