Reputation: 65
I'm trying to write a function in Octave to convert roman numerals into decimal numbers.
What I have so far has two major problems:
1) It will only work for roman numerals up to 6 letters in length
2) The answer is only correct if each letter is smaller than the previous. ie it will not compute (IV) correctly as 4, but incorrectly as 6.
I need to somehow fix both of these problems. I have a strong suspicion that my approach to the problem is wrong and that there is an altogether more efficient way of doing this.
Anyway, if the problem interests you and/or you know of a good way to do this, any help is much appreciated.
function roman2num(s)
decimal = [1000, 500, 100, 50, 10, 5, 1];
roman = ["M", "D", "C", "L", "X", "V", "I"];
num = 0;
for i = 1:7
if strcmp(s(1), roman(i))
num += decimal(i);
break
end
end
if length(s) >= 2
for i = 1:7
if strcmp(s(2), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 3
for i = 1:7
if strcmp(s(3), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 4
for i = 1:7
if strcmp(s(4), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 5
for i = 1:7
if strcmp(s(5), roman(i))
num += decimal(i);
break
end
end
end
if length(s) >= 6
for i = 1:7
if strcmp(s(6), roman(i))
num += decimal(i);
break
end
end
end
num
end
Upvotes: 3
Views: 407
Reputation: 22274
As far as I can tell the only rule you need to worry about is determining if the letter constitutes an "add" or "subtract" operation. For some letter, we only subtract it if the first non-equal letter to the right represents a greater value.
For example in 'IIV'
The first non-equal letter to the right of both I
's is V
so we subtract 2 and add 5 for the V
since it has no letters to the right.
Implementing this rule in MATLAB is fairly straightforward.
function num = roman2num(s)
decimal = [1000, 500, 100, 50, 10, 5, 1];
roman = ['M', 'D', 'C', 'L', 'X', 'V', 'I'];
tokens = arrayfun(@(x) decimal(find(roman==x,1)), char(s));
num = tokens(end);
for idx = 1:numel(tokens)-1
val = tokens(idx);
ridx = find(tokens(idx+1:end) ~= val, 1);
if ~isempty(ridx) && tokens(ridx + idx) > val
num = num - val;
else
num = num + val;
end
end
I tested using all the numerals between 1 and 3333.
Upvotes: 5