⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

;Task: Create a function that takes a Roman numeral as its argument and returns its value as a numeric decimal integer.

You don't need to validate the form of the Roman numeral.

Modern Roman numerals are written by expressing each decimal digit of the number to be encoded separately,

starting with the leftmost decimal digit and skipping any '''0'''s (zeroes).

'''1990''' is rendered as '''MCMXC''' (1000 = M, 900 = CM, 90 = XC) and

'''2008''' is rendered as '''MMVIII''' (2000 = MM, 8 = VIII).

The Roman numeral for '''1666''', '''MDCLXVI''', uses each letter in descending order.

## 360 Assembly

```*        Roman numerals Decode -   17/04/2019
B      72(R15)            skip savearea
DC     17F'0'             savearea
SAVE   (14,12)            save previous context
LA     R6,1               i=1
DO WHILE=(C,R6,LE,=A(NV))   do i=1 to hbound(vals)
LR     R1,R6                i
SLA    R1,3                 ~
LA     R4,VALS-L'VALS(R1)   @vals(i)
MVC    X,0(R4)              x=vals(i)
SR     R9,R9                prev=0
ST     R9,Y                 y=0
LA     R7,L'X               j=1
DO WHILE=(C,R7,GE,=A(1))      do j=length(x) to 1 by -1
LA     R4,X-1                 @x
AR     R4,R7                  +j
MVC    C,0(R4)                c=substr(x,j,1)
IF   CLI,C,NE,C' ' THEN         if c^=' ' then
SR     R1,R1                  r1=0
LA     R2,1                   k=1
DO WHILE=(C,R2,LE,=A(L'ROMAN))   do k=1 to length(roman)
LA     R3,ROMAN-1               @roman
AR     R3,R2                    +k
IF   CLC,0(L'C,R3),EQ,C THEN      if substr(roman,k,1)=c
LR     R1,R2                      index=k
B      REINDEX                    leave k
ENDIF    ,                        endif
LA     R2,1(R2)                 k=k+1
ENDDO    ,                      enddo k
REINDEX  EQU    *                      r1=index(roman,c)
SLA    R1,2                   ~
L      R8,DECIM-4(R1)         n=decim(index(roman,c))
IF    CR,R8,LT,R9 THEN          if n<prev then
LCR    R8,R8                    n=-n
ENDIF    ,                      endif
L      R2,Y                     y
AR     R2,R8                    +n
ST     R2,Y                     y=y+n
LR     R9,R8                    prev=n
ENDIF    ,                      endif
BCTR   R7,0                   j--
ENDDO    ,                    enddo j
MVC    PG(8),X              x
L      R1,Y                 y
XDECO  R1,XDEC              edit y
MVC    PG+12(4),XDEC+8      output y
XPRNT  PG,L'PG              print buffer
LA     R6,1(R6)             i++
ENDDO    ,                  enddo i
L      R13,4(0,R13)       restore previous savearea pointer
RETURN (14,12),RC=0       restore registers from calling sav
NV       EQU    (X-VALS)/L'VALS
ROMAN    DC     CL7'MDCLXVI'
DECIM    DC     F'1000',F'500',F'100',F'50',F'10',F'5',F'1'
VALS     DC     CL8'XIV',CL8'CMI',CL8'MIC',CL8'MCMXC',CL8'MDCLXVI'
DC     CL8'MMVIII',CL8'MMXIX',CL8'MMMCMXCV'
X        DS     CL(L'VALS)
Y        DS     F
C        DS     CL1
PG       DC     CL80'........ -> ....'
XDEC     DS     CL12
REGEQU
```

{{out}}

```
XIV      ->   14
CMI      ->  901
MIC      -> 1099
MCMXC    -> 1990
MDCLXVI  -> 1666
MMVIII   -> 2008
MMXIX    -> 2019
MMMCMXCV -> 3995

```

