Welcome, guest | Sign In | My Account | Store | Cart

Convert decimals to Roman numerials. I use a recursive algorithm here since it reflects the thinking clearly in code. A non-recursive algothrithm can be done as well.

Python, 90 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
"""
Victor Yang, pythonrocks@yahoo.com

Convert decimals to Roman numerials.
I use a recursive algorithm here since it reflects the thinking clearly in code.
A non-recursive algothrithm can be done as well.

usage: python roman.py 
It will run the test case against toRoman function
"""

import sys
import unittest


# these two lists serves as building blocks to construt any number
# just like coin denominations.
# 1000->"M", 900->"CM", 500->"D"...keep on going 
decimalDens=[1000,900,500,400,100,90,50,40,10,9,5,4,1]
romanDens=["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]


def toRoman(dec):
	"""
	Perform sanity check on decimal and throws exceptions when necessary
	"""		
        if dec <=0:
	  raise ValueError, "It must be a positive"
         # to avoid MMMM
	elif dec>=4000:  
	  raise ValueError, "It must be lower than MMMM(4000)"
  
	return decToRoman(dec,"",decimalDens,romanDens)

def decToRoman(num,s,decs,romans):
	"""
	  convert a Decimal number to Roman numeral recursively
	  num: the decimal number
	  s: the roman numerial string
	  decs: current list of decimal denomination
	  romans: current list of roman denomination
	"""
	if decs:
	  if (num < decs[0]):
	    # deal with the rest denomination
	    return decToRoman(num,s,decs[1:],romans[1:])		  
	  else:
	    # deduce this denomation till num<desc[0]
	    return decToRoman(num-decs[0],s+romans[0],decs,romans)	  
	else:
	  # we run out of denomination, we are done 
	  return s


class DecToRomanTest(unittest.TestCase):

	def setUp(self):
		print '\nset up'
	def tearDown(self):
		print 'tear down'
	
	def testDens(self):
		
	   for i in range(len(decimalDens)):
		r=toRoman(decimalDens[i])
		self.assertEqual(r,romanDens[i])

	def testSmallest(self):
		self.assertEqual('I',toRoman(1))

	def testBiggest(self):
		self.assertEqual('MMMCMXCIX',toRoman(3999))

	def testZero(self):
		self.assertRaises(ValueError,toRoman,0)

	def testNegative(self):
		
		self.assertRaises(ValueError,toRoman,-100)


	def testMillonDollar(self):
		
		self.assertRaises(ValueError,toRoman,1000000)

		

if __name__ == "__main__":
	
	unittest.main()

Just for fun.

2 comments

Raymond Hettinger 18 years, 10 months ago  # | flag

For grins: A non-recursive version.

coding = zip(
    [1000,900,500,400,100,90,50,40,10,9,5,4,1],
    ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
)

def decToRoman(num):
    if num &lt;= 0 or num &gt;= 4000 or int(num) != num:
        raise ValueError('Input should be an integer between 1 and 3999')
    result = []
    for d, r in coding:
        while num &gt;= d:
            result.append(r)
            num -= d
    return ''.join(result)


for i in xrange(1,4000):
    print i, decToRoman(i)
greg p 16 years, 8 months ago  # | flag

Now it's Online. I made this recipe into an online utility. Check it out:

http://www.utilitymill.com/utility/Decimal_to_Roman_Numerals