Welcome, guest | Sign In | My Account | Store | Cart
```"""
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()
```