```Pragma Ada_2012;
Pragma Assertion_Policy( Check );

With
Unchecked_Conversion,

Procedure Test_Roman_Numerals is

-- We create an enumeration of valid characters, note that they are
-- character-literals, this is so that we can use literal-strings,
-- and that their size is that of Integer.
Type Roman_Digits is ('I', 'V', 'X', 'L', 'C', 'D', 'M' )
with Size => Integer'Size;

-- We use a representation-clause ensure the proper integral-value
-- of each individual character.
For Roman_Digits use
(
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000
);

-- To convert a Roman_Digit to an integer, we now only need to
-- read its value as an integer.
Function Convert is new Unchecked_Conversion
(	Source => Roman_Digits,	Target => Integer );

-- Romena_Numeral is a string of Roman_Digit.
Type Roman_Numeral is array (Positive range <>) of Roman_Digits;

-- The Numeral_List type is used herein only for testing
-- and verification-data.
Type Numeral_List is array (Positive range <>) of
not null access Roman_Numeral;

-- The Test_Cases subtype ensures that Test_Data and Validation_Data
-- both contain the same number of elements, and that the indecies
-- are the same; essentially the same as:
--
--    pragma Assert( Test_Data'Length = Validation_Data'Length
--		   AND Test_Data'First = Validation_Data'First);

subtype Test_Cases is Positive range 1..14;

Test_Data : constant Numeral_List(Test_Cases):=
(
New Roman_Numeral'("III"),	-- 3
New Roman_Numeral'("XXX"),	-- 30
New Roman_Numeral'("CCC"),	-- 300
New Roman_Numeral'("MMM"),	-- 3000

New Roman_Numeral'("VII"),	-- 7
New Roman_Numeral'("LXVI"),	-- 66
New Roman_Numeral'("CL"),	-- 150
New Roman_Numeral'("MCC"),	-- 1200

New Roman_Numeral'("IV"),	-- 4
New Roman_Numeral'("IX"),	-- 9
New Roman_Numeral'("XC"),	-- 90

New Roman_Numeral'("ICM"),	-- 901
New Roman_Numeral'("CIM"),	-- 899

New Roman_Numeral'("MDCLXVI")	-- 1666
);

Validation_Data : constant array(Test_Cases) of Natural:=
(	3, 30, 300, 3000,
7, 66, 150, 1200,
4, 9, 90,
901, 899,
1666
);

-- In Roman numerals, the subtractive form [IV = 4] was used
-- very infrequently, the most common form was the addidive
-- form [IV = 6]. (Consider military logistics and squads.)

Function Sum( Number : Roman_Numeral ) return Natural is
begin
Return Result : Natural:= 0 do
For Item of Number loop
Result:= Result + Convert( Item );
end loop;
End Return;
end Sum;

-- EVAL returns Number read in the subtractive form.
Function Eval( Number : Roman_Numeral ) return Natural is
Current : Roman_Digits:= 'I';
begin
Return Result : Natural:= 0 do
For Item of Number loop
if Current < Item then
Result:= Convert(Item) - Result;
Current:= Item;
else
Result:= Result + Convert(Item);
end if;
end loop;
End Return;
end Eval;

-- Display the given Roman_Numeral via Text_IO.
Procedure Put( S: Roman_Numeral ) is
begin
For Ch of S loop
declare
-- The 'Image attribute returns the character inside
-- single-quotes; so we select the character itself.
C : Character renames Roman_Digits'Image(Ch)(2);
begin
end;
end loop;
end;

-- This displays pass/fail dependant on the parameter.
Function PF ( Value : Boolean ) Return String is
begin
Return Result : String(1..4):= ( if Value then"pass"else"fail" );
End PF;

Begin

for Index in Test_Data'Range loop
declare
Item  : Roman_Numeral renames Test_Data(Index).all;
Value : constant Natural := Eval(Item);
begin
Put( Item );

PF( Value = Validation_Data(Index) )& ']');
end;
end loop;

End Test_Roman_Numerals;

```

{{out}}

```Starting Test:
III	=  3	[pass]
XXX	=  30	[pass]
CCC	=  300	[pass]
MMM	=  3000	[pass]
VII	=  7	[pass]
LXVI	=  66	[pass]
CL	=  150	[pass]
MCC	=  1200	[pass]
IV	=  4	[pass]
IX	=  9	[pass]
XC	=  90	[pass]
ICM	=  901	[pass]
CIM	=  899	[pass]
MDCLXVI	=  1666	[pass]
Testing complete.
```

## ALGOL 68

{{works with|ALGOL 68G|Any - tested with release 2.2.0}} Note: roman to int will handle multiple subtraction, e.g. IIIIX for 6.

```    PROC roman to int = (STRING roman) INT:
BEGIN
PROC roman digit value = (CHAR roman digit) INT:
(roman digit = "M" | 1000 |:
roman digit = "D" |  500 |:
roman digit = "C" |  100 |:
roman digit = "L" |   50 |:
roman digit = "X" |   10 |:
roman digit = "V" |    5 |:
roman digit = "I" |    1);

INT result := 0, previous value := 0, run := 0;

FOR i FROM LWB roman TO UPB roman
DO
INT value = roman digit value(roman[i]);
IF previous value = value THEN
run +:= value
ELSE
IF previous value < value THEN
result -:= run
ELSE
result +:= run
FI;
run := previous value := value
FI
OD;

result +:= run
END;

MODE TEST = STRUCT (STRING input, INT expected output);

[] TEST roman test = (
("MMXI",    2011), ("MIM",     1999),
("MCMLVI",  1956), ("MDCLXVI", 1666),
("XXCIII",    83), ("LXXIIX",    78),
("IIIIX",      6)
);

print(("Test input  Value   Got", newline, "--------------------------", newline));
FOR i FROM LWB roman test TO UPB roman test
DO
INT output = roman to int(input OF roman test[i]);
printf((\$g, n (12 - UPB input OF roman test[i]) x\$, input OF roman test[i]));
printf((\$g(5), 1x, g(5), 1x\$, expected output OF roman test[i], output));
printf((\$b("ok", "not ok"), 1l\$, output = expected output OF roman test[i]))
OD
```

## ALGOL W

```begin
% decodes a roman numeral into an integer                                %
% there must be at least one blank after the numeral                     %
% This takes a lenient view on roman numbers so e.g. IIXX is 18 - see    %
% the Discussion                                                         %
integer procedure romanToDecimal ( string(32) value roman ) ;
begin
integer   decimal, rPos, currDigit, nextDigit, seqValue;
string(1) rDigit;

% the roman number is a sequence of sequences of roman digits        %
% if the previous sequence is of higher value digits than the next,  %
%    the higher value is added to the overall value                  %
% if the previous seequence is of lower value, it is subtracted      %
% e.g. MCMLXII                                                       %
%      the sequences are M, C, M, X, II                              %

% get the value of a sequence of roman digits                        %
integer procedure getSequence ;
if rDigit = " " then begin
% end of the number                                          %
0
end
else begin
% have another sequence                                      %
integer sValue;
sValue := 0;
while roman( rPos // 1 ) = rDigit do begin
sValue := sValue + currDigit;
rPos   := rPos + 1;
end while_have_same_digit ;
% remember the next digit                                    %
rDigit     := roman( rPos // 1 );
% result is the sequence value                               %
sValue
end getSequence ;

% convert a roman digit into its decimal equivalent                  %
% an invalid digit will terminate the program, " " is 0              %
integer procedure getValue( string(1) value romanDigit ) ;
if      romanDigit = "m" or romanDigit = "M" then 1000
else if romanDigit = "d" or romanDigit = "D" then  500
else if romanDigit = "c" or romanDigit = "C" then  100
else if romanDigit = "l" or romanDigit = "L" then   50
else if romanDigit = "x" or romanDigit = "X" then   10
else if romanDigit = "v" or romanDigit = "V" then    5
else if romanDigit = "i" or romanDigit = "I" then    1
else if romanDigit = " "                     then    0
else begin
write( s_w := 0, "Invalid roman digit: """, romanDigit, """" );
assert false;
0
end getValue ;

% get the first sequence                                             %
decimal   := 0;
rPos      := 0;
rDigit    := roman( rPos // 1 );
currDigit := getValue( rDigit );
seqValue  := getSequence;

% handle the sequences                                               %
while rDigit not = " " do begin
% have another sequence                                          %
nextDigit := getValue( rDigit );
if currDigit < nextDigit
then % prev digit is lower  % decimal := decimal - seqValue
else % prev digit is higher % decimal := decimal + seqValue
;
currDigit := nextDigit;
seqValue  := getSequence;
end while_have_a_roman_digit ;

% add the final sequence                                             %
decimal + seqValue
end roman ;

% test the romanToDecimal routine                                        %

procedure testRoman ( string(32) value romanNumber ) ;
write( i_w := 5, romanNumber, romanToDecimal( romanNumber ) );

testRoman( "I"        );    testRoman( "II"       );
testRoman( "III"      );    testRoman( "IV"       );
testRoman( "V"        );    testRoman( "VI"       );
testRoman( "VII"      );    testRoman( "VIII"     );
testRoman( "IX"       );    testRoman( "IIXX"     );
testRoman( "XIX"      );    testRoman( "XX"       );
write( "..." );
testRoman( "MCMXC"    );
testRoman( "MMVIII"   );
testRoman( "MDCLXVI"  );

end.
```

