Roman Numeral to Hindu and Vice Versa

This is a sample problem from the NCC ICT Proficiency Reviewer which I took last year:

Write a program that will convert a Roman number into its equivalent Hindu Arabic number, and vice versa. The program should ask the user what type of number to convert (Roman or Hindu Arabic).

Hindu to Roman is relatively straightforward: match it to the largest equivalent Roman numeral and subtract until you reach zero. Roman to Hindu gets a bit trickier, since you have to read non-numeric values and determine their equivalent normal value. See, it's only in those special instances (XC, XL, IV, IX, etc) that a lower value comes before a higher one (reading left to right). Everything else, it's VIII, XI, LX and such -- in those cases it's simple addition. But in the case of 4's and 9's, the left value is subtracted from the right value, so in IV, 1 is subtracted from 5 to produce 4, in XL 10 is subtracted from 50 to produce 40, and so on.

The following is the Python code for that implementation:

def hindu_to_roman(num):
	if not 0 < num < 4000:
		return "Invalid input."

	temp = num
	roman = ""
	i = 0
	romans = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
	numbers = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
	while temp > 0:
		if temp < numbers[i]:
			i += 1
		elif temp >= numbers[i]:
			roman += romans[i]
			temp -= numbers[i]

	return roman

def roman_to_hindu(num):
	romans = ["M", "D", "C", "L", "X", "V", "I"]
	numbers = [1000, 500, 100, 50, 10, 5, 1]
	total = 0
	temp = num.upper()

	for i in range(len(temp)):
		try:
			currval = numbers[romans.index(temp[i])]
			if i < len(temp) - 1:
				nextval = numbers[romans.index(temp[i+1])]
				if currval < nextval:
					currval *= -1

			total += currval
		except:
			total = "Invalid input."
	return total

def main():
	choice = input("[1] Roman to Hindu\n[2] Hindu to Roman\n[3] Quit\nChoose: ")
	while choice != 3:
		if choice == 1:
			num = raw_input("Enter a valid Roman numeral. Please? : ")
			res = roman_to_hindu(num)
			print res
		elif choice == 2:
			num = input("Enter a positive integer less than 4000: ")
			res = hindu_to_roman(num)
			print res
		elif choice == 3:
			pass
		else:
			print "\nInvalid choice.\n"

		choice = input("\n[1] Roman to Hindu\n[2] Hindu to Roman\n[3] Quit\nChoose: ")

main()

Some notes: 3,999 is traditionally the largest Roman number, following that you can only repeat a letter three times: MMMCMXCIX. Removing the check for it -- if not 0 < num < 4000 -- allows you to output larger values with a lot of repeating M's.

This was originally posted at the Far From Neutral blog — No Fun with Roman Numerals