I need to convert a number (in decimal form) that is between 1 to 4999 to Roman Numeral Form. However, though the code I have is kinda working, its only outputting the thousand digit, not anything less or any part thats less.

def int2roman(number):
    numerals={1:"I", 4:"IV", 5:"V", 9: "IX", 10:"X", 40:"XL", 50:"L",
              90:"XC", 100:"C", 400:"CD", 500:"D", 900:"CM", 1000:"M"}
    result=""
    for value, numeral in sorted(numerals.items(), reverse=True):
        while number >= value:
            result += numeral
            number -= value
        return result
print int2roman(input("Enter a number (1 to 4999) in decimal form: "))

if I input 1994, I get M instead of the MCMXCIV I should be getting. Any corrections and explanations to my code?
Thanks :)

Dani AI

Generated

Nice catch by and on the early return. One more improvement you can make: avoid re-sorting a dict on every call and sidestep tricky subtractive logic in loops. For the 1..4999 range you can build Roman numerals with precomputed digit tables. It is fast, deterministic, and naturally enforces the standard forms (e.g., 944 -> CMXLIV, not IMXLIV).

Here is a compact, testable version that validates input and works on both Python 2 and 3:

def to_roman(n):
    if not isinstance(n, int):
        raise TypeError("n must be int")
    if n < 1 or n > 4999:
        raise ValueError("n must be in 1..4999")

    thousands = ["", "M", "MM", "MMM", "MMMM"]
    hundreds  = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]
    tens      = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]
    ones      = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]

    return (
        thousands[n // 1000] +
        hundreds[(n % 1000) // 100] +
        tens[(n % 100) // 10] +
        ones[n % 10]
    )

# quick checks
assert to_roman(4) == "IV"
assert to_roman(944) == "CMXLIV"
assert to_roman(1994) == "MCMXCIV"

I would also tweak your input handling. In Python 2, input() evaluates the text the user types; prefer raw_input() and cast to int. A cross-version pattern is:

try:
    n = int(raw_input("Enter a number (1 to 4999): "))  # Py2
except NameError:
    n = int(input("Enter a number (1 to 4999): "))      # Py3
print(to_roman(n))

This keeps your logic simple and removes the need for a sorted dict loop while yielding the same correct outputs.

Recommended Answers

All 4 Replies

Any corrections and explanations to my code?

Your return statement is inside your for loop so it's exiting on the first iteration.... if you knock it back an indentation level it'll work:

>>> def int2roman(number):
...     numerals={1:"I", 4:"IV", 5:"V", 9: "IX", 10:"X", 40:"XL", 50:"L",
...               90:"XC", 100:"C", 400:"CD", 500:"D", 900:"CM", 1000:"M"}
...     result=""
...     for value, numeral in sorted(numerals.items(), reverse=True):
...         while number >= value:
...             result += numeral
...             number -= value
...     return result
...     
>>> print int2roman(input("Enter a number (1 to 4999) in decimal form: "))
Enter a number (1 to 4999) in decimal form: 1942
MCMXLII
>>> print int2roman(input("Enter a number (1 to 4999) in decimal form: "))
Enter a number (1 to 4999) in decimal form: 1994
MCMXCIV

I need to convert a number (in decimal form) that is between 1 to 4999 to Roman Numeral Form. However, though the code I have is kinda working, its only outputting the thousand digit, not anything less or any part thats less.

def int2roman(number):
    numerals={1:"I", 4:"IV", 5:"V", 9: "IX", 10:"X", 40:"XL", 50:"L",
              90:"XC", 100:"C", 400:"CD", 500:"D", 900:"CM", 1000:"M"}
    result=""
    for value, numeral in sorted(numerals.items(), reverse=True):
        while number >= value:
            result += numeral
            number -= value
        return result
print int2roman(input("Enter a number (1 to 4999) in decimal form: "))

if I input 1994, I get M instead of the MCMXCIV I should be getting. Any corrections and explanations to my code?
Thanks :)

You are almost there, your return statement needs to be outside the for loop.

def int2roman(number):
    numerals={1:"I", 4:"IV", 5:"V", 9: "IX", 10:"X", 40:"XL", 50:"L",
              90:"XC", 100:"C", 400:"CD", 500:"D", 900:"CM", 1000:"M"}
    result=""
    for value, numeral in sorted(numerals.items(), reverse=True):
        while number >= value:
            result += numeral
            number -= value
    return result

print int2roman(input("Enter a number (1 to 4999) in decimal form: "))

Sorry, didn't see Pen's early response.

I liked the Dive Into Python example, but felt it was incomplete. I recently published a different way of doing the same thing. This one defines a class (roman.Roman) so you can add and subtract roman numbers and print them out directly.

>>>import roman
>>>two = roman.Roman(2)
>>>print two + two
IV

see https://launchpad.net/romanclass

Here is a site where they do just what you are doing, the first bit talks about unit testing, just ignore that and keep going on, it shows you how to make a roman numeral converter that is almost impossible to break:
http://www.diveintopython.org/unit_testing/index.html

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.