{{out}}

```
I                                   1
II                                  2
III                                 3
IV                                  4
V                                   5
VI                                  6
VII                                 7
VIII                                8
IX                                  9
IIXX                               18
XIX                                19
XX                                 20
...
MCMXC                            1990
MMVIII                           2008
MDCLXVI                          1666

```

## ANTLR

[[File:Rn.PNG|left|Roman Numeral]] [[File:Hundreds.PNG|left|Roman Numeral]] [[File:H5.PNG|left|Roman Numeral]] [[File:H9.PNG|left|Roman Numeral]] [[File:Tens.PNG|left|Roman Numeral]] [[File:T5.PNG|left|Roman Numeral]] [[File:T9.PNG|left|Roman Numeral]] [[File:Units.PNG|left|Roman Numeral]] [[File:U5.PNG|left|Roman Numeral]] [[File:U9.PNG|left|Roman Numeral]]

### Java

```/* Parse Roman Numerals

Nigel Galloway March 16th., 2012
*/
grammar ParseRN ;

options {
language = Java;
}
@members {
int rnValue;
int ONE;
}

parseRN:	({rnValue = 0;} rn NEWLINE {System.out.println(\$rn.text + " = " + rnValue);})*
;

rn	:	(Thousand {rnValue += 1000;})* hundreds? tens? units?;

hundreds:	{ONE = 0;} (h9 | h5) {if (ONE > 3) System.out.println ("Too many hundreds");};
h9	:	Hundred {ONE += 1;} (FiveHund {rnValue += 400;}| Thousand {rnValue += 900;}|{rnValue += 100;} (Hundred {rnValue += 100; ONE += 1;})*);
h5	:	FiveHund {rnValue += 500;} (Hundred {rnValue += 100; ONE += 1;})*;

tens	:	{ONE = 0;} (t9 | t5) {if (ONE > 3) System.out.println ("Too many tens");};
t9	:	Ten {ONE += 1;} (Fifty {rnValue += 40;}| Hundred {rnValue += 90;}|{rnValue += 10;} (Ten {rnValue += 10; ONE += 1;})*);
t5	:	Fifty {rnValue += 50;} (Ten {rnValue += 10; ONE += 1;})*;

units	:	{ONE = 0;} (u9 | u5) {if (ONE > 3) System.out.println ("Too many ones");};
u9	:	One {ONE += 1;} (Five {rnValue += 4;}| Ten {rnValue += 9;}|{rnValue += 1;} (One {rnValue += 1; ONE += 1;})*);
u5	:	Five {rnValue += 5;} (One {rnValue += 1; ONE += 1;})*;

One	:	'I';
Five	:	'V';
Ten	:	'X';
Fifty	:	'L';
Hundred:	'C';
FiveHund:	'D';
Thousand:	'M' ;
NEWLINE:	'\r'? '\n' ;
```

Using this test data:

```
MMXI
MCMLVI
XXCIII
MCMXC
MMVIII
MDCLXVI
IIIIX
MIM
MDCLXVI
LXXIIX
M
MCXI
CMXI
MCM
MMIX
MCDXLIV
MMXII

```

Produces:

```
MMXI = 2011
MCMLVI = 1956
line 3:2 missing NEWLINE at 'C'
XX = 20
CIII = 103

```

Note that this implementation does not accept XXC as eighty. The error is detected and ANTLR attempts to continue by inserting the expected NEWLINE after XX and treating CIII as a new Number.

```
MCMXC = 1990
MMVIII = 2008
MDCLXVI = 1666
Too many ones
line 7:4 extraneous input 'X' expecting NEWLINE
IIII = 4

```

An implementation above thinks IIIIX is 6. It isn't. ANTLR detects the surfiet of 'I' reports the errors and tries to carry on.

```
line 8:2 no viable alternative at input 'M'
MIM = 1000
MDCLXVI = 1666
line 10:5 extraneous input 'X' expecting NEWLINE
LXXII = 72
M = 1000
MCXI = 1111
CMXI = 911
MCM = 1900
MMIX = 2009
MCDXLIV = 1444
MMXII = 2012

```

## AppleScript

### =isPrefixOf=

