Skip to content

Programming a roman to decimal converter using Python

This week while I was solving a Project Euler problem, I came up with a simple roman to decimals converter. I will show its implementation in Python in this post.

Roman numerals

Romans represented numbers using numerals as follows:

I - 1
V - 5
X - 10
L - 50
C - 100
D - 500
M - 1000

We will consider only three rules to convert them to decimal numbers.

  1. Numerals must be written in decreasing order.
    For example, MD is a valid representation of 1500 while DM isn’t.
  2. The total value is obtained by adding each successive decreasing numeral to the right.
    For example, VIII represents 8 (5 + 1 + 1 + 1). See the numerals value decrease from right to left.
  3. As an exception to rule 1., it’s possible to decrease I, X and C from the two next numerals with greater values. To do it, we write the lower numeral left of the greater one.
    For example, we can decrease X from both L and C:
    XL = 40 (50 – 10) and XC = 90 (100 – 10)
    However, we can’t subtract X from other greater numerals:
    XM = 990 (1000 – 10), isn’t a valid roman numeral.

A roman to decimal converter

For our converter, we will take advantage that roman numerals are written in decreasing order by analyzing it starting from the end. Then we will add the corresponding decimal value of each numeral using a Python dictionary.

We will consider the subtraction of numerals, such as I in IV, by the fact that the left hand side numeral is lower than the right hand side one (I < V). In this case, I in IV will be parsed as -1 instead of +1.

The dictionary used to convert roman numerals do decimals:

roman_dict ={'I': 1, 'V': 5,
             'X': 10, 'L': 50,
             'C': 100, 'D': 500,
             'M': 1000}

See that roman_dict['D'] will return 500 and so on.

The parsing will be implemented using function decimal:

def decimal(roman):
    """
    roman: a string or roman numerals.
    Returns the equivalent in decimal numbers (int).
    """
    global roman_dict
    # Analyze string backwards
    roman_back = list(reversed(list(roman)))  
    value = 0
    # To keep track of order
    right_val = roman_dict[roman_back[0]]  
    for numeral in roman_back:
        left_val = roman_dict[numeral]
        # Check for subtraction
        if left_val < right_val:
           value -= left_val
        else:
            value += left_val
        right_val = left_val
    return value

As it was stated before, all we are doing is getting the decimal value of each numeral:

left_val = roman_dict[numeral]

And then verifying if we have to add or subtract the value of that numeral by checking if the left value is lower than the right one:

if left_val < right_val:
...

Let’s check it works with a rather complicated roman numeral:

>>> decimal('MCDXLIX')
1449

It works!

Finally, we have to remark that we’re assuming that the roman numerals are written correctly. This converter will retun a value for any possible combination of roman numerals, even invalid ones such as IXM.

Published inProgramming
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments