Roman numeral conversion

B

Brian Tickler

First time poster here...

I realize that rubyquiz.com is no longer really active, but some of the
code there is still used by people googling for example code (roman
numeral conversion in my case for a class I am taking), and I wanted to
point out that many of the solutions listed for quiz #22 are evaluating
roman to arabic numerals incorrectly.

If you run many of the solutions, especially the ones that use this
table:

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

...and then you try to evaluate the string value XD (for example), it
will convert this string to 510. This should not happen; XD is not a
legal roman numeral, DX would be 510, and CDXC would be 490. The
problem seems to be that in roman to arabic numeral conversion, the
solutions just add the raw values together. This means that converters
using this kind of conversion will accept any combination of roman
numeral values from the table above...regardless of order.

A crazier example:

If you evaluate XIV, you get 14, by finding X and then IV in the table
above and then adding their corresponding values together.

If you put in IXIVI, it will *also* evaluate to 14 by adding IX + IV + I
and accept it as a valid roman numeral.

I don't have a solution yet, but I thought I would at least point this
out in case someone is adding a to_roman method to Integer or something
and wants it to be 100% robust.
 
F

Fabian Streitel

[Note: parts of this message were removed to make it a legal post.]

how about that one (it's a little longish):

class String
def to_roman
str = self.downcase
raise SyntaxError, "Not a roman numeral" unless str =~
/^[mdclxvi]+$/
raise SyntaxError, "Not a roman numeral" if
%w{iiii vv xxxx ll cccc dd}.any? { |x| str.include?(x) }
str.tr!("ivxlcdm", "0123456") # translate into numbers
level, last, deviated, ret = 7, 0, false, 0
table = [1,5,10,50,100,500,1000] # the translation table
str.each_char do |char|
num = char.to_i
if num > level # means a deviation
raise SyntaxError, "Not a roman numeral" if deviated or
not # no double deviation
%w{01 02 23 24 45 46}.include?("#{last}#{num}") #
only allowed deviations
ret -= table[last]*2 # remedy deviation
level = last-1 # don't allow IXI or IXV etc.
deviated = true
else
deviated = false
level = num # don't allow MLM etc.
end
ret += table[num]
last = num
end
ret
end
end

fulfills all your examples, but i dunno if it's correct. would be great if
someone
could test this (let alone improve it).

What it checks for:
* only [ivxlcdm] allowed
* ixc may each only occur max. 3 times in a row
* vld may each only occur max once in a row
* when dropping to a certain level, only the following sequences may rise
above that level: cm cd xc xl ix iv
* and not twice in a row, so ixc is not legal
* and after that, the level drops to the smaller char, so ixivi is not
legal

...and then you try to evaluate the string value XD (for example), it
 
B

Brian Tickler

Cool, I will give this a shot, but while I know enough about Roman
numerals, I am not an expert by any means, so I will leave any
"approvals" to someone that knows everything about them :).
 
T

trans

First time poster here...

I realize that rubyquiz.com is no longer really active, but some of the
code there is still used by people googling for example code (roman
numeral conversion in my case for a class I am taking), and I wanted to
point out that many of the solutions listed for quiz #22 are evaluating
roman to arabic numerals incorrectly.

If you run many of the solutions, especially the ones that use this
table:

=A0 =A0 =A0 =A0 [ 1000, 'M' =A0],
=A0 =A0 =A0 =A0 [ =A0900, 'CM' ],
=A0 =A0 =A0 =A0 [ =A0500, 'D' =A0],
=A0 =A0 =A0 =A0 [ =A0400, 'CD' ],
=A0 =A0 =A0 =A0 [ =A0100, 'C' =A0],
=A0 =A0 =A0 =A0 [ =A0 90, 'XC' ],
=A0 =A0 =A0 =A0 [ =A0 50, 'L' =A0],
=A0 =A0 =A0 =A0 [ =A0 40, 'XL' ],
=A0 =A0 =A0 =A0 [ =A0 10, 'X' =A0],
=A0 =A0 =A0 =A0 [ =A0 =A09, 'IX' ],
=A0 =A0 =A0 =A0 [ =A0 =A05, 'V' =A0],
=A0 =A0 =A0 =A0 [ =A0 =A04, 'IV' ],
=A0 =A0 =A0 =A0 [ =A0 =A01, 'I' =A0]
=A0 =A0 =A0 =A0 ]

...and then you try to evaluate the string value XD (for example), it
will convert this string to 510. =A0This should not happen; XD is not a
legal roman numeral, DX would be 510, and CDXC would be 490. =A0The
problem seems to be that in roman to arabic numeral conversion, the
solutions just add the raw values together. =A0This means that converters
using this kind of conversion will accept any combination of roman
numeral values from the table above...regardless of order.

A crazier example:

If you evaluate XIV, you get 14, by finding X and then IV in the table
above and then adding their corresponding values together.

If you put in IXIVI, it will *also* evaluate to 14 by adding IX + IV + I
and accept it as a valid roman numeral.

I don't have a solution yet, but I thought I would at least point this
out in case someone is adding a to_roman method to Integer or something
and wants it to be 100% robust.

english/roman.rb checks out.

T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top