```-- romanValue :: String -> Int
on romanValue(s)
script roman
property mapping : [["M", 1000], ["CM", 900], ["D", 500], ["CD", 400], ¬
["C", 100], ["XC", 90], ["L", 50], ["XL", 40], ["X", 10], ["IX", 9], ¬
["V", 5], ["IV", 4], ["I", 1]]

-- Value of first Roman glyph + value of remaining glyphs
-- toArabic :: [Char] -> Int
on toArabic(xs)
script transcribe
-- If this glyph:value pair matches the head of the list
-- return the value and the tail of the list
-- transcribe :: (String, Number) -> Maybe (Number, [String])
on |λ|(lstPair)
set lstR to characters of (item 1 of lstPair)
if isPrefixOf(lstR, xs) then
-- Value of this matching glyph, with any remaining glyphs
{item 2 of lstPair, drop(length of lstR, xs)}
else
{}
end if
end |λ|
end script

if length of xs > 0 then
set lstParse to concatMap(transcribe, mapping)
(item 1 of lstParse) + toArabic(item 2 of lstParse)
else
0
end if
end toArabic
end script

toArabic(characters of s) of roman
end romanValue

-- TEST -----------------------------------------------------------------------
on run
map(romanValue, {"MCMXC", "MDCLXVI", "MMVIII"})

--> {1990, 1666, 2008}
end run

-- GENERIC FUNCTIONS ----------------------------------------------------------

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
set lst to {}
set lng to length of xs
tell mReturn(f)
repeat with i from 1 to lng
set lst to (lst & |λ|(item i of xs, i, xs))
end repeat
end tell
return lst
end concatMap

--  drop :: Int -> a -> a
on drop(n, a)
if n < length of a then
if class of a is text then
text (n + 1) thru -1 of a
else
items (n + 1) thru -1 of a
end if
else
{}
end if
end drop

-- isPrefixOf :: [a] -> [a] -> Bool
on isPrefixOf(xs, ys)
if length of xs = 0 then
true
else
if length of ys = 0 then
false
else
set {x, xt} to uncons(xs)
set {y, yt} to uncons(ys)
(x = y) and isPrefixOf(xt, yt)
end if
end if
end isPrefixOf

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn

-- uncons :: [a] -> Maybe (a, [a])
on uncons(xs)
if length of xs > 0 then
{item 1 of xs, rest of xs}
else
missing value
end if
end uncons
```

{{Out}}

```{1990, 1666, 2008}
```

```use framework "Foundation"

-- INTEGER VALUE OF ROMAN NUMBER STRING ---------------------------------------

-- fromRoman :: String -> Int
on fromRoman(s)
script subtractIfLower
on |λ|(rn, L)
set {r, n} to rn
if L ≥ r then  -- Digit values that increase (right to left),
{L, n + L} -- are added
else
{L, n - L} -- Digit values that go down, are subtracted.
end if
end |λ|
end script

snd(foldr(subtractIfLower, {0, 0}, map(my charVal, characters of s)))
end fromRoman

-- charVal :: Char -> Int
on charVal(C)
set V to keyValue({I:1, V:5, X:10, L:50, C:100, D:500, M:1000}, ¬
toUpper(C))
if nothing of V then
0
else
just of V
end if
end charVal

-- TEST -----------------------------------------------------------------------
on run
map(fromRoman, {"MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"})

--> {1666, 1990, 2008, 2016, 2017}
end run

-- GENERIC FUNCTIONS ----------------------------------------------------------

-- foldr :: (a -> b -> a) -> a -> [b] -> a
on foldr(f, startValue, xs)
tell mReturn(f)
set V to startValue
set lng to length of xs
repeat with I from lng to 1 by -1
set V to |λ|(V, item I of xs, I, xs)
end repeat
return V
end tell
end foldr

-- keyValue :: Record -> String -> Maybe String
on keyValue(rec, strKey)
set ca to current application
set V to (ca's NSDictionary's dictionaryWithDictionary:rec)'s objectForKey:strKey
if V is not missing value then
{nothing:false, just:item 1 of ((ca's NSArray's arrayWithObject:V) as list)}
else
{nothing:true}
end if
end keyValue

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with I from 1 to lng
set end of lst to |λ|(item I of xs, I, xs)
end repeat
return lst
end tell
end map

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn

-- snd :: (a, b) -> b
on snd(xs)
if class of xs is list and length of xs = 2 then
item 2 of xs
else
missing value
end if
end snd

-- toUpper :: String -> String
on toUpper(str)
set ca to current application
((ca's NSString's stringWithString:(str))'s ¬
uppercaseStringWithLocale:(ca's NSLocale's currentLocale())) as text
end toUpper
```

