Conversione tra numeri romani e arabi in Java

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.