T-SQL, 1974 - 50 = 1924 bytes
I know that golfing in SQL is equivalent to playing 18 holes with nothing but a sand wedge, but I relished the challenge of this one, and I think I managed to do a few interesting things methodologically.
This does support the vinculum for both input and output. I adopted the convention of using a trailing tilde to represent it , so V~ is 5000, X~ is 10000, etc. It should also handle outputs up to 399,999 according to standard modern Roman numeral usage. After that, it will do partially non-standard Roman encoding of anything in INT's supported range.
Because it's all integer math, any non-integer results are implicitly rounded.
DECLARE @i VARCHAR(MAX)
SET @i='I+V*IV+IX*MXLVII+X~C~DCCVI'
SELECT @i
DECLARE @t TABLE(i INT IDENTITY,n VARCHAR(4),v INT)
DECLARE @u TABLE(n VARCHAR(50),v INT)
DECLARE @o TABLE(n INT IDENTITY,v CHAR(1))
DECLARE @r TABLE(n INT IDENTITY,v INT,r VARCHAR(MAX))
DECLARE @s TABLE(v INT,s VARCHAR(MAX))
DECLARE @p INT,@x VARCHAR(4000)='SELECT ',@j INT=1,@m INT,@y INT,@z VARCHAR(2),@q VARCHAR(50)='+-/*~]%'
INSERT @t(n,v) VALUES('i',1),('iv',4),('v',5),('ix',9),('x',10),('xl',50),('l',50),('xc',90),('c',100),('cd',400),('d',500),('cm',900),('m',1000),('mv~',4000),('v~',5000),('mx~',9000),('x~',10000),('x~l~',40000),('l~',50000),('x~c~',90000),('c~',100000)
INSERT @u VALUES('%i[^i'+@q,-2),('%v[^vi'+@q,-10),('%x[^xvi'+@q,-20),('%l[^lxvi'+@q,-100),('%c[^clxvi'+@q,-200),('%d[^dclxvi'+@q,-1000),('%mx~%',-2010),('%x~l~%',-20060),('%x~c~%',-20110)
WHILE PATINDEX('%[+-/*]%', @i)!=0
BEGIN
SET @p=PATINDEX('%[+-/*]%', @i)
INSERT @o(v) SELECT SUBSTRING(@i,@p,1)
INSERT @r(r) SELECT SUBSTRING(@i,1,@p-1)
SET @i=STUFF(@i,1,@p,'')
END
INSERT @r(r) SELECT @i
UPDATE r SET v=COALESCE(q.v,0) FROM @r r LEFT JOIN (SELECT r.r,SUM(u.v)v FROM @u u JOIN @r r ON r.r LIKE u.n GROUP BY r.r)q ON q.r=r.r
UPDATE r SET v=r.v+q.v FROM @r r JOIN (SELECT r.n,r.r,SUM((LEN(r.r)-LEN(REPLACE(r.r,t.n,REPLICATE(' ',LEN(t.n)-1))))*t.v) v FROM @r r JOIN @t t ON CHARINDEX(t.n,r.r) != 0 AND (LEN(t.n)=1 OR (LEN(t.n)=2 AND RIGHT(t.n,1)='~')) GROUP BY r.n,r.r) q ON q.r=r.r AND q.n = r.n
SELECT @m=MAX(n) FROM @o
SELECT @x=@x+REPLICATE('(',@m)+CAST(v AS VARCHAR) FROM @r WHERE n=1
WHILE @j<=@m
BEGIN
SELECT @x=@x+o.v+CAST(r.v AS VARCHAR)+')'
FROM @o o JOIN @r r ON r.n=o.n+1 WHERE o.n=@j
SET @j=@j+1
END
INSERT @s(v,s) EXEC(@x+',''''')
UPDATE @s SET s=s+CAST(v AS VARCHAR(MAX))+' = '
SET @j=21
WHILE @j>0
BEGIN
SELECT @y=v,@z=n FROM @t WHERE i = @j
WHILE @y<=(SELECT v FROM @s)
BEGIN
UPDATE @s SET v=v-@y,s=s+@z
END
SET @j=@j-1
END
SELECT @x+' = '+UPPER(s) FROM @s
I'm still tinkering with a set-based solution to replace some of the WHILE looping that might whittle down the byte count and be a more elegant example of idiomatic SQL. There are also some bytes to be gained by reducing use of table aliases to a bare minimum. But as it's essentially un-winnable in this language, I'm mostly just here to show off my Don Quixote outfit. :)
SELECT @i at the top repeats the input:
I+V*IV+IX*MXLVII+X~C~DCCVI
And the SELECT at the end returns:
SELECT (((((1+5)*4)+9)*1047)+90706) = 125257 = C~X~X~V~CCLVII
And you can test it yourself at this SQLFiddle
And I will be returning to add some commentary on how it works, because why post an obviously losing answer if you're not going to exploit it for educational value?
(99+1/50*500+4)=113 with my calculator (and to formula precedence)... If you want something else have to add parenthesis... – RosLuP – 2017-11-01T21:09:59.670
(99+1/50*500+4) = (99+10+4) = 113, but your sample input/output says it is MIV (1004). – Victor Stafusa – 2014-02-12T15:05:22.157
1@Victor - strict left to right operation - no precedence rules - so 99 + 1 / 50 * 500 + 4 should be calculated as ((((99 + 1) / 50) * 500) + 4) – None – 2014-02-12T15:09:12.047
Is handling numbers like
IM = 999
required? – Kendall Frey – 2014-02-12T18:45:54.670@KendallFrey I would expect you could input
IM
. Whether the output isIM
orCMXCIX
for 999 is up to you. Both fit the requirements. – Danny – 2014-02-12T18:51:05.8902IM is non-standard for modern Roman numeral usage. Typically it's only the 4s and 9s of each order of magnitude (4, 9, 40, 90, 400, 900, etc.) that are done by subtraction. For 1999, MCMXCIX would be canonical, not MIM...watch the credits of any film from that year. Otherwise, where does it end? Are we also expected to support other non-standard subtractions like VL for 45? Would IC with a vinculum over the C have to be supported as 99999 for the bonus? – Jonathan Van Matre – 2014-02-12T23:11:58.017
@JonathanVanMatre Can you think of a way to edit the question such to define the standard way of writing Roman numerals? I am not sure I understand the standard way enough to define it in the requirements (but it looks like most if not all of the answers follow it) – Danny – 2014-02-13T03:54:14.603
I've proposed an edit accordingly. – Jonathan Van Matre – 2014-02-13T05:50:29.533