[Question]
  [
Create a basic calculator for Roman numerals.
### Requirements
* Supports `+`,`-`,`*`,`/`
* Input and output should expect only one subtractor prefix per symbol (i.e. 3 can't be `IIV` because there are two `I`'s before `V`)
* Handling of the subtraction principle in input and output must at minimum support modern standard conventions, in which only powers of ten are subtracted from larger numbers (e.g. `I`,`X`,`C` are required subtractors but not `V`,`L`,`D`) and subtraction is never done from a number more than 10x the subtractor (e.g. `IX` must be supported but `IC` is not required).
* Input and output should be left to right in order of value, starting with the largest (i.e. 19 = `XIX` not `IXX`, 10 is larger than 9)
* Left to right, no operator precedence, as if you were using a hand calculator.
* Supports whole positive numbers input/output between 1-4999 (no need for V̅)
* No libraries that do roman numeral conversion for you
### For you to decide
* Case sensitivity
* Spaces or no spaces on input
* What happens if you get a decimal output. Truncate, no answer, error, etc..
* What to do for output that you can't handle. Negatives or numbers to large to be printed.
* Whether to support a more liberal use of the subtraction principle than the minimum requirement.
### Extra Credit
* **-50** - Handle up to 99999 or larger. Symbols **must** include a [vinculum](http://en.wikipedia.org/wiki/Vinculum_(symbol)#Roman_numerals)
Sample input/output
```
XIX + LXXX                 (19+80)
XCIX
XCIX + I / L * D + IV      (99+1/50*500+4)
MIV
```
The shortest code wins.
  
[Answer]
# JavaScript (ES6), 238
```
c=s=>{X={M:1e3,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1}
n=eval('W='+s.replace(/[\w]+/g,n=>(o=0,n.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g,d=>o+=X[d]),
o+';W=W')));o='';for(i in X)while(n>=X[i])o+=i,n-=X[i];return o}
```
Usage:
```
c("XIX + LXXX")
> "XCIX"
c('XCIX + I / L * D + IV')
> "MIV"
```
Annotated version:
```
/**
 * Process basic calculation for roman numerals.
 * 
 * @param {String} s The calculation to perform
 * @return {String} The result in roman numerals
 */
c = s => {
  // Create a lookup table.
  X = {
    M: 1e3, CM: 900, D: 500, CD: 400, C: 100, XC: 90, 
    L: 50,  XL: 40,  X: 10,  IX: 9,   V: 5,   IV: 4, I: 1
  };
  // Do the calculation.
  // 
  // The evaluated string is instrumented to as below:
  //   99+1/50*500+4 -> W=99;W=W+1;W=W/50;W=W*500;W=W+4;W=W
  //                 -> 1004
  n = eval('W=' + s.replace(
    // Match all roman numerals.
    /[\w]+/g,
    // Convert the roman number into an integer.
    n => (
      o = 0,
      n.replace(
        /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g,
        d => o += X[d]
      ),
      // Instrument number to operate left-side operations.
      o + ';W=W'
    )
  ));
  // Convert the result into roman numerals.
  o = '';
  for (i in X)
    while (n >= X[i])
      o += i,
      n -= X[i];
  // Return calculation result.
  return o
}
```
[Answer]
## 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](http://sqlfiddle.com/#!6/d41d8/15047)
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?
[Answer]
# [APL (Dyalog Unicode 18.0)](https://www.dyalog.com/), 187 − 50 = 137 [bytes](https://codegolf.meta.stackexchange.com/a/9429/43319 "When can APL characters be counted as 1 byte each?") ([SBCS](https://github.com/abrudz/SBCS ".dyalog files using a single byte character set"))
Full program using stdin/stdout. Requires 0-based indexing and space(s) between symbols and numbers.
```
d←,∘⌊⍨'IVXLCD'
'[a-z]'⎕R('\u&',⎕UCS 773)⊢d[∊(2×⌽⍳≢r)+{⍵=⍛⌽⍺0/⍨⍺×⍛⍮⍵-1}⌿0 5⊤1+⍎¨r←⍕⍎∊'\w+'⎕R{⍕(×\1,11⍴5 2)[d⍳⍵.Match](⊣+.×¯1*2</,)0}'(.)\pM'⎕R'\l1'⌽'-' '\*' '/' '\S+'⎕S'-⍨' '×' '÷⍨' '&'⊢⍞]
```
[Try it online!](https://tio.run/##VVBNa8JAEL3nV2wvbmISNRbx0p7iZSFeKg0LxoM00hakBrH0C4@2NrjSi6RQ6MH24Kk9tFIolIK5@ivmj6STiJoOw@7bNy9vZtL02rp71Wx3jvXWZa915rbcCMaT0w7cPhQkGN55kYtQg@EjjHwQM8psbpkVKtF6U79uUBQfyNQ5z1AN4aFZI@XyrgL@1K3D0JeLYQCjHxAfcD/tKuoNiPk@iKeE@y7k0RBv1CAl3rCoG30Y/RZICfxXQwUxXsy62B/EBDEaUudCTXqi00QOA8fQDAPEZ4kUlbob9xHzXLXZOzppyOC/qLkwWLwb2eJeXlMKfSrnFMerJgbUaRsU56A6JdTJ4pGPQS2xr1E93pXQMIiPr9UjQ3EvEM@NCH9MRJLwJM44UYnFOZc2lJlwjOSJRbKkEmN7W@WcMaQttv2CLQerjKVrnK6i3ty8Y1PzH1NZDsx1WssBT6W9tltlxcSIp@U2w9j2SNlvIccVWDKtnZLaZOcP "APL (Dyalog Unicode) – Try It Online")
* Full support for [vinculum](https://en.wikipedia.org/wiki/Roman_numerals#Vinculum), so 1000 is written as `I̅` (`M` is a modern addition)
* Handles all positive results until 899999
* Allows non-standard input, including, e.g. purely additive notation and too large/small subtractors
* Includes support for factorial ! (and actually a bunch of other operations)
[Answer]
# Javascript - ~~482~~ 476 characters
```
String.prototype.m=String.prototype.replace;eval("function r(a){return a>999?'Mk1e3j899?'CMk900j499?'Dk500j399?'CDk400j99?'Ck100j89?'XCk90j49?'Lk50j39?'XLk40j9?'Xk10j8?'IX':a>4?'Vk5j3?'IV':a>0?'Ik1):''}".m(/k/g,"'+r(a-").m(/j/g,"):a>"));s=prompt();h=s.match(/\w+/gi);for(k in h)s=s.m(h[k],eval(eval("'0'+h[k].m(/IVu4pIXu9pXLu40pXCu90pCDu400pCMu900pMu1000pDu500pCu100pLu50pXu10pVu5pIu1')".m(/u/g,"/g,'+").m(/p/g,"').m(/")))+")");for(k in h)s="("+s;alert(r(Math.floor(eval(s))))
```
The sample input/output works:
```
XIX + LXXX -> XCIX
XCIX + I / L * D + IV -> MIV
```
It badly handles large numbers too:
```
MMM+MMM -> MMMMMM
M*C -> MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
```
And it accepts, but does not requires, spaces too.
But, since I was golfing it has some problems:
* It does not validates if the input is well-formed. If the input is not well-formed, the behaviour is undefined (and in practice it is very bizarre and strange).
* It truncates fraction numbers on output (but it is able to do intermediate calculations with them).
* It really abuses the eval function.
* It does not attempt to handle negative numbers.
* It is case-sensitive.
This alternative version handles numbers over 5000 upto 99999, but it has ~~600~~ ~~598~~ 584 characters:
```
String.prototype.m=String.prototype.replace;eval("function r(a){return a>8zz?'XqCqk9e4j4zz?'Lqk5e4j3zz?'XqLqk4e4jzz?'Xqk1e4j89z?'IqXqk9e3j49z?'Vqk5e3j9z?'Mk1e3j8z?'CMk900j4z?'Dk500j3z?'CDk400jz?'Ck100j89?'XCk90j49?'Lk50j39?'XLk40j9?'Xk10j8?'IX':a>4?'Vk5j3?'IV':a>0?'Ik1):''}".m(/k/g,"'+r(a-").m(/j/g,"):a>").m(/q/g,"\u0305").m(/z/g,"99"));s=prompt();h=s.match(/\w+/gi);for(k in h)s=s.m(h[k],eval(eval("'0'+h[k].m(/IVu4pIXu9pXLu40pXCu90pCDu400pCMu900pMu1000pDu500pCu100pLu50pXu10pVu5pIu1')".m(/u/g,"/g,'+").m(/p/g,"').m(/")))+")");for(k in h)s="("+s;console.log(r(Math.floor(eval(s))))
```
[Answer]
## Javascript ~~479~~ ~~361~~ ~~348~~ ~~278~~ 253
303 characters - 50 for supporting numbers up to 1 million, complete with vinculum support:
```
function p(s){s=s[r](/(^|[*\/+-])/g,"0;s$1=");for(i in v){f=R("\\b"+i);while(f.test(s))s=s[r](f,v[i]+"+")}eval(s+"0");h="";for(i in v)while(s>=v[i]){h+=i;s-=v[i]}return h}v={M̅:1e6,D̅:5e5,C̅:1e5,L̅:5e4,X̅:1e4,V̅:5e3,M:1e3,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1};r="replace";R=RegExp
```
Usage: `p(text)`, e.g., `p('XIX + LXXX')` returns `XCIX`.
Code with explanatory comments:
```
// Array mapping characters to values
v={M¯:1e6,D¯:5e5,C¯:1e5,L¯:5e4,X¯:1e4,V¯:5e3,M:1e3,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1};
// Shortcut for String.replace
r='replace';
R=RegExp;
// The heart of the program
function p(s) {
    // Replace operators with ";s+=", ";s-=", and so on
    s=s[r](/(^|[*\/+-])/g,'0;s$1=');
    // Loop over the character map and replace all letters with numbers
    for(i in v){
        f=R('\\b'+i);
        while(f.test(s))
            s=s[r](f, v[i]+'+')
    }
    eval(s+'0');
    // Set up our return string
    h='';
    // Replace digits with characters
    for(i in v)
        while(s>=v[i]) {
            h+=i;
            s-=v[i];
        }
    return h;
}
```
This works for the given samples and for all others I have tried. Examples:
```
XIX + LXXX = XCIX
XCIX + I / L * D + IV = MIV
XL + IX/VII + II * XIX = CLXXI
CD + C + XL + X + I = DLI
M̅ + I = M̅I
MMMM + M = V̅
```
[Answer]
## Ruby 2.1, 353 (and *many* other iterations), 295 - 50 = 245
The vinculum handling adds ~23 characters.
This handles "IL" or "VM" in the input, and fails without error on negatives (goes to high ints) or decimals (truncates), or any spaces. Now also handles a negative first number (though if the total is negative, it still fails poorly). Also fails poorly if you start with \* or / or if the result is 4 million or larger.
Uses Object#send for "hand-calculator" functionality.
```
m=%w{I V X L C D M V̅ X̅ L̅ C̅ D̅ M̅};n=m.zip((0..12).map{|v|(v%2*4+1)*10**(v/2)}).to_h
d=0
gets.scan(/([-+*\/])?([A-Z̅]+)/){|o,l|f=t=0
l.scan(/.̅?/){t-=2*f if f<v=n[$&]
t+=f=v}
d=d.send o||:+,t}
7.downto(1){|v|z=10**v
y=(d%z)*10/z
q,w,e=m[v*2-2,3]
$><<(y>8?q+e : y<4?q*y : y<5?q+w : w+q*(y-5))}
```
Ungolfed:
```
m=%w{I V X L C D M V̅ X̅ L̅ C̅ D̅ M̅} # roman numerals
n=m.zip((0..12).map{|v|(v%2*4+1)*10**(v/2)}).to_h # map symbols to values
d=0
gets. # get input and...
  scan(/([-+*\/])?([A-Z̅]+)/) { |l,o|  # for each optional operator plus number
    f=t=0
    l.scan(/.̅?/){                           # read the number in one letter at a time
      t -= 2 * f if f < (v=n[$&])           # if the number's greater than the prev, subtract the prev twice since you already added it
      t += (f = v)                          # add this, and set prev to this number
    }
    d = d.send((o || :+), t)                # now that we've built our number, "o" it to the running total (default to +)
}
7.upto(1) { |v|                        # We now print the output string from left to right
  z = 10**v                            # z = [10, 100, 1000, etc.]
  y = (d%z)*10/z                       # if d is 167 and z is 100, y = 67/10 = 6 
  q,w,e = m[v*2-2,3]                   # q,w,e = X, L, C
  $><< (                               # print: 
    y>8 ? q+e :                        # if y==9,    XC
      y<4 ? q*y :                      # if y<4,     X*y
        y>3 ? q+w :                    # if y==4,    XL
          q*(y-5)                      # else,       L + X*(y-5)
  )
}
```
[Answer]
# Python 2 - ~~427~~ ~~418~~ ~~404~~ ~~401~~ ~~396~~ ~~395~~ 392 characters
Reads from standard input. It only handles uppercase (could make it case-insensitive at the cost of 8 extra characters) and requires spaces. Does no validation--I haven't tested to see how it breaks in various cases. It does, however, handle numbers like VC = 95.
```
N=['?M','DC','LX','VI'];t=0;o='+'
for q in raw_input().split():
 if q in"+-*/":o=q;continue
 n=s=0;X=1
 for l in q:
  x=''.join(N).find(l);v=(5-x%2*4)*10**(3-x/2)
  if X<x:n+=s;s=v;X=x
  elif X>x:n+=v-s;s=0
  else:n+=v+s;s=0
 exec"t"+o+"=n+s"
r=t/1000*'M'
for p,d in enumerate("%04d"%(t%1e3)):
 i="49".find(d);g=N[p]
 if i<0:
  if'4'<d:r+=g[0]
  r+=int(d)%5*g[1]
 else:r+=g[1]+N[p-i][i]
print r
```
And the ungolfed version:
```
# Numerals grouped by powers of 10
N = ['?M','DC','LX','VI']
# Start with zero plus whatever the first number is
t = 0
o = '+'
for q in raw_input().split():
    if q in "+-*/":
        # An operator; store it and skip to the next entry
        o = q
        continue
    # n holds the converted Roman numeral, s is a temp storage variable
    n = s = 0
    # X stores our current index moving left-to-right in the string '?MDCLXVI'
    X = 1
    for l in q:
        # x is the index of the current letter in '?MDCLXVI'
        x = ''.join(N).find(l)
        # Calculate the value of this letter based on x
        v = (5 - x%2 * 4) * 10 ** (3 - x/2)
        if X < x:
            # We're moving forward in the list, e.g. CX
            n += s      # Add in any previously-stored value
            s = v       # Store this value in case we have something like CXL
            X = x       # Advance the index
        elif X > x:
            # Moving backward, e.g. XC
            n += v - s  # Add the current value and subtract the stored one
            s=0
        else:
            # Same index as before, e.g. XX
            n += v + s  # Add the current value and any stored one
            s = 0
    # Update total using operator and value (including leftover stored value
    # if any)
    exec "t" + o + "=n+s"
# Now convert the answer back to Roman numerals
# Special-case the thousands digit
r = t / 1000 * 'M'
# Loop over the number mod 1000, padded with zeroes to four digits (to make
# the indices come out right)
for p, d in enumerate("%04d" % (t % 1e3)):
    i = "49".find(d)
    g = N[p]
    if i < 0:
        # i == -1, thus d isn't '4' or '9'
        if '4' < d:
            # >= 5, so add the 5's letter
            r += g[0]
        # ... plus (digit % 5) copies of the 1's letter
        r += int(d) % 5 * g[1]
    else:
        # If it's a 4 or 9, add the 1's letter plus the appropriate
        # larger-valued letter
        r += g[1] + N[p-i][i]
print r
```
I have a feeling Perl would have been better, but I don't know enough of it. For a first stab at code golf, though, I feel pretty good about this.
[Answer]
# PHP — ~~549~~ ~~525~~ ~~524~~ 520 bytes
Nothing too innovative: normalizes the operators to ensure left to right precedence, converts Roman to decimal, runs `eval` on the statement, e.g. *XCIX + I / L \* D + IV* is converted to something like *return (((((+90 +9) + (+1)) / (+50)) \* (+500)) + (+4));*, then converts decimal back to Roman.
* final results are truncated
* answers less than 1 come back blank
* results are undefined if given incorrect input
```
$f='str_replace';$g='str_split';$c=array('M'=>1e3,'CM'=>900,'D'=>500,'CD'=>400,'C'=>100,'XC'=>90,'L'=>50,'XL'=>40,'X'=>10,'IX'=>9,'V'=>5,'IV'=>4,'I'=>1);$j='['.$f(array('+','-','*','/'),array('])+[','])-[','])*[','])/['), $argv[1]).'])';$j=str_repeat('(',substr_count($j,')')).$j;$j=$f('[','(',$j);$j=$f(']',')',$j);foreach($g('IVIXXLXCCDCM',2)as$w)$j=$f($w,'+'.$c[$w],$j);foreach($g('IVXLCDM')as$w)$j=$f($w,'+'.$c[$w],$j);$k=eval('return '.$j.';');$l='';foreach($c as$a=>$b){while($k>=$b){$l.=$a;$k-=$b;}}print$l."\n";
```
e.g.
```
$ php roman.php 'XCIX + I / L * D + IV' — test case
MIV                                     — 1004
$ php roman.php 'XXXII * LIX'           — 32 × 59
MDCCCLXXXVIII                           — 1888
```
[Answer]
# Python - 446 bytes
This could be improved considerably. I felt I had to take the first swing using Python. It does 3 things on the first pass
1. tokenizes the numbers and operators
2. evaluates the numbers, and enlarges the symbol table `x` to include all possible combinations encountered (even if they are not used). For example, while `XIX` is being lexed, the partial values of `"X":10`, `"XI":11` and `"XIX":19` are added to the symbol table
3. inserts nested parens to enforce left-to-right evaluation
At the end, it calls `eval` on the original string (except with added parens) and gives it the symbol table.
Then I just pasted in a known solution to convert integer to Roman, since I had worked on this long enough... please feel free to improve so that I learn something new :)
```
m=zip((1000,900,500,400,100,90,50,40,10,9,5,4,1),
('M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'))
def doit(s):
 x={'M':1e3,'D':500,'C':100,'L':50,'X':10,'V':5,'I':1};y=[];z='';a='0';s='+'+s
 for c in s.upper():
  if c in x:
   z+=c;y.append(x[c])
   if len(y)>1and y[-1]>y[-2]:y[-2]*=-1
   x[z]=sum(y)
  elif c in"+/*-":a='('+a+z+')'+c;y=[];z=''
 a+=z;i=eval(a,x);r = ''
 for n,c in m:d=int(i/n);r+=c*d;i-=n*d
 return r
        
print doit("XIX + LXXX")
print doit("XCIX + I / L * D + IV")
```
[Answer]
## MATLAB - 543 bytes
I tried not to look at others' answers before working on my own, although my approach ended up similar regardless. I use a regular expression to match word characters (the numbers) or operators, which splits up the input into a cell array alternating between numbers and operators. I then replace the roman numerals in every other cell with itself and a plus sign, using order of precedence on the groups to ensure proper grouping. I define variables with the same name as each split group and use an eval statement on the split roman numeral to convert it to a value with a closing parenthese. I then concatenate the whole list of values and operators with proper opening parentheses to ensure strict left-to-right order of operations. I then deconstruct the resulting number digit-by-digit and convert it to the proper roman numeral based on its "power".
```
function n=m(I)
e=regexp(I,'\w+|[\+\-\*\/]','match');CM=900;XC=90;IX=9;CD=400;XL=40;IV=4;M=1e3;D=500;C=100;L=50;X=10;V=5;I=1;e(1:2:end)=cellfun(@(x) [num2str(evalin('caller',[x '0'])) ')'],regexprep(e(1:2:end),'CM|XC|IX|CD|XL|IV|.?','$0+'),'un',0);S=num2str(eval(strcat(repmat('(',1,(length(e)+1)/2),e{:})));n='';I='IXCM';V='VLD ';l=length(S);for i=1:l
p=l-i+1;a=eval(S(i));if p>3
n=repmat('M',1,a);continue
end
b=a>4;switch a
case 4
n=[n I(p) V(p)];case 9
n=[n I(p:p+1)];otherwise
n=[n repmat(V(p),1,b) repmat(I(p),1,a-5*b)];end
end
```
ungolfed:
```
function n=m(I)
e=regexp(I,'\w+|[\+\-\*\/]','match'); % match roman numerals or operators
CM=900;XC=90;IX=9; % nines
CD=400;XL=40;IV=4; % fours
M=1e3;D=500;C=100; % single character numbers (ones and fives)
L=50;X=10;V=5;I=1;
e(1:2:end)=cellfun(@(x) [num2str(evalin('caller',[x '0'])) ')'],... % Evaluate each group and add a parenthesis
                   regexprep(e(1:2:end),'CM|XC|IX|CD|XL|IV|.?','$0+'),'un',0); % replace each group or single digit with itself and a +
S=num2str(eval(strcat(repmat('(',1,(length(e)+1)/2),e{:}))); % concatenate the split string and evaluate with proper parentheses for left-to-right Order of Operations
n='';         % initialize output 
I='IXCM';     % Define ones and fives
V='VLD ';
l=length(S);
for i=1:l
p=l-i+1;
a=eval(S(i));
if p>3              % if the number has 4 or more digits, just add a bunch of Ms
n=repmat('M',1,a);
continue
end
b=a>4;
switch a
case 4
n=[n I(p) V(p)]; % If the digit is 4, add the proper 1 and 5
case 9
n=[n I(p:p+1)]; % If the digit is 9, add the correct 9 group
otherwise
n=[n repmat(V(p),1,b) repmat(I(p),1,a-5*b)]; % Add a 5 if the digit is greater than 4. add 1s for either the digit value (1,2,3) or the value - 5 (6,7,8)
end
end
```
]