Convertendo entre algarismos romanos e árabes em Java
1. Introdução
Os romanos antigos desenvolveram seu próprio sistema numérico chamado numeração romana. O sistema usa letras com valores diferentes para representar números. Os algarismos romanos ainda são usados hoje em algumas aplicações menores.
Neste tutorial, implementaremossimple converters that will transform numbers from one system to the other.
2. Números romanos
No sistema romano, temos7 symbols that represent numbers:
-
I representa 1
-
V representa 5
-
X representa 10
-
L representa 50
-
C representa 100
-
D representa 500
-
M representa 1000
Originalmente, as pessoas costumavam representar um 4 com IIII ou 40 com XXXX. Isso pode ser bastante desconfortável de ler. Também é fácil confundir quatro símbolos lado a lado com três símbolos.
Roman numerals use subtractive notation para evitar tais erros. Em vez de dizerfour times one (IIII), pode-se dizer que éone less than five (IV).
Como isso é importante do nosso ponto de vista? É importante porque, em vez de simplesmente adicionar números, símbolo por símbolo, podemos precisar verificar o próximo símbolo para determinar se o número deve ser adicionado ou subtraído.
3. Modelo
Vamos definir um enum para representar os algarismos romanos:
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());
}
}
Observe que definimos símbolos adicionais para ajudar na notação subtrativa. Também definimos um método adicional denominadogetReverseSortedValues().
Este método nos permitirá recuperar explicitamente os números romanos definidos em ordem decrescente.
4. Romano para Árabe
Roman numerals can only represent integers between 1 to 4000. Podemos usar o seguinte algoritmo para converter um algarismo romano em um número arábico (iterando por meio de símbolos na ordem inversa deM aI):
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. Implementação
Em seguida, podemos implementar o algoritmo em 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 < romanNumerals.size())) {
RomanNumeral symbol = romanNumerals.get(i);
if (romanNumeral.startsWith(symbol.name())) {
result += symbol.getValue();
romanNumeral = romanNumeral.substring(symbol.name().length());
} else {
i++;
}
}
if (romanNumeral.length() > 0) {
throw new IllegalArgumentException(input + " cannot be converted to a Roman Numeral");
}
return result;
}
4.2. Test
Por fim, podemos testar a implementação:
@Test
public void given2018Roman_WhenConvertingToArabic_ThenReturn2018() {
String roman2018 = "MMXVIII";
int result = RomanArabicConverter.romanToArabic(roman2018);
assertThat(result).isEqualTo(2018);
}
5. Árabe para romano
Podemos usar o seguinte algoritmo para converter algarismos arábicos em romanos (iterando por meio de símbolos na ordem inversa deM paraI):
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. Implementação
Em seguida, agora podemos implementar o algoritmo:
public static String arabicToRoman(int number) {
if ((number <= 0) || (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
Por fim, podemos testar a implementação:
@Test
public void given1999Arabic_WhenConvertingToRoman_ThenReturnMCMXCIX() {
int arabic1999 = 1999;
String result = RomanArabicConverter.arabicToRoman(arabic1999);
assertThat(result).isEqualTo("MCMXCIX");
}
6. Conclusão
Neste artigo rápido, mostramos como converter entre algarismos romanos e arábicos.
Usamos umenum para representar o conjunto de algarismos romanos e criamos uma classe de utilitário para realizar as conversões.
A implementação completa e todos os testes podem ser encontradosover on GitHub.