{{Out}}

```{1666, 1990, 2008, 2016, 2017}
```

## AutoHotkey

{{works with|AutoHotkey_L}}

```Roman_Decode(str){
res := 0
Loop Parse, str
{
n := {M: 1000, D:500, C:100, L:50, X:10, V:5, I:1}[A_LoopField]
If ( n > OldN ) && OldN
res -= 2*OldN
res += n, oldN := n
}
return res
}

test = MCMXC|MMVIII|MDCLXVI
Loop Parse, test, |
res .= A_LoopField "`t= " Roman_Decode(A_LoopField) "`r`n"
clipboard := res
```

{{out}}

```MCMXC	= 1990
MMVIII	= 2008
MDCLXVI	= 1666
```

## AWK

```# syntax: GAWK -f ROMAN_NUMERALS_DECODE.AWK
BEGIN {
leng = split("MCMXC MMVIII MDCLXVI",arr," ")
for (i=1; i<=leng; i++) {
n = arr[i]
printf("%s = %s\n",n,roman2arabic(n))
}
exit(0)
}
function roman2arabic(r,  a,i,p,q,u,ua,una,unr) {
r = toupper(r)
unr = "MDCLXVI" # each Roman numeral in descending order
una = "1000 500 100 50 10 5 1" # and its Arabic equivalent
split(una,ua," ")
i = split(r,u,"")
a = ua[index(unr,u[i])]
while (--i) {
p = index(unr,u[i])
q = index(unr,u[i+1])
a += ua[p] * ((p>q) ? -1 : 1)
}
return( (a>0) ? a : "" )
}
```

{{out}}

```
MCMXC = 1990
MMVIII = 2008
MDCLXVI = 1666

```

## BBC BASIC

```      PRINT "MCMXCIX", FNromandecode("MCMXCIX")
PRINT "MMXII", FNromandecode("MMXII")
PRINT "MDCLXVI", FNromandecode("MDCLXVI")
PRINT "MMMDCCCLXXXVIII", FNromandecode("MMMDCCCLXXXVIII")
END

DEF FNromandecode(roman\$)
LOCAL i%, j%, p%, n%, r%()
DIM r%(7) : r%() = 0,1,5,10,50,100,500,1000
FOR i% = LEN(roman\$) TO 1 STEP -1
j% = INSTR("IVXLCDM", MID\$(roman\$,i%,1))
IF j%=0 ERROR 100, "Invalid character"
IF j%>=p% n% += r%(j%) ELSE n% -= r%(j%)
p% = j%
NEXT
= n%
```

{{out}}

```
MCMXCIX         1999
MMXII           2012
MDCLXVI         1666
MMMDCCCLXXXVIII           3888

```

## Batch File

{{trans|Fortran}}

```@echo off
setlocal enabledelayedexpansion

::Testing...
call :toArabic MCMXC
echo MCMXC = !arabic!
call :toArabic MMVIII
echo MMVIII = !arabic!
call :toArabic MDCLXVI
echo MDCLXVI = !arabic!
call :toArabic CDXLIV
echo CDXLIV = !arabic!
call :toArabic XCIX
echo XCIX = !arabic!
pause>nul
exit/b 0

