Adding, the old-fashioned way
Python, 100
s="IVXLCDM"
r=raw_input()
a=""
i=2
u=0
for c in s:r+=u/i*c;i=7-i;u=r.count(c);a+=u%i*c
print a[::-1]
Takes one string from input (e.g. VIII + XII
or VIII + XII =
).
APL (59 56)
,/N⍴⍨¨{∨/K←⍵≥D←7⍴5 2:∇⍵+(1⌽K)-K×D⋄⍵}⊃+/(N←'MDCLXVI')∘=¨⍞
Input on one line (i.e. XII + XII
, though the +
is not necessary).
Edit: changed shift to rotate to save three characters - it only matters when the answer ≥ 5000, which should never happen as the question says the input values will always be ≤ 2000. The only effect is it now "overflows" at 5000, giving 5000=1, 5001=2, etc.
(I don't really think the Romans did it this way... APL is more something for Ancient Egyptians I think :) )
Explanation:
⍞
: get user input(N←'MDCLXVI')∘=¨
: store 'MDCLXVI' in N. Return, for each character of the input string, a vector with a 1 in the place where the character corresponds to one of 'MDCLXVI', and 0 otherwise.⊃+/
: Sum the vectors and de-encapsulate. We now have a vector with information about how many of each Roman numeral we have. I.e, if the input wasXXII XIIII
, we now have:
M D C L X V I 0 0 0 0 3 0 6
- Note that this is not converting the values.
{
...:
...⋄
...}
is a function with an if-else construct.D←7⍴5 2
:D
is the vector5 2 5 2 5 2 5
. This is how many of a Roman numeral are not allowed. I.e. if you have 5I
s, that's too many, and if you have 2V
s that's also too many. This vector also happens to be the multiplication factor for each Roman numeral, i.e. aV
is worth 5I
s and anX
is worth 2V
s.∨/K←⍵≥D
:K
is the vector where there's a 1 if we have too many Roman numerals of a certain kind.∨/
ORs this vector together.- If this vector is not all zeroes:
K×D
: Multiply K by D. This vector has zeroes where we don't have too many Roman numerals, and the amount of Roman numerals where we do.⍵+(1⌽K)
: Rotate K to the left by 1, and add it to the input. For each Roman numeral we have too many, this will add one of the next-higher one.⍵+(1⌽K)-K×D
: Subtract this from the other vector. The effect is, for example if you have 6I
s, it will add oneV
and remove 4I
s.∇
: Recurse.⋄⍵
: But ifK
was all zeroes, then ⍵ represents a valid Roman numeral, so return ⍵.N⍴⍨¨
: For each element of the resulting vector, create that many of the corresponding Roman numeral.,/
: Join these vectors together to get rid of the ugly spaces in the output.
Ruby, 85 82 characters
gets;r=0;v=5;puts"IVXLCDM".gsub(/./){|g|r+=$_.count g;t=r%v;r/=v;v^=7;g*t}.reverse
This version takes input on STDIN as a single string (e.g. XXIIII + XXXXII
) and prints output to STDOUT.
f=->*a{r=0;v=5;"IVXLCDM".gsub(/./){|g|r+=(a*'').count g;t=r%v;r/=v;v^=7;g*t}.reverse}
The second one is an implementation as a function. Takes two (or more) strings and returns the summed values. Usage:
puts f["XXIIII", "XXXXII"] # -> LXVI