Converting Roman Numerals To Decimal
I have managed to get my code to convert most Roman numerals to its appropriate decimal value. But it doesn't work for some exceptional cases. Example : XCIX
= 99
but my code prints 109
.
Here is my code.
public static int romanConvert(String roman)
{
int decimal = 0;
String romanNumeral = roman.toUpperCase();
for(int x = 0;x<romanNumeral.length();x++)
{
char convertToDecimal = roman.charAt(x);
switch (convertToDecimal)
{
case 'M':
decimal += 1000;
break;
case 'D':
decimal += 500;
break;
case 'C':
decimal += 100;
break;
case 'L':
decimal += 50;
break;
case 'X':
decimal += 10;
break;
case 'V':
decimal += 5;
break;
case 'I':
decimal += 1;
break;
}
}
if (romanNumeral.contains("IV"))
{
decimal-=2;
}
if (romanNumeral.contains("IX"))
{
decimal-=2;
}
if (romanNumeral.contains("XL"))
{
decimal-=10;
}
if (romanNumeral.contains("XC"))
{
decimal-=10;
}
if (romanNumeral.contains("CD"))
{
decimal-=100;
}
if (romanNumeral.contains("CM"))
{
decimal-=100;
}
return decimal;
}
Solution 1:
It will be good if you traverse in reverse.
public class RomanToDecimal {
public static void romanToDecimal(java.lang.String romanNumber) {
int decimal = 0;
int lastNumber = 0;
String romanNumeral = romanNumber.toUpperCase();
/* operation to be performed on upper cases even if user
enters roman values in lower case chars */
for (int x = romanNumeral.length() - 1; x >= 0 ; x--) {
char convertToDecimal = romanNumeral.charAt(x);
switch (convertToDecimal) {
case 'M':
decimal = processDecimal(1000, lastNumber, decimal);
lastNumber = 1000;
break;
case 'D':
decimal = processDecimal(500, lastNumber, decimal);
lastNumber = 500;
break;
case 'C':
decimal = processDecimal(100, lastNumber, decimal);
lastNumber = 100;
break;
case 'L':
decimal = processDecimal(50, lastNumber, decimal);
lastNumber = 50;
break;
case 'X':
decimal = processDecimal(10, lastNumber, decimal);
lastNumber = 10;
break;
case 'V':
decimal = processDecimal(5, lastNumber, decimal);
lastNumber = 5;
break;
case 'I':
decimal = processDecimal(1, lastNumber, decimal);
lastNumber = 1;
break;
}
}
System.out.println(decimal);
}
public static int processDecimal(int decimal, int lastNumber, int lastDecimal) {
if (lastNumber > decimal) {
return lastDecimal - decimal;
} else {
return lastDecimal + decimal;
}
}
public static void main(java.lang.String args[]) {
romanToDecimal("XIV");
}
}
Solution 2:
Try this - It is simple and compact and works quite smoothly:
public static int ToArabic(string number) {
if (number == string.Empty) return 0;
if (number.StartsWith("M")) return 1000 + ToArabic(number.Remove(0, 1));
if (number.StartsWith("CM")) return 900 + ToArabic(number.Remove(0, 2));
if (number.StartsWith("D")) return 500 + ToArabic(number.Remove(0, 1));
if (number.StartsWith("CD")) return 400 + ToArabic(number.Remove(0, 2));
if (number.StartsWith("C")) return 100 + ToArabic(number.Remove(0, 1));
if (number.StartsWith("XC")) return 90 + ToArabic(number.Remove(0, 2));
if (number.StartsWith("L")) return 50 + ToArabic(number.Remove(0, 1));
if (number.StartsWith("XL")) return 40 + ToArabic(number.Remove(0, 2));
if (number.StartsWith("X")) return 10 + ToArabic(number.Remove(0, 1));
if (number.StartsWith("IX")) return 9 + ToArabic(number.Remove(0, 2));
if (number.StartsWith("V")) return 5 + ToArabic(number.Remove(0, 1));
if (number.StartsWith("IV")) return 4 + ToArabic(number.Remove(0, 2));
if (number.StartsWith("I")) return 1 + ToArabic(number.Remove(0, 1));
throw new ArgumentOutOfRangeException("something bad happened");
}
Solution 3:
assuming the hash looks something like this
Hashtable<Character, Integer> ht = new Hashtable<Character, Integer>();
ht.put('i',1);
ht.put('x',10);
ht.put('c',100);
ht.put('m',1000);
ht.put('v',5);
ht.put('l',50);
ht.put('d',500);
then the logic gets pretty simple going by digit right to left
public static int rtoi(String num)
{
int intNum=0;
int prev = 0;
for(int i = num.length()-1; i>=0 ; i--)
{
int temp = ht.get(num.charAt(i));
if(temp < prev)
intNum-=temp;
else
intNum+=temp;
prev = temp;
}
return intNum;
}