::The "function"...
:toArabic
set roman=%1
set arabic=
set lastval=
%== Alternative for counting the string length ==%
set leng=-1
for /l %%. in (0,1,1000) do set/a leng+=1&if "!roman:~%%.,1!"=="" goto break
:break
set /a last=!leng!-1
for /l %%i in (!last!,-1,0) do (
set n=0
if /i "!roman:~%%i,1!"=="M" set n=1000
if /i "!roman:~%%i,1!"=="D" set n=500
if /i "!roman:~%%i,1!"=="C" set n=100
if /i "!roman:~%%i,1!"=="L" set n=50
if /i "!roman:~%%i,1!"=="X" set n=10
if /i "!roman:~%%i,1!"=="V" set n=5
if /i "!roman:~%%i,1!"=="I" set n=1

if !n! lss !lastval! (
set /a arabic-=n
) else (
set /a arabic+=n
)
set lastval=!n!
)
goto :EOF
```

{{Out}}

```MCMXC = 1990
MMVIII = 2008
MDCLXVI = 1666
CDXLIV = 444
XCIX = 99
```

## Bracmat

{{trans|Icon and Unicon}}

```  ( unroman
=   nbr,lastVal,val
.     0:?nbr:?lastVal
& @( low\$!arg
:   ?
%@?L
( ?
&     (m.1000)
(d.500)
(c.100)
(l.50)
(x.10)
(v.5)
(i.1)
: ? (!L.?val) ?
&     (!val:~>!lastVal|!val+-2*!lastVal)
+ !nbr
: ?nbr
& !val:?lastVal
& ~
)
)
| !nbr
)
&     (M.1000)
(MCXI.1111)
(CMXI.911)
(MCM.1900)
(MCMXC.1990)
(MMVIII.2008)
(MMIX.2009)
(MCDXLIV.1444)
(MDCLXVI.1666)
(MMXII.2012)
: ?years
& (test=.out\$(!arg unroman\$!arg))
& (   !years
: ? (?L.?D) (?&test\$!L&~)
| done
);
```

{{out}}

```M 1000
MCXI 1111
CMXI 911
MCM 1900
MCMXC 1990
MMVIII 2008
MMIX 2009
MCDXLIV 1444
MDCLXVI 1666
MMXII 2012
```

## C

Note: the code deliberately did not distinguish between "I", "J" or "U", "V", doing what Romans did for fun.

```#include <stdio.h>

int digits[26] = { 0, 0, 100, 500, 0, 0, 0, 0, 1, 1, 0, 50, 1000, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 10, 0, 0 };

/* assuming ASCII, do upper case and get index in alphabet. could also be
inline int VALUE(char x) { return digits [ (~0x20 & x) - 'A' ]; }
if you think macros are evil */
#define VALUE(x) digits[(~0x20 & (x)) - 'A']

int decode(const char * roman)
{
const char *bigger;
int current;
int arabic = 0;
while (*roman != '\0') {
current = VALUE(*roman);
/*      if (!current) return -1;
note: -1 can be used as error code; Romans didn't even have zero
*/
bigger = roman;

/* look for a larger digit, like IV or XM */
while (VALUE(*bigger) <= current && *++bigger != '\0');

if (*bigger == '\0')
arabic += current;
else {
arabic += VALUE(*bigger);
while (roman < bigger)
arabic -= VALUE(* (roman++) );
}

roman ++;
}
return arabic;
}

int main()
{
const char * romans[] = { "MCmxC", "MMVIII", "MDClXVI", "MCXLUJ" };
int i;

for (i = 0; i < 4; i++)
printf("%s\t%d\n", romans[i], decode(romans[i]));

return 0;
}
```

## C++

```
#include <exception>
#include <string>
#include <iostream>
using namespace std;

namespace Roman
{
int ToInt(char c)
{
switch (c)
{
case 'I':  return 1;
case 'V':  return 5;
case 'X':  return 10;
case 'L':  return 50;
case 'C':  return 100;
case 'D':  return 500;
case 'M':  return 1000;
}
throw exception("Invalid character");
}

int ToInt(const string& s)
{
int retval = 0, pvs = 0;
for (auto pc = s.rbegin(); pc != s.rend(); ++pc)
{
const int inc = ToInt(*pc);
retval += inc < pvs ? -inc : inc;
pvs = inc;
}
return retval;
}
}

int main(int argc, char* argv[])
{
try
{
cout << "MCMXC = " << Roman::ToInt("MCMXC") << "\n";
cout << "MMVIII = " << Roman::ToInt("MMVIII") << "\n";
cout << "MDCLXVI = " << Roman::ToInt("MDCLXVI") << "\n";
}
catch (exception& e)
{
cerr << e.what();
return -1;
}
return 0;
}

```

{{out}}

```MCMXC = 1990
MMVIII = 2008
MDCLXVI = 1666```
```MMMCMXCIX=3999
LXXIIX=invalid
MMXVII=2017
LXXIX=79
CXCIX=199
MCMXCIX=1999
MMMDCCCLXXXVIII=3888
CMXI=911
M=1000
MCDXLIV=1444
CCCC=invalid
IXV=invalid
XLIXL=invalid
LXXIIX=invalid
IVM=invalid
XXXIX=39
XXXX=invalid
XIXX=invalid
IVI=invalid
XLIX=49
XCIX=99
XCIV=94
XLVIII=48

```