Roman numerals/Decode: Difference between revisions
Add a declarative way of achieving the transformation
Not a robot (talk | contribs) (Add Modula-2) |
(Add a declarative way of achieving the transformation) |
||
(37 intermediate revisions by 20 users not shown) | |||
Line 18:
{{trans|Python}}
<
(‘XL’, 40), (‘L’, 50), (‘XC’, 90), (‘C’, 100),
(‘CD’, 400), (‘D’, 500), (‘CM’, 900), (‘M’, 1000)]
Line 31:
L(value) [‘MCMXC’, ‘MMVIII’, ‘MDCLXVI’]
print(value‘ = ’roman_value(value))</
{{out}}
Line 41:
=={{header|360 Assembly}}==
<
ROMADEC CSECT
USING ROMADEC,R13 base register
Line 108:
XDEC DS CL12
REGEQU
END ROMADEC </
{{out}}
<pre>
Line 127:
The Roman numeral must be in uppercase letters.
<
jmp test
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Line 236:
nl: db 13,10,'$'
bufdef: db 16,0
buf: ds 17</
=={{header|Action!}}==
<syntaxhighlight lang="action!">CARD FUNC DecodeRomanDigit(CHAR c)
IF c='I THEN RETURN (1)
ELSEIF c='V THEN RETURN (5)
ELSEIF c='X THEN RETURN (10)
ELSEIF c='L THEN RETURN (50)
ELSEIF c='C THEN RETURN (100)
ELSEIF c='D THEN RETURN (500)
ELSEIF c='M THEN RETURN (1000)
FI
RETURN (0)
CARD FUNC DecodeRomanNumber(CHAR ARRAY s)
CARD res,curr,prev
BYTE i
res=0 prev=0 i=s(0)
WHILE i>0
DO
curr=DecodeRomanDigit(s(i))
IF curr<prev THEN
res==-curr
ELSE
res==+curr
FI
prev=curr
i==-1
OD
RETURN (res)
PROC Test(CHAR ARRAY s)
CARD n
n=DecodeRomanNumber(s)
PrintF("%S=%U%E",s,n)
RETURN
PROC Main()
Test("MCMXC")
Test("MMVIII")
Test("MDCLXVI")
Test("MMMDCCCLXXXVIII")
Test("MMMCMXCIX")
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Roman_numerals_decode.png Screenshot from Atari 8-bit computer]
<pre>
MCMXC=1990
MMVIII=2008
MDCLXVI=1666
MMMDCCCLXXXVIII=3888
MMMCMXCIX=3999
</pre>
=={{header|Ada}}==
<
Pragma Assertion_Policy( Check );
Line 391 ⟶ 445:
Ada.Text_IO.Put_Line("Testing complete.");
End Test_Roman_Numerals;
</syntaxhighlight>
{{out}}
Line 414 ⟶ 468:
{{works with|ALGOL 68G|Any - tested with release 2.2.0}}
Note: roman to int will handle multiple subtraction, e.g. IIIIX for 6.
<
BEGIN
PROC roman digit value = (CHAR roman digit) INT:
Line 461 ⟶ 515:
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</
=={{header|ALGOL W}}==
<
% decodes a roman numeral into an integer %
% there must be at least one blank after the numeral %
Line 558 ⟶ 612:
testRoman( "MDCLXVI" );
end.</
{{out}}
<pre>
Line 593 ⟶ 647:
===Java===
<
Nigel Galloway March 16th., 2012
Line 631 ⟶ 685:
FiveHund: 'D';
Thousand: 'M' ;
NEWLINE: '\r'? '\n' ;</
Using this test data:
<pre>
Line 687 ⟶ 741:
=={{header|APL}}==
{{works with|Dyalog APL}}
<
rmn←(⎕A,⎕A,'*')[(⎕A,⎕UCS 96+⍳26)⍳⍵] ⍝ make input uppercase
dgt←↑'IVXLCDM' (1 5 10 50 100 500 1000) ⍝ values of roman digits
Line 693 ⟶ 747:
map←dgt[2;dgt[1;]⍳rmn] ⍝ map digits to values
+/map×1-2×(2</map),0 ⍝ subtractive principle
}</
{{out}}
Line 705 ⟶ 759:
(Functional ES5 version)
{{trans|Haskell}}
<syntaxhighlight lang="applescript">
------------- INTEGER VALUE OF A ROMAN STRING ------------
Line 880 ⟶ 934:
end if
end if
end uncons</
{{Out}}
<syntaxhighlight lang
====Fold right – subtracting or adding====
{{Works with|Yosemite onwards}}
{{trans|Haskell}}
<
----------- INTEGER VALUE OF ROMAN NUMBER STRING ---------
Line 996 ⟶ 1,050:
(its NSLocale's currentLocale())) as text
end tell
end toUpper</
{{Out}}
<
=={{header|
==={{header|Applesoft BASIC}}===
{{trans|BBC BASIC}}
<syntaxhighlight lang="gwbasic"> 10 LET R$ = "MCMXCIX"
20 GOSUB 100 PRINT "ROMAN NUMERALS DECODED"
30 LET R$ = "MMXII"
40 GOSUB 100
50 LET R$ = "MDCLXVI"
60 GOSUB 100
70 LET R$ = "MMMDCCCLXXXVIII"
80 GOSUB 100
90 END
100 PRINT M$R$,
110 LET M$ = CHR$ (13)
120 GOSUB 150"ROMAN NUMERALS DECODE given R$"
130 PRINT N;
140 RETURN
150 IF NOT C THEN GOSUB 250INITIALIZE
160 LET J = 0
170 LET N = 0
180 FOR I = LEN (R$) TO 1 STEP - 1
190 LET P = J
200 FOR J = 1 TO C
210 IF MID$ (C$,J,1) < > MID$ (R$,I,1) THEN NEXT J
220 IF J < = C THEN N = N + R(J) * ((J > = P) * 2 - 1)
230 NEXT I
240 RETURN
250 READ C$
260 LET C = LEN (C$)
270 DIM R(C)
280 FOR I = 0 TO C
290 READ R(I)
300 NEXT I
310 RETURN
320 DATA "IVXLCDM",0,1,5,10,50,100,500,1000</syntaxhighlight>
==={{header|BASIC256}}===
<syntaxhighlight lang="freebasic">function romToDec (roman$)
num = 0
prenum = 0
for i = length(roman$) to 1 step -1
x$ = mid(roman$, i, 1)
n = 0
if x$ = "M" then n = 1000
if x$ = "D" then n = 500
if x$ = "C" then n = 100
if x$ = "L" then n = 50
if x$ = "X" then n = 10
if x$ = "V" then n = 5
if x$ = "I" then n = 1
preNum = n
next i
return num
end function
#Testing
print "MCMXCIX = "; romToDec("MCMXCIX") #1999
print "MDCLXVI = "; romToDec("MDCLXVI") #1666
print "XXV = "; romToDec("XXV") #25
print "CMLIV = "; romToDec("CMLIV") #954
print "MMXI = "; romToDec("MMXI") #2011</syntaxhighlight>
==={{header|BBC BASIC}}===
<syntaxhighlight lang="bbcbasic"> 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%</syntaxhighlight>
{{out}}
<pre>MCMXCIX 1999
MMXII 2012
MDCLXVI 1666
MMMDCCCLXXXVIII 3888</pre>
==={{header|Chipmunk Basic}}===
====Through IF-THEN statements====
{{works with|Chipmunk Basic|3.6.4}}
{{works with|Applesoft BASIC}}
{{works with|MSX_BASIC}}
{{works with|QBasic}}
<syntaxhighlight lang="qbasic">100 cls : rem 100 home for Applesoft BASIC
110 roman$ = "MCMXCIX" : print roman$,"=> "; : gosub 170 : print decimal '1999
120 roman$ = "XXV" : print roman$,"=> "; : gosub 170 : print decimal '25
130 roman$ = "CMLIV" : print roman$,"=> "; : gosub 170 : print decimal '954
140 roman$ = "MMXI" : print roman$,"=> "; : gosub 170 : print decimal '2011
150 end
160 rem Decode from roman
170 decimal = 0
180 predecimal = 0
190 for i = len(roman$) to 1 step -1
200 x$ = mid$(roman$,i,1)
210 if x$ = "M" then n = 1000 : goto 280
220 if x$ = "D" then n = 500 : goto 280
230 if x$ = "C" then n = 100 : goto 280
240 if x$ = "L" then n = 50 : goto 280
250 if x$ = "X" then n = 10 : goto 280
260 if x$ = "V" then n = 5 : goto 280
270 if x$ = "I" then n = 1
280 if n < predecimal then decimal = decimal-n
285 if n >= predecimal then decimal = decimal+n
290 predecimal = n
300 next i
310 return</syntaxhighlight>
====Through SELECT CASE statement====
{{works with|Chipmunk Basic|3.6.4}}
<syntaxhighlight lang="qbasic">100 cls
110 roman$ = "MCMXCIX" : print roman$,"=> "; : gosub 170 : print decimal '1999
120 roman$ = "XXV" : print roman$,"=> "; : gosub 170 : print decimal '25
130 roman$ = "CMLIV" : print roman$,"=> "; : gosub 170 : print decimal '954
140 roman$ = "MMXI" : print roman$,"=> "; : gosub 170 : print decimal '2011
150 end
160 rem Decode from roman
170 decimal = 0
180 predecimal = 0
190 for i = len(roman$) to 1 step -1
200 x$ = mid$(roman$,i,1)
210 select case x$
220 case "M" : n = 1000
230 case "D" : n = 500
240 case "C" : n = 100
250 case "L" : n = 50
260 case "X" : n = 10
270 case "V" : n = 5
280 case "I" : n = 1
290 case else : print "not a roman numeral" : end
300 end select
310 if n < predecimal then decimal = decimal-n else decimal = decimal+n
320 predecimal = n
330 next i
340 return</syntaxhighlight>
==={{header|FreeBASIC}}===
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64
Function romanDecode(roman As Const String) As Integer
If roman = "" Then Return 0 '' zero denotes invalid roman number
Dim roman1(0 To 2) As String = {"MMM", "MM", "M"}
Dim roman2(0 To 8) As String = {"CM", "DCCC", "DCC", "DC", "D", "CD", "CCC", "CC", "C"}
Dim roman3(0 To 8) As String = {"XC", "LXXX", "LXX", "LX", "L", "XL", "XXX", "XX", "X"}
Dim roman4(0 To 8) As String = {"IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I"}
Dim As Integer i, value = 0, length = 0
Dim r As String = UCase(roman)
For i = 0 To 2
If Left(r, Len(roman1(i))) = roman1(i) Then
value += 1000 * (3 - i)
length = Len(roman1(i))
r = Mid(r, length + 1)
length = 0
Exit For
End If
Next
For i = 0 To 8
If Left(r, Len(roman2(i))) = roman2(i) Then
value += 100 * (9 - i)
length = Len(roman2(i))
r = Mid(r, length + 1)
length = 0
Exit For
End If
Next
For i = 0 To 8
If Left(r, Len(roman3(i))) = roman3(i) Then
value += 10 * (9 - i)
length = Len(roman3(i))
r = Mid(r, length + 1)
length = 0
Exit For
End If
Next
For i = 0 To 8
If Left(r, Len(roman4(i))) = roman4(i) Then
value += 9 - i
length = Len(roman4(i))
Exit For
End If
Next
' Can't be a valid roman number if there are any characters left
If Len(r) > length Then Return 0
Return value
End Function
Dim a(2) As String = {"MCMXC", "MMVIII" , "MDCLXVI"}
For i As Integer = 0 To 2
Print a(i); Tab(8); " =>"; romanDecode(a(i))
Next
Print
Print "Press any key to quit"
Sleep</syntaxhighlight>
{{out}}
<pre>MCMXC => 1990
MMVIII => 2008
MDCLXVI => 1666</pre>
==={{header|FutureBasic}}===
<syntaxhighlight lang="futurebasic">window 1
local fn RomantoDecimal( roman as CFStringRef ) as long
long i, n, preNum = 0, num = 0
for i = len(roman) - 1 to 0 step -1
n = 0
select ( fn StringCharacterAtIndex( roman, i ) )
case _"M" : n = 1000
case _"D" : n = 500
case _"C" : n = 100
case _"L" : n = 50
case _"X" : n = 10
case _"V" : n = 5
case _"I" : n = 1
end select
if ( n < preNum ) then num = num - n else num = num + n
preNum = n
next
end fn = num
print @" MCMXC = "; fn RomantoDecimal( @"MCMXC" )
print @" MMVIII = "; fn RomantoDecimal( @"MMVIII" )
print @" MMXVI = "; fn RomantoDecimal( @"MMXVI" )
print @"MDCLXVI = "; fn RomantoDecimal( @"MDCLXVI" )
print @" MCMXIV = "; fn RomantoDecimal( @"MCMXIV" )
print @" DXIII = "; fn RomantoDecimal( @"DXIII" )
print @" M = "; fn RomantoDecimal( @"M" )
print @" DXIII = "; fn RomantoDecimal( @"DXIII" )
print @" XXXIII = "; fn RomantoDecimal( @"XXXIII" )
HandleEvents</syntaxhighlight>
{{out}}
<pre> MCMXC = 1990
MMVIII = 2008
MMXVI = 2016
MDCLXVI = 1666
MCMXIV = 1914
DXIII = 513
M = 1000
DXIII = 513
XXXIII = 33</pre>
==={{header|Gambas}}===
<syntaxhighlight lang="gambas">'This code will create a GUI Form and Objects and carry out the Roman Numeral convertion as you type
'The input is case insensitive
'A basic check for invalid charaters is made
hTextBox As TextBox 'To allow the creation of a TextBox
hValueBox As ValueBox 'To allow the creation of a ValueBox
Public Sub Form_Open() 'Form opens..
SetUpForm 'Go to the SetUpForm Routine
hTextBox.text = "MCMXC" 'Put a Roman numeral in the TextBox
End
Public Sub TextBoxInput_Change() 'Each time the TextBox text changes..
Dim cRomanN As Collection = ["M": 1000, "D": 500, "C": 100, "L": 50, "X": 10, "V": 5, "I": 1] 'Collection of nemerals e.g 'M' = 1000
Dim cMinus As Collection = ["IV": -2, "IX": -2, "XL": -20, "XC": - 20, "CD": -200, "CM": -200] 'Collection of the 'one less than' numbers e.g. 'IV' = 4
Dim sClean, sTemp As String 'Various string variables
Dim siCount As Short 'Counter
Dim iTotal As Integer 'Stores the total of the calculation
hTextBox.Text = UCase(hTextBox.Text) 'Make any text in the TextBox upper case
For siCount = 1 To Len(hTextBox.Text) 'Loop through each character in the TextBox
If InStr("MDCLXVI", Mid(hTextBox.Text, siCount, 1)) Then 'If a Roman numeral exists then..
sClean &= Mid(hTextBox.Text, siCount, 1) 'Put it in 'sClean' (Stops input of non Roman numerals)
End If
Next
hTextBox.Text = sClean 'Put the now clean text in the TextBox
For siCount = 1 To Len(hTextBox.Text) 'Loop through each character in the TextBox
iTotal += cRomanN[Mid(hTextBox.Text, siCount, 1)] 'Total up all the characters, note 'IX' will = 11 not 9
Next
For Each sTemp In cMinus 'Loop through each item in the cMinus Collection
If InStr(sClean, cMinus.Key) > 0 Then iTotal += Val(sTemp) 'If a 'Minus' value is in the string e.g. 'IX' which has been calculated at 11 subtract 2 = 9
Next
hValueBox.text = iTotal 'Display the total
End
Public Sub SetUpForm() 'Create the Objects for the Form
Dim hLabel1, hLabel2 As Label 'For 2 Labels
Me.height = 150 'Form Height
Me.Width = 300 'Form Width
Me.Padding = 20 'Form padding (border)
Me.Text = "Roman Numeral converter" 'Text in Form header
Me.Arrangement = Arrange.Vertical 'Form arrangement
hLabel1 = New Label(Me) 'Create a Label
hLabel1.Height = 21 'Label Height
hLabel1.expand = True 'Expand the Label
hLabel1.Text = "Enter a Roman numeral" 'Put text in the Label
hTextBox = New TextBox(Me) As "TextBoxInput" 'Set up a TextBox with an Event Label
hTextBox.Height = 21 'TextBox height
hTextBox.expand = True 'Expand the TextBox
hLabel2 = New Label(Me) 'Create a Label
hLabel2.Height = 21 'Label Height
hLabel2.expand = True 'Expand the Label
hLabel2.Text = "The decimal equivelent is: -" 'Put text in the Label
hValueBox = New ValueBox(Me) 'Create a ValueBox
hValueBox.Height = 21 'ValuBox Height
hValueBox.expand = True 'Expand the ValueBox
hValueBox.ReadOnly = True 'Set ValueBox to Read Only
End</syntaxhighlight>
'''[http://www.cogier.com/gambas/Roman%20Numeral%20converter.png Click here for image of running code]'''
==={{header|GW-BASIC}}===
The [[#Chipmunk_Basic|Chipmunk Basic]] [[#Through_IF-THEN_statements|through IF-THEN statements]] solution works without any changes.
==={{header|Liberty BASIC}}===
As Fortran & PureBasic.
<syntaxhighlight lang="lb"> print "MCMXCIX = "; romanDec( "MCMXCIX") '1999
print "MDCLXVI = "; romanDec( "MDCLXVI") '1666
print "XXV = "; romanDec( "XXV") '25
print "CMLIV = "; romanDec( "CMLIV") '954
print "MMXI = "; romanDec( "MMXI") '2011
end
function romanDec( roman$)
arabic =0
lastval =0
for i = len( roman$) to 1 step -1
select case upper$( mid$( roman$, i, 1))
case "M"
n = 1000
case "D"
n = 500
case "C"
n = 100
case "L"
n = 50
case "X"
n = 10
case "V"
n = 5
case "I"
n = 1
case else
n = 0
end select
if n <lastval then
arabic =arabic -n
else
arabic =arabic +n
end if
lastval =n
next
romanDec =arabic
end function</syntaxhighlight>
{{out}}
<pre>MCMXCIX = 1999
MDCLXVI = 1666
XXV = 25
CMLIV = 954
MMXI = 2011</pre>
==={{header|MSX Basic}}===
The [[#Chipmunk_Basic|Chipmunk Basic]] [[#Through_IF-THEN_statements|through IF-THEN statements]] solution works without any changes.
==={{header|PureBasic}}===
<syntaxhighlight lang="purebasic">Procedure romanDec(roman.s)
Protected i, n, lastval, arabic
For i = Len(roman) To 1 Step -1
Select UCase(Mid(roman, i, 1))
Case "M"
n = 1000
Case "D"
n = 500
Case "C"
n = 100
Case "L"
n = 50
Case "X"
n = 10
Case "V"
n = 5
Case "I"
n = 1
Default
n = 0
EndSelect
If (n < lastval)
arabic - n
Else
arabic + n
EndIf
lastval = n
Next
ProcedureReturn arabic
EndProcedure
If OpenConsole()
PrintN(Str(romanDec("MCMXCIX"))) ;1999
PrintN(Str(romanDec("MDCLXVI"))) ;1666
PrintN(Str(romanDec("XXV"))) ;25
PrintN(Str(romanDec("CMLIV"))) ;954
PrintN(Str(romanDec("MMXI"))) ;2011
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
EndIf</syntaxhighlight>
{{out}}
<pre>1999
1666
25
954
2011</pre>
==={{header|QBasic}}===
<syntaxhighlight lang="qbasic">FUNCTION romToDec (roman$)
num = 0
prenum = 0
FOR i = LEN(roman$) TO 1 STEP -1
x$ = MID$(roman$, i, 1)
n = 0
IF x$ = "M" THEN n = 1000
IF x$ = "D" THEN n = 500
IF x$ = "C" THEN n = 100
IF x$ = "L" THEN n = 50
IF x$ = "X" THEN n = 10
IF x$ = "V" THEN n = 5
IF x$ = "I" THEN n = 1
IF n < preNum THEN num = num - n ELSE num = num + n
preNum = n
NEXT i
romToDec = num
END FUNCTION
!Testing
PRINT "MCMXCIX = "; romToDec("MCMXCIX") '1999
PRINT "MDCLXVI = "; romToDec("MDCLXVI") '1666
PRINT "XXV = "; romToDec("XXV") '25
PRINT "CMLIV = "; romToDec("CMLIV") '954
PRINT "MMXI = "; romToDec("MMXI") '2011</syntaxhighlight>
==={{header|QB64}}===
<syntaxhighlight lang="qb64">SCREEN _NEWIMAGE(400, 600, 32)
CLS
Main:
'------------------------------------------------
' CALLS THE romToDec FUNCTION WITH THE ROMAN
' NUMERALS AND RETURNS ITS DECIMAL EQUIVELENT.
'
PRINT "ROMAN NUMERAL TO DECIMAL CONVERSION"
PRINT: PRINT
PRINT "MDCCIV = "; romToDec("MDCCIV") '1704
PRINT "MCMXC = "; romToDec("MCMXC") '1990
PRINT "MMVIII = "; romToDec("MMVIII") '2008
PRINT "MDCLXVI = "; romToDec("MDCLXVI") '1666
PRINT: PRINT
PRINT "Here are other solutions not from the TASK:"
PRINT "MCMXCIX = "; romToDec("MCMXCIX") '1999
PRINT "XXV = "; romToDec("XXV") '25
PRINT "CMLIV = "; romToDec("CMLIV") '954
PRINT "MMXI = "; romToDec("MMXI") '2011
PRINT "MMIIIX = "; romToDec("MMIIIX") '2011
PRINT: PRINT
PRINT "2011 can be written either as MMXI or MMIIIX"
PRINT "With the IX = 9, MMIIIX is also 2011."
PRINT "2011 IS CORRECT (MM=2000 + II = 2 + IX = 9)"
END
FUNCTION romToDec (roman AS STRING)
'------------------------------------------------------
' FUNCTION THAT CONVERTS ANY ROMAN NUMERAL TO A DECIMAL
'
prenum = 0: num = 0
LN = LEN(roman)
FOR i = LN TO 1 STEP -1
x$ = MID$(roman, i, 1)
n = 1000
SELECT CASE x$
CASE "M": n = n / 1
CASE "D": n = n / 2
CASE "C": n = n / 10
CASE "L": n = n / 20
CASE "X": n = n / 100
CASE "V": n = n / 200
CASE "I": n = n / n
CASE ELSE: n = 0
END SELECT
IF n < prenum THEN num = num - n ELSE num = num + n
prenum = n
NEXT i
romToDec = num
END FUNCTION</syntaxhighlight>
==={{header|Run BASIC}}===
<syntaxhighlight lang="runbasic">print "MCMXCIX = "; romToDec( "MCMXCIX") '1999
print "MDCLXVI = "; romToDec( "MDCLXVI") '1666
print "XXV = "; romToDec( "XXV") '25
print "CMLIV = "; romToDec( "CMLIV") '954
print "MMXI = "; romToDec( "MMXI") '2011
function romToDec(roman$)
for i = len(roman$) to 1 step -1
x$ = mid$(roman$, i, 1)
n = 0
if x$ = "M" then n = 1000
if x$ = "D" then n = 500
if x$ = "C" then n = 100
if x$ = "L" then n = 50
if x$ = "X" then n = 10
if x$ = "V" then n = 5
if x$ = "I" then n = 1
if n < preNum then num = num - n else num = num + n
preNum = n
next
romToDec =num
end function</syntaxhighlight>
==={{header|TechBASIC}}===
<syntaxhighlight lang="techbasic">Main:
!------------------------------------------------
! CALLS THE romToDec FUNCTION WITH THE ROMAN
! NUMERALS AND RETURNS ITS DECIMAL EQUIVELENT.
!
PRINT "MCMXC = "; romToDec("MCMXC") !1990
PRINT "MMVIII = "; romToDec("MMVIII") !2008
PRINT "MDCLXVI = "; romToDec("MDCLXVI") !1666
PRINT:PRINT
PRINT "Here are other solutions not from the TASK:"
PRINT "MCMXCIX = "; romToDec("MCMXCIX") !1999
PRINT "XXV = "; romToDec("XXV") !25
PRINT "CMLIV = "; romToDec("CMLIV") !954
PRINT "MMXI = "; romToDec("MMXI") !2011
PRINT:PRINT
PRINT "Without error checking, this also is 2011, but is wrong"
PRINT "MMIIIX = "; romToDec("MMIIIX") !INVAID, 2011
STOP
FUNCTION romToDec(roman AS STRING) AS INTEGER
!------------------------------------------------------
! FUNCTION THAT CONVERTS ANY ROMAN NUMERAL TO A DECIMAL
!
prenum=0!num=0
ln=LEN(roman)
FOR i=ln TO 1 STEP -1
x$=MID(roman,i,1)
n=1000
SELECT CASE x$
CASE "M":n=n/1
CASE "D":n=n/2
CASE "C":n=n/10
CASE "L":n=n/20
CASE "X":n=n/100
CASE "V":n=n/200
CASE "I":n=n/n
CASE ELSE:n=0
END SELECT
IF n < preNum THEN num=num-n ELSE num=num+n
preNum=n
next i
romToDec=num
END FUNCTION</syntaxhighlight>
{{out}}
<pre>MCMXC = 1990
MMVIII = 2008
MDCLXVI = 1666
Here are other solutions not from the TASK:
MCMXCIX = 1999
XXV = 25
CMLIV = 954
MMXI = 2011
Without error checking, this also is 2011, but is wrong
MMIIIX = 2011</pre>
==={{header|TI-83 BASIC}}===
Using the Rom‣Dec function "real(21," from [http://www.detachedsolutions.com/omnicalc/ Omnicalc].
<syntaxhighlight lang="ti83b">PROGRAM:ROM2DEC
:Input Str1
:Disp real(21,Str1)</syntaxhighlight>
Using TI-83 BASIC
<syntaxhighlight lang="ti83b">PROGRAM:ROM2DEC
:Input "ROMAN:",Str1
:{1000,500,100,50,10,5,1}➞L1
:0➞P
:0➞Y
:For(I,length(Str1),1,-1)
:inString("MDCLXVI",sub(Str1,I,1))➞X
:If X≤0:Then
:Disp "BAD NUMBER"
:Stop
:End
:L1(x)➞N
:If N<P:Then
:Y–N➞Y
:Else
:Y+N➞Y
:End
:N➞P
:End
:Disp Y</syntaxhighlight>
==={{header|True BASIC}}===
<syntaxhighlight lang="qbasic">FUNCTION romtodec(roman$)
LET num = 0
LET prenum = 0
FOR i = len(roman$) to 1 step -1
LET x$ = (roman$)[i:i+1-1]
LET n = 0
IF x$ = "M" then LET n = 1000
IF x$ = "D" then LET n = 500
IF x$ = "C" then LET n = 100
IF x$ = "L" then LET n = 50
IF x$ = "X" then LET n = 10
IF x$ = "V" then LET n = 5
IF x$ = "I" then LET n = 1
IF n < prenum then LET num = num-n else LET num = num+n
LET prenum = n
NEXT i
LET romtodec = num
END FUNCTION
!Testing
PRINT "MCMXCIX = "; romToDec("MCMXCIX") !1999
PRINT "MDCLXVI = "; romToDec("MDCLXVI") !1666
PRINT "XXV = "; romToDec("XXV") !25
PRINT "CMLIV = "; romToDec("CMLIV") !954
PRINT "MMXI = "; romToDec("MMXI") !2011
END</syntaxhighlight>
==={{header|XBasic}}===
{{works with|Windows XBasic}}
<syntaxhighlight lang="qbasic">PROGRAM "romandec"
VERSION "0.0000"
DECLARE FUNCTION Entry ()
DECLARE FUNCTION romToDec (roman$)
FUNCTION Entry ()
PRINT "MCMXCIX = "; romToDec("MCMXCIX")
PRINT "MDCLXVI = "; romToDec("MDCLXVI")
PRINT "XXV = "; romToDec("XXV")
PRINT "CMLIV = "; romToDec("CMLIV")
PRINT "MMXI = "; romToDec("MMXI")
END FUNCTION
FUNCTION romToDec (roman$)
num = 0
prenum = 0
FOR i = LEN(roman$) TO 1 STEP -1
x$ = MID$(roman$, i, 1)
SELECT CASE x$
CASE "M" : n = 1000
CASE "D" : n = 500
CASE "C" : n = 100
CASE "L" : n = 50
CASE "X" : n = 10
CASE "V" : n = 5
CASE "I" : n = 1
END SELECT
IF n < prenum THEN num = num-n ELSE num = num+n
prenum = n
NEXT i
RETURN num
END FUNCTION
END PROGRAM</syntaxhighlight>
==={{header|Yabasic}}===
<syntaxhighlight lang="yabasic">romans$ = "MDCLXVI"
decmls$ = "1000,500,100,50,10,5,1"
sub romanDec(s$)
local i, n, prev, res, decmls$(1)
n = token(decmls$, decmls$(), ",")
for i = len(s$) to 1 step -1
n = val(decmls$(instr(romans$, mid$(s$, i, 1))))
if n < prev n = 0 - n
res = res + n
prev = n
next i
return res
end sub
? romanDec("MCMXCIX") // 1999
? romanDec("MDCLXVI") // 1666
? romanDec("XXV") // 25
? romanDec("XIX") // 19
? romanDec("XI") // 11
? romanDec("CMLIV") // 954
? romanDec("MMXI") // 2011
? romanDec("CD") // 400
? romanDec("MCMXC") // 1990
? romanDec("MMVIII") // 2008
? romanDec("MMIX") // 2009
? romanDec("MDCLXVI") // 1666
? romanDec("MMMDCCCLXXXVIII") // 3888</syntaxhighlight>
=={{header|Arturo}}==
<syntaxhighlight lang="rebol">syms: #[ M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 ]
fromRoman: function [roman][
Line 1,018 ⟶ 1,823:
]
loop ["MCMXC" "MMVIII" "MDCLXVI"] 'r -> print [r "->" fromRoman r]</
{{out}}
<pre>MCMXC -> 1990
MMVIII -> 2008
Line 1,028 ⟶ 1,831:
=={{header|AutoHotkey}}==
{{works with|AutoHotkey_L}}
<
res := 0
Loop Parse, str
Line 1,043 ⟶ 1,846:
Loop Parse, test, |
res .= A_LoopField "`t= " Roman_Decode(A_LoopField) "`r`n"
clipboard := res</
{{out}}
<pre>MCMXC = 1990
Line 1,050 ⟶ 1,853:
=={{header|AWK}}==
<
BEGIN {
leng = split("MCMXC MMVIII MDCLXVI",arr," ")
Line 1,072 ⟶ 1,875:
}
return( (a>0) ? a : "" )
}</
{{out}}
<pre>MCMXC = 1990
MMVIII = 2008
MDCLXVI = 1666</pre>
=={{header|Batch File}}==
{{trans|Fortran}}
<
setlocal enabledelayedexpansion
Line 1,126 ⟶ 1,927:
set lastval=!n!
)
goto :EOF</
{{Out}}
<pre>MCMXC = 1990
Line 1,133 ⟶ 1,934:
CDXLIV = 444
XCIX = 99</pre>
=={{header|BCPL}}==
<
let roman(s) = valof
Line 1,188 ⟶ 1,964:
show("MMVII")
show("MMXXI")
$)</
{{out}}
<pre>MCMXC: 1990
Line 1,194 ⟶ 1,970:
MMVII: 2007
MMXXI: 2021</pre>
=={{header|BQN}}==
<syntaxhighlight lang="bqn">⟨ToArabic⇐A⟩ ← {
c ← "IVXLCDM" # Characters
v ← ⥊ (10⋆↕4) ×⌜ 1‿5 # Their values
A ⇐ +´∘(⊢ׯ1⋆<⟜«) v ⊏˜ c ⊐ ⊢
}</syntaxhighlight>
{{out|Example use}}
<syntaxhighlight lang="bqn"> ToArabic¨ "MCMXC"‿"MDCLXVI"‿"MMVII"‿"MMXXI"
⟨ 1990 1666 2007 2021 ⟩</syntaxhighlight>
=={{header|Bracmat}}==
{{trans|Icon and Unicon}}
<
= nbr,lastVal,val
. 0:?nbr:?lastVal
Line 1,236 ⟶ 2,024:
: ? (?L.?D) (?&test$!L&~)
| done
);</
{{out}}
<pre>M 1000
Line 1,251 ⟶ 2,039:
=={{header|C}}==
Note: the code deliberately did not distinguish between "I", "J" or "U", "V", doing what Romans did for fun.
<
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 };
Line 1,297 ⟶ 2,085:
return 0;
}</
=={{header|C sharp|C#}}==
<
using System.Collections.Generic;
Line 1,361 ⟶ 2,149:
}
}
}</
{{out}}
<pre>MCMXC: 1990
Line 1,369 ⟶ 2,157:
=={{header|C++}}==
<
#include <exception>
#include <string>
Line 1,420 ⟶ 2,208:
return 0;
}
</syntaxhighlight>
{{out}}
<PRE>MCMXC = 1990
Line 1,427 ⟶ 2,215:
=={{header|Ceylon}}==
<
value numerals = map {
Line 1,463 ⟶ 2,251:
assert(toHindu("MCMXC") == 1990);
assert(toHindu("MMVIII") == 2008);
}</
=={{header|Clojure}}==
<
;; Incorporated some improvements from the alternative implementation below
(defn ro2ar [r]
Line 1,481 ⟶ 2,269:
(map numerals)
(reduce (fn [[sum lastv] curr] [(+ sum curr (if (< lastv curr) (* -2 lastv) 0)) curr]) [0,0])
first))</
{{out}}
<pre>(map ro2ar ["MDCLXVI" "MMMCMXCIX" "XLVIII" "MMVIII"])
(1666 3999 48 2008)</pre>
=={{header|CLU}}==
<syntaxhighlight lang="clu">roman = cluster is decode
rep = null
digit_value = proc (c: char) returns (int) signals (invalid)
if c < 'a' then c := char$i2c(char$c2i(c) + 32) end
if c = 'm' then return(1000)
elseif c = 'd' then return(500)
elseif c = 'c' then return(100)
elseif c = 'l' then return(50)
elseif c = 'x' then return(10)
elseif c = 'v' then return(5)
elseif c = 'i' then return(1)
else signal invalid
end
end digit_value
decode = proc (s: string) returns (int) signals (invalid)
acc: int := 0
for i: int in int$from_to(1, string$size(s)) do
d: int := digit_value(s[i])
if i < string$size(s) cand d < digit_value(s[i+1]) then
acc := acc - d
else
acc := acc + d
end
end resignal invalid
return(acc)
end decode
end roman
start_up = proc ()
po: stream := stream$primary_output()
tests: array[string] := array[string]$
["MCMXC", "mdclxvi", "MmViI", "mmXXi", "INVALID"]
for test: string in array[string]$elements(tests) do
stream$puts(po, test || ": ")
stream$putl(po, int$unparse(roman$decode(test))) except when invalid:
stream$putl(po, "not a valid Roman numeral!")
end
end
end start_up</syntaxhighlight>
{{out}}
<pre>MCMXC: 1990
mdclxvi: 1666
MmViI: 2007
mmXXi: 2021
INVALID: not a valid Roman numeral!</pre>
=={{header|COBOL}}==
<syntaxhighlight lang="cobol">
IDENTIFICATION DIVISION.
PROGRAM-ID. UNROMAN.
Line 1,564 ⟶ 2,402:
.
END PROGRAM UNROMAN.
</syntaxhighlight>
{{out}} input was supplied via STDIN
<pre>
Line 1,605 ⟶ 2,443:
=={{header|CoffeeScript}}==
<
# s is well-formed Roman Numeral >= I
numbers =
Line 1,640 ⟶ 2,478:
dec = roman_to_demical(roman)
console.log "error" if dec != expected
console.log "#{roman} = #{dec}"</
=={{header|Common Lisp}}==
<
(defun mapcn (chars nums string)
(loop as char across string as i = (position char chars) collect (and i (nth i nums))))
Line 1,650 ⟶ 2,488:
(loop with nums = (mapcn "IVXLCDM" '(1 5 10 50 100 500 1000) R)
as (A B) on nums if A sum (if (and B (< A B)) (- A) A)))
</syntaxhighlight>
Description:
Line 1,665 ⟶ 2,503:
Test code:
<
(format t "~a:~10t~d~%" r (parse-roman r)))</
{{out}}
<pre>MCMXC: 1990
Line 1,674 ⟶ 2,512:
=={{header|Cowgol}}==
<
include "argv.coh";
Line 1,732 ⟶ 2,570:
print_i16(romanToDecimal(argmt));
print_nl();</
{{out}}
Line 1,743 ⟶ 2,581:
=={{header|D}}==
<
int toArabic(in string s) /*pure nothrow*/ {
Line 1,761 ⟶ 2,599:
assert("MMVIII".toArabic == 2008);
assert("MDCLXVI".toArabic == 1666);
}</
Alternative more functional version:
<
immutable uint[string] w2s;
Line 1,784 ⟶ 2,622:
assert("MMVIII".toArabic == 2008);
assert("MDCLXVI".toArabic == 1666);
}</
=={{header|Delphi}}/{{header|Pascal}}==
<
{$APPTYPE CONSOLE}
Line 1,830 ⟶ 2,668:
Writeln(RomanToInteger('MMVIII')); // 2008
Writeln(RomanToInteger('MDCLXVI')); // 1666
end.</
=={{header|EasyLang}}==
<syntaxhighlight lang="text">
func rom2dec rom$ .
symbols$[] = [ "M" "D" "C" "L" "X" "V" "I" ]
values[] = [ 1000 500 100 50 10 5 1 ]
val = 0
for dig$ in
for i
if
v =
.
.
val += v
if oldv < v
val -= 2 * oldv
.
return val
.
print
print rom2dec "MDCLXVI"
</syntaxhighlight>
=={{header|ECL}}==
The best declarative approach:
<syntaxhighlight lang="ecl">
MapChar(STRING1 c) := CASE(c,'M'=>1000,'D'=>500,'C'=>100,'L'=>50,'X'=>10,'V'=>5,'I'=>1,0);
Line 1,878 ⟶ 2,715:
RomanDecode('MMVIII'); //2008
RomanDecode('MDCLXVI'); //1666
RomanDecode('MDLXVI'); //1566</
Here's an alternative that emulates the wat procedural code would approach the problem:
<
RomanDecode(STRING s) := FUNCTION
SetWeights := [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
Line 1,920 ⟶ 2,757:
RomanDecode('MMVIII'); //2008
RomanDecode('MDCLXVI'); //1666
RomanDecode('MDLXVI'); //1566</
=={{header|Eiffel}}==
Line 1,926 ⟶ 2,763:
This solution is case insensitive. It performs no input validation other than checking that all Roman digits in the input string are one of <tt>M</tt>, <tt>D</tt>, <tt>C</tt>, <tt>L</tt>, <tt>X</tt>, <tt>V</tt>, and <tt>I</tt>.
<
APPLICATION
Line 2,036 ⟶ 2,873:
end
end</
=={{header|Elena}}==
ELENA
<
import system'collections;
import system'routines;
import system'culture;
static RomanDictionary = Dictionary.new()
Line 2,058 ⟶ 2,896:
{
var minus := 0;
var s := self.
var total := 0;
for(int i := 0
{
var thisNumeral := RomanDictionary[s[i]] - minus;
Line 2,084 ⟶ 2,922:
console.printLine("MMVIII: ", "MMVIII".toRomanInt());
console.printLine("MDCLXVI:", "MDCLXVI".toRomanInt())
}</
{{out}}
<pre>
Line 2,094 ⟶ 2,932:
=={{header|Elixir}}==
{{trans|Erlang}}
<
def decode([]), do: 0
def decode([x]), do: to_value(x)
Line 2,115 ⟶ 2,953:
Enum.each(['MCMXC', 'MMVIII', 'MDCLXVI', 'IIIID'], fn clist ->
IO.puts "#{clist}\t: #{Roman_numeral.decode(clist)}"
end)</
{{out}}
Line 2,125 ⟶ 2,963:
=={{header|Emacs Lisp}}==
<syntaxhighlight lang="lisp">(defun ro2ar (RN)
"Translate a roman number RN into arabic number.
Its argument RN is wether a symbol, wether a list.
Returns the arabic number. (ro2ar 'C) gives 100,
Line 2,141 ⟶ 2,978:
((null (cdr RN)) (ro2ar (car RN))) ;; stop recursion
((< (ro2ar (car RN)) (ro2ar (car (cdr RN)))) (- (ro2ar (cdr RN)) (ro2ar (car RN)))) ;; "IV" -> 5-1=4
(t (+ (ro2ar (car RN)) (ro2ar (cdr RN)))))) ;; "VI" -> 5+1=6</syntaxhighlight>
{{out}}
(ro2ar '(M D C L X V I))
=={{header|Erlang}}==
Putting the character X into a list, [X], creates a string with a single character.
<syntaxhighlight lang="erlang">
-module( roman_numerals ).
Line 2,173 ⟶ 3,008:
{V1, _} -> V1 + decode_from_string([H2|Rest])
end.
</syntaxhighlight>
{{out}}
Line 2,186 ⟶ 3,021:
=={{header|ERRE}}==
<syntaxhighlight lang="erre">
PROGRAM ROMAN2ARAB
Line 2,216 ⟶ 3,051:
TOARAB("MMMDCCCLXXXVIII"->ANS%) PRINT(ANS%)
END PROGRAM
</syntaxhighlight>
If the answer is -9999, roman number is illegal.
=={{header|Euphoria}}==
{{trans|PureBasic}}
<
function romanDec(sequence roman)
integer n, lastval, arabic
Line 2,245 ⟶ 3,080:
? romanDec("XXV")
? romanDec("CMLIV")
? romanDec("MMXI")</
{{out}}
<pre>1999
Line 2,255 ⟶ 3,090:
=={{header|F Sharp|F#}}==
This implementation uses tail recursion. The accumulator (arabic) and the last roman digit (lastval) are recursively passed as each element of the list is consumed.
<
let rec convert arabic lastval = function
| head::tail ->
Line 2,271 ⟶ 3,106:
| _ -> arabic + lastval
convert 0 0 (Seq.toList roman)
;;</
Here is an alternative implementation that uses Seq(uence).fold. It threads a Tuple of the state (accumulator, last roman digit) through the list of characters.
<
let convert (arabic,lastval) c =
let n = match c with
Line 2,289 ⟶ 3,124:
let (arabic, lastval) = Seq.fold convert (0,0) roman
arabic + lastval
;;</
Test code:
<
for test in tests do Printf.printf "%s: %d\n" test (decimal_of_roman test)
;;</
{{out}}
Line 2,306 ⟶ 3,141:
=={{header|Factor}}==
A roman numeral library ships with Factor.
<
( scratchpad ) "MMMCCCXXXIII" roman> .
3333</
Implementation for decoding:
<
{ "m" "cm" "d" "cd" "c" "xc" "l" "xl" "x" "ix" "v" "iv" "i" }
Line 2,331 ⟶ 3,166:
: roman-digit-value ( ch -- n )
roman-digit-index roman-values nth ;</
=={{header|FALSE}}==
<
$'m= $[\% 1000\]? ~[
$'d= $[\% 500\]? ~[
Line 2,354 ⟶ 3,189:
]#
%+. {add final digit to accumulator and output}
10, {and a newline}</
{{out}}
Line 2,368 ⟶ 3,203:
=={{header|Forth}}==
<
1000 128 * char M + ,
500 128 * char D + ,
Line 2,393 ⟶ 3,228:
;
s" MCMLXXXIV" >arabic .</
<
\ create words to describe and solve the problem
\ ANS/ISO Forth
Line 2,436 ⟶ 3,271:
I C@ >VALUE ?NEGATE +
-1 +LOOP ;
</syntaxhighlight>
Alternative Version Forth Console Test
Line 2,456 ⟶ 3,291:
=={{header|Fortran}}==
{{works with|Fortran|90 and later}}
<
implicit none
Line 2,496 ⟶ 3,331:
end do
end function decode
end program Roman_decode</
{{out}}
<pre> 1990 2008 1666</pre>
=={{header|Go}}==
For fluff, the unicode overbar is recognized as a factor of 1000, [http://en.wikipedia.org/wiki/Roman_numerals#Large_numbers as described in WP].
<
import (
Line 2,776 ⟶ 3,420:
}
}
}</
{{out}}
<pre>
Line 2,785 ⟶ 3,429:
Simpler:
<
import (
Line 2,821 ⟶ 3,465:
fmt.Printf("%-10s == %d\n", roman_digit, from_roman(roman_digit))
}
}</
=={{header|Golo}}==
<
----
This module converts a Roman numeral into a decimal number.
Line 2,870 ⟶ 3,514:
println("MDCLXVI = " + "MDCLXVI": decode())
}
</syntaxhighlight>
=={{header|Groovy}}==
Solution:
<
I(1), V(5), X(10), L(50), C(100), D(500), M(1000);
Line 2,893 ⟶ 3,537:
}
}
}</
Test:
<
Digit Values = ${RomanDigits.values()}
M => ${RomanDigits.parse('M')}
Line 2,906 ⟶ 3,550:
MCDXLIV => ${RomanDigits.parse('MCDXLIV')}
MDCLXVI => ${RomanDigits.parse('MDCLXVI')}
"""</
{{out}}
<pre>Digit Values = [I=1, V=5, X=10, L=50, C=100, D=500, M=1000]
Line 2,925 ⟶ 3,569:
Compiles with GHC.
<syntaxhighlight lang="haskell">
module Main where
Line 2,971 ⟶ 3,615:
arabic = decode roman
remark = " (" ++ (if arabic == expected then "PASS" else ("FAIL, expected " ++ (show expected))) ++ ")"
</syntaxhighlight>
{{Out}}
Line 2,982 ⟶ 3,626:
====Same logic as above but in a functional idiom====
<syntaxhighlight lang="haskell">
module Main where
Line 3,023 ⟶ 3,667:
arabic = decode roman
remark = " (" ++ (if arabic == expected then "PASS" else ("FAIL, expected " ++ (show expected))) ++ ")"
</syntaxhighlight>
====List comprehension====
<
mapping = [("M",1000),("CM",900),("D",500),("CD",400),("C",100),("XC",90),
Line 3,034 ⟶ 3,678:
toArabic "" = 0
toArabic str = num + toArabic xs
where (num, xs):_ = [ (num, drop (length n) str) | (n,num) <- mapping, isPrefixOf n str ]</
Usage:
<pre>
Line 3,046 ⟶ 3,690:
====mapAccum====
Or, expressing '''romanValue''' in terms of '''mapAccumL''' (avoiding recursive descent, and visiting each k v pair just once)
<
import Data.List (isPrefixOf, mapAccumL)
Line 3,084 ⟶ 3,728:
"MMXVI",
"MMXVII"
]</
Or, in a '''mapAccumR''' version:
<
import qualified Data.Map.Strict as M
import Data.Maybe (maybe)
Line 3,151 ⟶ 3,795:
where
rjust n c = drop . length <*> (replicate n c <>)
w = maximum (length . xShow <$> xs)</
{{Out}}
<pre>Decoding Roman numbers:
Line 3,165 ⟶ 3,809:
An alternative solution using a fold. (This turns out to be the fastest of the four approaches here) {{Trans|F#}}
<
fromRoman :: String -> Int
Line 3,195 ⟶ 3,839:
main :: IO ()
main = print $ fromRoman <$> ["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"]</
Where the left fold above could also be rewritten [http://wiki.haskell.org/Foldr_Foldl_Foldl%27 | as a right fold].
<
import Data.Maybe (maybe)
------------------ ROMAN NUMERALS DECODED ----------------
mapRoman :: M.Map Char Int
mapRoman =
M.fromList $
zip "IVXLCDM" $
scanl (*) 1 (cycle [5, 2])
fromRoman :: String -> Maybe Int
fromRoman cs =
let op l r
| otherwise = (-)
in snd
. foldr
(\l (r, n) -> (l, op l r n l))
(0, 0)
<$> traverse (`M.lookup` mapRoman) cs
--------------------------- TEST -------------------------
main :: IO ()
main =
putStrLn $
fTable
"Roman numeral decoding as a right fold:\n"
show
(maybe "(Unrecognised character seen)" show)
fromRoman
[ "MDCLXVI",
"MCMXC",
"MMVIII",
"MMXVI",
"MMXVII",
"QQXVII"
]
------------------------ FORMATTING ----------------------
fTable ::
String ->
(a -> String) ->
(b -> String) ->
(a -> b) ->
[a] ->
String
fTable s xShow fxShow f xs =
unlines $
s :
<*> ((" -> " <>) . fxShow . f)
)
xs
where
rjust n c = drop . length <*> (replicate n c <>)
w = maximum (length . xShow <$> xs)</syntaxhighlight>
{{Out}}
<pre>Roman numeral decoding as a right fold:
Line 3,248 ⟶ 3,918:
(Probably more trouble than it's worth in practice, but at least an illustration of some Data.Maybe and Data.Map functions)
<
import Data.Maybe (isNothing, isJust, fromJust, catMaybes)
import Data.List (mapAccumL)
Line 3,286 ⟶ 3,956:
main :: IO ()
main = print $ fromRoman <$> ["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"]</
{{Out}}
<pre>[1666,1990,2008,2016,2017]</pre>
=={{header|Hoon}}==
Library file (e.g. <code>/lib/rhonda.hoon</code>):
<syntaxhighlight lang="hoon">|%
++ parse
|= t=tape ^- @ud
=. t (cass t)
=| result=@ud
|-
?~ t result
?~ t.t (add result (from-numeral i.t))
=+ [a=(from-numeral i.t) b=(from-numeral i.t.t)]
?: (gte a b) $(result (add result a), t t.t)
$(result (sub (add result b) a), t t.t.t)
++ yield
|= n=@ud ^- tape
=| result=tape
=/ values to-numeral
|-
?~ values result
?: (gte n -.i.values)
$(result (weld result +.i.values), n (sub n -.i.values))
$(values t.values)
++ from-numeral
|= c=@t ^- @ud
?: =(c 'i') 1
?: =(c 'v') 5
?: =(c 'x') 10
?: =(c 'l') 50
?: =(c 'c') 100
?: =(c 'd') 500
?: =(c 'm') 1.000
!!
++ to-numeral
^- (list [@ud tape])
:*
[1.000 "m"]
[900 "cm"]
[500 "d"]
[400 "cd"]
[100 "c"]
[90 "xc"]
[50 "l"]
[40 "xl"]
[10 "x"]
[9 "ix"]
[5 "v"]
[4 "iv"]
[1 "i"]
~
==
--</syntaxhighlight>
Script file ("generator") (e.g. <code>/gen/roman.hoon</code>):
<syntaxhighlight lang="hoon">/+ *roman
:- %say
|= [* [x=$%([%from-roman tape] [%to-roman @ud]) ~] ~]
:- %noun
^- tape
?- -.x
%from-roman "{<(parse +.x)>}"
%to-roman (yield +.x)
==</syntaxhighlight>
=={{header|Icon}} and {{header|Unicon}}==
<
procedure main()
every R := "MCMXC"|"MDCLXVI"|"MMVIII" do
write(R, " = ",unroman(R))
end</
{{libheader|Icon Programming Library}}
[http://www.cs.arizona.edu/icon/library/src/procs/numbers.icn numbers.icn provides unroman]
The code for this procedure is copied below:
<
local nbr,lastVal,val
Line 3,320 ⟶ 4,056:
}
return nbr
end</
{{out}}
<pre>MCMXC = 1990
MDCLXVI = 1666
MMVIII = 2008</pre>
=={{header|Insitux}}==
{{Trans|Clojure}}
<syntaxhighlight lang="insitux">
(var numerals {"M" 1000 "D" 500 "C" 100 "L" 50 "X" 10 "V" 5 "I" 1})
; Approach A
(function ro->ar r
(-> (reverse (upper-case r))
(map numerals)
(split-with val)
(map (.. +0))
(reduce @(((< % %1) + -)))))
; Approach B
(function ro->ar r
(-> (upper-case r)
(map numerals)
@(reduce (fn [sum lastv] curr [(+ sum curr ((< lastv curr) (* -2 lastv) 0)) curr]) [0 0])
0))
(map ro->ar ["MDCLXVI" "MMMCMXCIX" "XLVIII" "MMVIII"])
</syntaxhighlight>
{{out}}
<pre>
[1666 3999 48 2008]
</pre>
=={{header|J}}==
<
Example use:
<
1990
rom2d 'MDCLXVI'
1666
rom2d 'MMVIII'
2008</
=={{header|Java}}==
{{works with|Java|1.5+}}
<
private static int decodeSingle(char letter) {
switch(letter) {
Line 3,374 ⟶ 4,141:
System.out.println(decode("MDCLXVI")); //1666
}
}</
{{out}}
<pre>1990
Line 3,380 ⟶ 4,147:
1666</pre>
{{works with|Java|1.8+}}
<
import java.util.EnumSet;
import java.util.Collections;
Line 3,438 ⟶ 4,205:
LongStream.of(1999, 25, 944).forEach(RomanNumerals::test);
}
}</
{{out}}
<pre>1999 = MCMXCIX
Line 3,452 ⟶ 4,219:
{{works with|Rhino}}
{{works with|SpiderMonkey}}
<
Values: [['CM', 900], ['CD', 400], ['XC', 90], ['XL', 40], ['IV', 4],
['IX', 9], ['V', 5], ['X', 10], ['L', 50],
Line 3,477 ⟶ 4,244:
var test_datum = test_data[i]
print(test_datum + ": " + Roman.parse(test_datum))
}</
{{out}}
<pre>MCMXC: 1990
Line 3,486 ⟶ 4,253:
{{Trans|Haskell}}
(isPrefixOf example)
<
var mapping = [["M", 1000], ["CM", 900], ["D", 500], ["CD", 400], ["C", 100], [
Line 3,533 ⟶ 4,300:
return lstTest.map(romanValue);
})(['MCMXC', 'MDCLXVI', 'MMVIII']);</
{{Out}}
<syntaxhighlight lang
or, more natively:
<
function romanValue(s) {
Line 3,568 ⟶ 4,335:
return lstTest.map(romanValue);
})(["MCMXC", "MDCLXVI", "MMVIII", "MMMM"]);</
{{Out}}
<syntaxhighlight lang
===ES6===
====Recursion====
<
// romanValue :: String -> Int
const romanValue = s =>
Line 3,608 ⟶ 4,375:
// TEST -------------------------------------------------------------------
return ["MCMXC", "MDCLXVI", "MMVIII", "MMMM"].map(romanValue);
})();</
{{Out}}
<syntaxhighlight lang
Line 3,616 ⟶ 4,383:
{{Trans|Haskell}}
(fold and foldr examples)
<
// -------------- ROMAN NUMERALS DECODED ---------------
Line 3,671 ⟶ 4,438:
// MAIN ---
return main();
})();</
{{Out}}
<pre>1666
Line 3,678 ⟶ 4,445:
2016
2017</pre>
====Declarative====
<syntaxhighlight lang="javascript">
(() => {
function toNumeric(value) {
return value
.replace(/IV/, 'I'.repeat(4))
.replace(/V/g, 'I'.repeat(5))
.replace(/IX/, 'I'.repeat(9))
.replace(/XC/, 'I'.repeat(90))
.replace(/XL/, 'I'.repeat(40))
.replace(/X/g, 'I'.repeat(10))
.replace(/L/, 'I'.repeat(50))
.replace(/CD/, 'I'.repeat(400))
.replace(/CM/, 'I'.repeat(900))
.replace(/C/g, 'I'.repeat(100))
.replace(/D/g, 'I'.repeat(500))
.replace(/M/g, 'I'.repeat(1000))
.length;
}
const numerics = ["MMXVI", "MCMXC", "MMVIII", "MM", "MDCLXVI"]
.map(toNumeric);
console.log(numerics);
})();
</syntaxhighlight>
{{Out}}
<pre>
[2016, 1990, 2008, 2000, 1666]
</pre>
=={{header|jq}}==
{{works with|jq|1.4}}
This version requires the Roman numerals to be presented in upper case.
<
def addRoman(n):
if length == 0 then n
Line 3,701 ⟶ 4,500:
error("invalid Roman numeral: " + tostring)
end;
addRoman(0);</
'''Example:'''
<
{{out}}
<
MCMXC => 1990
MMVIII => 2008
MDCLXVI => 1666</
=={{header|Jsish}}==
Line 3,720 ⟶ 4,519:
{{works with|Julia|0.6}}
'''The Function''':
<
romandigits = Dict('I' => 1, 'V' => 5, 'X' => 10, 'L' => 50,
'C' => 100, 'D' => 500, 'M' => 1000)
Line 3,738 ⟶ 4,537:
end
return accm
end</
This function is rather permissive. There are no limitations on the numbers of Roman numerals nor on their order. Because of this and because any out of order numerals subtract from the total represented, it is possible to represent zero and negative integers. Also mixed case representations are allowed. The function does throw an error if the string contains any invalid characters.
'''Test the code''':
<
test = ["I", "III", "IX", "IVI", "IIM",
Line 3,750 ⟶ 4,549:
for rnum in test
@printf("%15s → %s\n", rnum, try parseroman(rnum) catch "not valid" end)
end</
{{out}}
Line 3,771 ⟶ 4,570:
=={{header|K}}==
{{trans|J}}
<
'''Example:'''
<
1990 2008 1666</
=={{header|Kotlin}}==
As specified in the task description, there is no attempt to validate the form of the Roman number in the following program - invalid characters and ordering are simply ignored:
<
fun romanDecode(roman: String): Int {
Line 3,802 ⟶ 4,601:
val romans = arrayOf("I", "III", "IV", "VIII", "XLIX", "CCII", "CDXXXIII", "MCMXC", "MMVIII", "MDCLXVI")
for (roman in romans) println("${roman.padEnd(10)} = ${romanDecode(roman)}")
}</
{{out}}
Line 3,819 ⟶ 4,618:
=={{header|Lasso}}==
<
//decode roman
define decodeRoman(roman::string)::integer => {
Line 3,841 ⟶ 4,640:
'MMVIII as integer is '+decodeRoman('MMVIII')
br
'MDCLXVI as integer is '+decodeRoman('MDCLXVI')</
=={{header|LiveScript}}==
<
# String → Number
Line 3,910 ⟶ 4,656:
fold(_convert, [0, 0]) >> sum
{[rom, decimal_of_roman rom] for rom in <[ MCMXC MMVII MDCLXVII MMMCLIX MCMLXXVII MMX ]>}</
Output:
Line 3,916 ⟶ 4,662:
=={{header|Logo}}==
<
; First, some useful substring utilities
Line 3,950 ⟶ 4,696:
foreach [MCMXC MDCLXVI MMVIII] [print (sentence (word ? "|: |) from_roman ?)]
bye</
{{out}}
<pre>MCMXC: 1990
Line 3,958 ⟶ 4,704:
=={{header|Lua}}==
<
local Num = { ["M"] = 1000, ["D"] = 500, ["C"] = 100, ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 }
local numeral = 0
Line 3,982 ⟶ 4,728:
print( ToNumeral( "MCMXC" ) )
print( ToNumeral( "MMVIII" ) )
print( ToNumeral( "MDCLXVI" ) )</
<pre>1990
2008
Line 3,990 ⟶ 4,736:
Maximum Roman number is MMMCMXCIX (3999)
<syntaxhighlight lang="m2000 interpreter">
Module RomanNumbers {
flush ' empty current stack
Line 4,067 ⟶ 4,813:
RomanNumbers
</syntaxhighlight>
{{out}}
Line 4,098 ⟶ 4,844:
=={{header|Maple}}==
<
seq(printf("%a\n", f(i)), i in [MCMXC, MMVIII, MDCLXVI]);</
{{out}}
<pre>
Line 4,108 ⟶ 4,854:
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<
{{out}}
<pre>2405</pre>
=={{header|MATLAB}}==
<
% ROM2DEC converts Roman numbers to decimal
Line 4,123 ⟶ 4,869:
x = sum(values .* [sign(diff(-values)+eps),1]);
end</
Here is a test:
<
for n = 1 : numel(romanNumbers)
fprintf('%10s = %4d\n',romanNumbers{n}, rom2dec(romanNumbers{n}));
end</
{{out}}
<pre>
Line 4,137 ⟶ 4,883:
=={{header|Mercury}}==
<
:- interface.
Line 4,185 ⟶ 4,931:
Args, !IO).
:- end_module test_roman.</
=={{header|Miranda}}==
<syntaxhighlight lang="miranda">main :: [sys_message]
main = [ Stdout (s ++ ": " ++ show (fromroman s) ++ "\n")
| s <- ["MCMXC", "MDCLXVI", "MMVII", "MMXXIII"]
]
fromroman :: [char]->num
fromroman = f
where f [] = 0
f [x] = r x
f (x:y:xs) = f (y:xs) - r x, if r x < r y
= f (y:xs) + r x, otherwise
r 'M' = 1000
r 'D' = 500
r 'C' = 100
r 'L' = 50
r 'X' = 10
r 'V' = 5
r 'I' = 1</syntaxhighlight>
{{out}}
<pre>MCMXC: 1990
MDCLXVI: 1666
MMVII: 2007
MMXXIII: 2023</pre>
=={{header|Modula-2}}==
<
FROM InOut IMPORT WriteString, WriteCard, WriteLn;
FROM Strings IMPORT Length;
Line 4,239 ⟶ 5,010:
Show("mmvii");
Show("mmxxi");
END RomanNumerals.</
{{out}}
<pre>MCMXC: 1990
Line 4,248 ⟶ 5,019:
=={{header|Nanoquery}}==
{{trans|Java}}
<
if letter = "M"
return 1000
Line 4,286 ⟶ 5,057:
println decode("MCMXC")
println decode("MMVIII")
println decode("MDCLXVI")</
{{out}}
<pre>1990
Line 4,293 ⟶ 5,064:
=={{header|NetRexx}}==
<
options replace format comments java crossref savelog symbols binary
Line 4,341 ⟶ 5,112:
end
return digit</
{{out}}
<pre>
Line 4,351 ⟶ 5,122:
=={{header|Nim}}==
{{trans|Python}}
<
let rdecode = {'M': 1000, 'D': 500, 'C': 100, 'L': 50, 'X': 10, 'V': 5, 'I': 1}.toTable
Line 4,362 ⟶ 5,133:
for r in ["MCMXC", "MMVIII", "MDCLXVI"]:
echo r, " ", decode(r)</
{{out}}
Line 4,370 ⟶ 5,141:
=={{header|OCaml}}==
<
let arabic = ref 0 in
let lastval = ref 0 in
Line 4,396 ⟶ 5,167:
Printf.printf " %d\n" (decimal_of_roman "MMVIII");
Printf.printf " %d\n" (decimal_of_roman "MDCLXVI");
;;</
=== Another implementation ===
Another implementation, a bit more OCaml-esque: no mutable variables, and a recursive function instead of a for loop.
{{works with|OCaml|4.03+}}
<
(* Scan the roman number from right to left. *)
(* When processing a roman digit, if the previously processed roman digit was
Line 4,458 ⟶ 5,229:
print_endline (testit "2 * PI ^ 2" 1); (* The I in PI... *)
print_endline (testit "E = MC^2" 1100)
</syntaxhighlight>
Output:
<pre>
Line 4,480 ⟶ 5,251:
=={{header|PARI/GP}}==
<
my(v=Vecsmall(s),key=vector(88),cur,t=0,tmp);
key[73]=1;key[86]=5;key[88]=10;key[76]=50;key[67]=100;key[68]=500;key[77]=1000;
Line 4,496 ⟶ 5,267:
);
t+cur
};</
=={{header|Perl}}==
<
{
Line 4,523 ⟶ 5,294:
}
say "$_: ", from_roman($_) for qw(MCMXC MDCLXVI MMVIII);</
{{out}}
<pre>MCMXC: 1990
Line 4,529 ⟶ 5,300:
MMVIII: 2008</pre>
=== Alternate ===
<
use strict;
Line 4,548 ⟶ 5,319:
MCMXC
MMVIII
MDCLXVI</
{{out}}
<pre>
Line 4,556 ⟶ 5,327:
</pre>
=== Another Alternate ===
<
use strict;
Line 4,581 ⟶ 5,352:
MCMXC
MMVIII
MDCLXVI</
{{out}}
<pre>
Line 4,590 ⟶ 5,361:
=={{header|Phix}}==
<!--
<syntaxhighlight lang="phix">
with javascript_semantics
function romanDec(string s)
integer res = 0, prev = 0
for i=length(s) to 1 by -1 do
integer rdx = find(upper(s[i]),"IVXLCDM"),
rn = power(10,floor((rdx-1)/2))
if even(rdx) then rn *= 5 end if
res += iff(rn<prev?-rn:rn)
prev = rn
end for
return {s,res} -- (for output)
end function
?apply({"MCMXC","MMVIII","MDCLXVI"},romanDec)
</syntaxhighlight>
{{out}}
<pre>
{{"MCMXC",1990},{"MMVIII",2008},{"MDCLXVI",1666}}
</pre>
=== cheating slightly ===
<syntaxhighlight lang="phix">
with javascript_semantics
requires("1.0.5")
function romanDec(string s)
return {s,scanf(s,"%R")[1][1]}
end function
</syntaxhighlight>
same output, if applied the same way as above, error handling omitted
=={{header|Phixmonti}}==
<
0 >ps 0 >ps
( ( "M" 1000 ) ( "D" 500 ) ( "C" 100 ) ( "L" 50 ) ( "X" 10 ) ( "V" 5 ) ( "I" 1 ) )
Line 4,634 ⟶ 5,414:
enddef
/# usage example: "MMXX" romanDec ? (show 2020) #/</
More traditional solution:
<
( 1000 500 100 50 10 5 1 ) var decmls
Line 4,659 ⟶ 5,439:
drop
res
enddef</
=={{header|PHP}}==
<
/**
* @author Elad Yosifon
Line 4,747 ⟶ 5,527:
{
echo "($key == {$value[0]}) => " . ($value[0] === $value[1] ? "true" : "false, should be {$value[1]}.") . "\n";
}</
{{out}}
<pre>
Line 4,771 ⟶ 5,551:
(MCMLXXVII == 1977) => true
</pre>
=={{header|Picat}}==
<syntaxhighlight lang="picat">go =>
List = ["IV",
"XLII",
"M",
"MCXI",
"CMXI",
"MCM",
"MCMXC",
"MMVIII",
"MMIX",
"MCDXLIV",
"MDCLXVI",
"MMXII"],
foreach(R in List)
printf("%-8s: %w\n", R, roman_decode(R))
end,
nl.
roman_decode(Str) = Res =>
if Str == "" then
Res := ""
else
D = new_map(findall((R=D), roman(R,D))),
Res = 0,
Old = 0,
foreach(S in Str)
N = D.get(S),
% Fix for the Roman convention that XC = 90, not 110.
if Old > 0, N > Old then
Res := Res - 2*Old
end,
Res := Res + N,
Old := N
end
end.
roman('I', 1).
roman('V', 5).
roman('X', 10).
roman('L', 50).
roman('C', 100).
roman('D', 500).
roman('M', 1000).</syntaxhighlight>
{{out}}
<pre>IV : 4
XLII : 42
M : 1000
MCXI : 1111
CMXI : 911
MCM : 1900
MCMXC : 1990
MMVIII : 2008
MMIX : 2009
MCDXLIV : 1444
MDCLXVI : 1666
MMXII : 2012</pre>
=={{header|PicoLisp}}==
<
(let L (replace (chop Rom) 'M 1000 'D 500 'C 100 'L 50 'X 10 'V 5 'I 1)
(sum '((A B) (if (>= A B) A (- A))) L (cdr L)) ) )</
Test:
<pre>: (roman2decimal "MCMXC")
Line 4,787 ⟶ 5,628:
=={{header|PL/I}}==
<syntaxhighlight lang="pl/i">
test_decode: procedure options (main); /* 28 January 2013 */
declare roman character (20) varying;
Line 4,834 ⟶ 5,675:
end test_decode;
</syntaxhighlight>
<pre>
i 1
Line 4,858 ⟶ 5,699:
=={{header|PL/M}}==
<
/* CP/M CALLS */
BDOS: PROCEDURE (FN, ARG); DECLARE FN BYTE, ARG ADDRESS; GO TO 5; END BDOS;
Line 4,918 ⟶ 5,759:
CALL PRINT$NUMBER(READ$ROMAN(.ARG(1))); /* CONVERT AND PRINT VALUE */
CALL EXIT;
EOF</
{{out}}
Line 4,933 ⟶ 5,774:
=={{header|PL/SQL}}==
<syntaxhighlight lang="pl/sql">
/*****************************************************************
* $Author: Atanas Kebedjiev $
Line 5,017 ⟶ 5,858:
END;
</syntaxhighlight>
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
Filter FromRoman {
$output = 0
Line 5,054 ⟶ 5,895:
$output
}
</syntaxhighlight>
<syntaxhighlight lang="powershell">
'XIX','IV','','MMCDLXXIX','MMMI' | FromRoman
</syntaxhighlight>
{{Out}}
<pre>
Line 5,068 ⟶ 5,909:
=={{header|Prolog}}==
<
decode_digit(v, 5).
decode_digit(x, 10).
Line 5,099 ⟶ 5,940:
decode_string(mcmxc, 1990),
decode_string(mmviii, 2008),
decode_string(mdclxvi, 1666).</
The program above contains its own test predicate.
The respective goal succeeds.
Therefore the test passes.
=={{header|Python}}==
===Imperative===
<
def decode( roman ):
Line 5,168 ⟶ 5,958:
if __name__ == '__main__':
for r in 'MCMXC MMVIII MDCLXVI'.split():
print( r, decode(r) )</
{{out}}
<pre>MCMXC 1990
Line 5,175 ⟶ 5,965:
Another version, which I believe has clearer logic:
<
('CD', 400), ('D', 500), ('CM', 900), ('M',1000))
Line 5,189 ⟶ 5,979:
for value in "MCMXC", "MMVIII", "MDCLXVI":
print('%s = %i' % (value, roman_value(value)))
</syntaxhighlight>
{{out}}
<pre>
Line 5,200 ⟶ 5,990:
===Declarative===
Less clear, but a 'one liner':
<
def romannumeral2number(s):
return reduce(lambda x, y: -x + y if x < y else x + y, map(lambda x: numerals.get(x, 0), s.upper()))</
Line 5,209 ⟶ 5,999:
{{Trans|Haskell}}
{{Works with|Python|3}}
<
from operator import mul
Line 5,223 ⟶ 6,013:
characters are unrecognised.
'''
dct = defaultdict(
lambda: None,
Line 5,244 ⟶ 6,020:
)
)
def go(mb, x):
'''Just a letter value added to or
subtracted from a total, or Nothing
if no letter value is defined.
'''
if None in (mb, x):
return None
else:
r, total = mb
return x, total + (-x if x < r else x)
return bindMay(reduce(
go,
[dct[k.upper()] for k in reversed(list(s))],
(0, 0)
))(snd)
# ------------------------- TEST -------------------------
def main():
'''Testing a sample of dates.'''
Line 5,269 ⟶ 6,055:
#
# bindMay (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Line 5,290 ⟶ 6,064:
of the (a -> Maybe b) function (mf) to x.'''
return lambda mf: (
m if None is m
)
Line 5,306 ⟶ 6,074:
where m is Just(x).
'''
return lambda f: lambda m: v if None is m
f(m
)
# snd :: (a, b) -> b
def snd(
'''Second member of a pair.'''
return
#
# fTable :: String -> (a -> String) ->
#
def fTable(s):
'''Heading -> x
fx display function
'''
def go(xShow, fxShow, f, xs):
Line 5,329 ⟶ 6,097:
w = max(map(len, ys))
return s + '\n' + '\n'.join(map(
lambda x, y:
f'{y.rjust(w, " ")} -> {fxShow(f(x))}'
),
xs, ys
))
return lambda xShow: lambda fxShow: lambda f:
lambda xs: go(xShow, fxShow, f, xs)
)
Line 5,339 ⟶ 6,109:
# MAIN ---
if __name__ == '__main__':
main()</
{{Out}}
<pre>Roman numerals decoded:
Line 5,351 ⟶ 6,121:
=={{header|Quackery}}==
<syntaxhighlight lang="quackery"> [ 2dup <
if
[ dip
Line 5,382 ⟶ 6,151:
$ "I MIX VIVID MILD MIMIC"
dup echo$ say " = " ->arabic echo cr
</syntaxhighlight>
{{Out}}
<pre> MCMXC = 1990
MMVIII = 2008
Line 5,392 ⟶ 6,159:
I MIX VIVID MILD MIMIC = 3063</pre>
=={{header|R}}==
===version 1===
Modelled along the lines of other decode routines on this page, but using a vectorised approach
<
romanLookup <- c(I=1L, V=5L, X=10L, L=50L, C=100L, D=500L, M=1000L)
rSplit <- strsplit(toupper(roman), character(0)) # Split input vector into characters
Line 5,472 ⟶ 6,176:
}
vapply(rSplit, toArabic, integer(1))
}</
Example usage:
<
===version 2===
Using built-in functionality in R
<
=={{header|Racket}}==
<
(define (decode/roman number)
(define letter-values
Line 5,499 ⟶ 6,203:
(map decode/roman '("MCMXC" "MMVIII" "MDCLXVI"))
;-> '(1990 2008 1666)</
=={{header|Raku}}==
(formerly Perl 6)
A non-validating version:
<syntaxhighlight lang="raku"
[+] gather $r.uc ~~ /
^
Line 5,526 ⟶ 6,230:
}
say "$_ => &rom-to-num($_)" for <MCMXC MDCLXVI MMVIII>;</
{{out}}
<pre>MCMXC => 1990
Line 5,532 ⟶ 6,236:
MMVIII => 2008</pre>
A validating version. Also handles older forms such as 'IIXX' and "IIII".
<syntaxhighlight lang="raku"
[+] gather $r.uc ~~ /
^
Line 5,546 ⟶ 6,250:
}
say "$_ => ", rom-to-num($_) for <MCMXC mdclxvi MMViii IIXX ILL>;</
{{out}}
<pre>MCMXC => 1990
Line 5,557 ⟶ 6,261:
===version 1===
<
Purpose: "Arabic <-> Roman numbers converter"
Author: "Didier Cadieu"
Line 5,575 ⟶ 6,279:
print roman-to-arabic "MDCCCLXXXVIII"
print roman-to-arabic "MMXVI"
</syntaxhighlight>
=={{header|REFAL}}==
<syntaxhighlight lang="refal">$ENTRY Go {
= <Prout <RomanDecode 'MCMXC'>>
<Prout <RomanDecode 'MMVIII'>>
<Prout <RomanDecode 'MDCLXVI'>>;
};
RomanDecode {
= 0;
e.D, <Upper e.D>: {
'M' e.R = <+ 1000 <RomanDecode e.R>>;
'CM' e.R = <+ 900 <RomanDecode e.R>>;
'D' e.R = <+ 500 <RomanDecode e.R>>;
'CD' e.R = <+ 400 <RomanDecode e.R>>;
'C' e.R = <+ 100 <RomanDecode e.R>>;
'XC' e.R = <+ 90 <RomanDecode e.R>>;
'L' e.R = <+ 50 <RomanDecode e.R>>;
'XL' e.R = <+ 40 <RomanDecode e.R>>;
'X' e.R = <+ 10 <RomanDecode e.R>>;
'IX' e.R = <+ 9 <RomanDecode e.R>>;
'V' e.R = <+ 5 <RomanDecode e.R>>;
'IV' e.R = <+ 4 <RomanDecode e.R>>;
'I' e.R = <+ 1 <RomanDecode e.R>>;
};
};</syntaxhighlight>
{{out}}
<pre>1990
2008
1666</pre>
=={{header|REXX}}==
Line 5,583 ⟶ 6,317:
{{Works with|ooRexx}}
<
Do
Line 5,645 ⟶ 6,379:
Return digit
End
Exit</
{{out}}
<pre>
Line 5,665 ⟶ 6,399:
:::* the '''j''' and '''u''' numerals
:::* (deep) parenthesis type Roman numbers
<
rYear = 'MCMXC' ; say right(rYear, 9)":" rom2dec(rYear)
rYear = 'mmviii' ; say right(rYear, 9)":" rom2dec(rYear)
Line 5,690 ⟶ 6,424:
if _=='D' then return 500
if _=='M' then return 1000
return 0 /*indicate an invalid Roman numeral. */</
===version 3===
Line 5,712 ⟶ 6,446:
<br>Also note that '''IIII''' is a legal Roman numeral construct; (as demonstrated by almost any old clock or
<br>"dialed" wristwatch that has Roman numerals).
<
numeric digits 1000 /*so we can handle the big numbers. */
parse arg z /*obtain optional arguments from the CL*/
Line 5,737 ⟶ 6,471:
else #=#+_ /* else add. */
end /*k*/
return # /*return Arabic number. */</
'''output''' when using the default inputs:
<pre>
Line 5,751 ⟶ 6,485:
=={{header|Ring}}==
<
symbols = "MDCLXVI"
weights = [1000,500,100,50,10,5,1]
Line 5,773 ⟶ 6,507:
next
return arabic
</syntaxhighlight>
=={{header|RPL}}==
{{works with|Halcyon Calc|4.2.7}}
{| class="wikitable"
! RPL code
! Comment
|-
|
≪ DUP SIZE "IVXLCDM" { 1 5 10 50 100 500 1000 }
→ rom siz dig val
≪ 0 1 siz '''FOR''' j
rom j DUP SUB
'''IF''' dig SWAP POS '''THEN''' val LAST GET '''END'''
'''IF''' DUP2 < '''THEN''' SWAP NEG SWAP '''END'''
'''NEXT'''
0 1 siz '''START''' + '''NEXT''' +
≫ ≫ ''''ROM→'''' STO
|
'''ROM→''' ''( "ROMAN" -- n )''
store input string, length and tables
scan string from highest digit
get jth character
if char in the table then push its value into stack
if > to previous value then change sign of previous value
sum the stack
.
|}
=={{header|Ruby}}==
<
r = roman.upcase
n = 0
Line 5,803 ⟶ 6,565:
end
[ "MCMXC", "MMVIII", "MDCLXVI" ].each {|r| p r => fromRoman(r)}</
{{out}}
Line 5,812 ⟶ 6,574:
</pre>
or
<
['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1] ]
Line 5,822 ⟶ 6,584:
end
[ "MCMXC", "MMVIII", "MDCLXVI" ].each {|r| puts "%8s :%5d" % [r, parseRoman(r)]}</
{{out}}
Line 5,830 ⟶ 6,592:
MDCLXVI : 1666
</pre>
=={{header|Rust}}==
<
symbol: &'static str,
value: u32
Line 5,892 ⟶ 6,628:
println!("{:2$} = {}", r, to_hindu(r), 15);
}
}</
{{out}}
<pre>MMXIV = 2014
Line 5,901 ⟶ 6,637:
=={{header|Scala}}==
<
val arabicNumerals = List("CM"->900,"M"->1000,"CD"->400,"D"->500,"XC"->90,"C"->100,
"XL"->40,"L"->50,"IX"->9,"X"->10,"IV"->4,"V"->5,"I"->1)
Line 5,926 ⟶ 6,662:
test("MCMXC")
test("MMVIII")
test("MDCLXVI")</
{{out}}
<pre>MCMXC => 1990
Line 5,936 ⟶ 6,672:
{{works with|Gauche Scheme}}
<
(define (char-val char)
Line 5,948 ⟶ 6,684:
0 0
(map char-val (reverse (string->list roman)))))
</syntaxhighlight>
<b>Testing:</b>
<
(^s (format #t "~7d: ~d\n" s (decode s)))
'("MCMLVI" "XXC" "MCMXC" "XXCIII" "IIIIX" "MIM" "LXXIIX"))
</syntaxhighlight>
{{out}}
<pre>
Line 5,967 ⟶ 6,703:
=={{header|Seed7}}==
<
const func integer: ROMAN parse (in string: roman) is func
Line 6,002 ⟶ 6,738:
writeln(ROMAN parse "MMVIII");
writeln(ROMAN parse "MDCLXVI");
end func;</
Original source: [http://seed7.sourceforge.net/algorith/puzzles.htm#decode_roman_numerals]
{{out}}
Line 6,012 ⟶ 6,748:
=={{header|SenseTalk}}==
<
put {
"M": 1000,
Line 6,032 ⟶ 6,768:
end repeat
return total
end RomanNumeralsDecode</
<
"MCMXC",
"MMVIII",
Line 6,041 ⟶ 6,777:
put RomanNumeralsDecode(it)
end repeat
</syntaxhighlight>
{{out}}
Line 6,051 ⟶ 6,787:
=={{header|Sidef}}==
<
var arabic = 0
Line 6,078 ⟶ 6,814:
%w(MCMXC MMVIII MDCLXVI).each { |roman_digit|
"%-10s == %d\n".printf(roman_digit, roman2arabic(roman_digit))
}</
{{out}}
<pre>
Line 6,087 ⟶ 6,823:
Simpler solution:
<
digit.uc.trans([
:M: '1000+',
Line 6,107 ⟶ 6,843:
%w(MCMXC MMVIII MDCLXVI).each { |roman_num|
say "#{roman_num}\t-> #{roman2arabic(roman_num)}";
}</
{{out}}
<pre>
Line 6,116 ⟶ 6,852:
=={{header|Simula}}==
<
INTEGER PROCEDURE FROMROMAN(S); TEXT S;
Line 6,161 ⟶ 6,897:
END PROGRAM;
</syntaxhighlight>
{{out}}
<pre>
Line 6,170 ⟶ 6,906:
=={{header|SNOBOL4}}==
<
define('arabic(n)s,ch,val,sum,x') :(arabic_end)
arabic s = 'M1000 D500 C100 L50 X10 V5 I1 '
Line 6,186 ⟶ 6,922:
astr = astr r '=' arabic(r) ' ' :(tloop)
out output = astr
end</
{{out}}
<pre>MMX=2010 MCMXCIX=1999 MCDXCII=1492 MLXVI=1066 CDLXXVI=476</pre>
Here's an alternative version, which is maybe more SNOBOL4-idiomatic and less like one might program it in a more common language:
<
define("arabic1(romans,arabic1)rdigit,adigit,b4")
romans1 = " 0 IX9 IV4 III3 II2 I1 VIII8 VII7 VI6 V5" :(arabic1_end)
Line 6,204 ⟶ 6,940:
astr = astr r '=' arabic1(r) ' ' :(tloop)
out output = astr
end</
The output is the same as in the earlier version.
Line 6,210 ⟶ 6,946:
This allows removing several labels and explicit transfers of control, and moves some of the looping into the pattern matcher.
Again, the output is the same.
<
define("arabic1(romans,arabic1)rdigit,adigit,b4")
romans1 = " 0 IX9 IV4 III3 II2 I1 VIII8 VII7 VI6 V5" :(arabic1_end)
Line 6,222 ⟶ 6,958:
tstr span(' ') break(' ') $ r *?(astr = astr r '=' arabic1(r) ' ') fail
output = astr
end</
=={{header|SPL}}==
<
n = [1,5,10,50,100,500,1000]
a,m = 0
Line 6,240 ⟶ 6,976:
> i, 1..#.size(t,1)
#.output(t[i]," = ",r2a(t[i]))
<</
{{out}}
<pre>
Line 6,253 ⟶ 6,989:
=={{header|Swift}}==
<
init(romanNumerals: String) {
let values = [
Line 6,281 ⟶ 7,017:
}
}
</syntaxhighlight>
{{output}}
<
=={{header|Tailspin}}==
<
def digits: [(M:1000"1"), (CM:900"1"), (D:500"1"), (CD:400"1"), (C:100"1"), (XC:90"1"), (L:50"1"), (XL:40"1"), (X:10"1"), (IX:9"1"), (V:5"1"), (IV:4"1"), (I:1"1")];
composer decodeRoman
@: 1;
[ <digit>* ] -> \(@: 0"1"; $... -> @: $@ + $; $@ !\)
rule digit: <value>* (@: $@ + 1;)
rule value: <='$digits($@)::key;'> -> $digits($@)::value
Line 6,302 ⟶ 7,038:
' -> !OUT::write
'MDCLXVI' -> decodeRoman -> !OUT::write
</syntaxhighlight>
{{out}}
<pre>
1990"1"
2008"1"
1666"1"
</pre>
=={{header|Tcl}}==
As long as we assume that we have a valid roman number, this is most easily done by transforming the number into a sum and evaluating the expression:
<
set map {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+}
expr [string map $map $rnum]0}
}</
Demonstrating:
<
puts "$r\t-> [fromRoman $r]"
}</
{{out}}
<pre>MCMXC -> 1990
MDCLXVI -> 1666
MMVIII -> 2008</pre>
=={{header|TMG}}==
Unix TMG dialect. Version without validation:
<
roman: string(!<<MDCLXVI>>) [n=0] num
letter: num/render letter;
Line 6,444 ⟶ 7,081:
render: decimal(n) = { 1 * };
n: 0;</
Unix TMG dialect. Version with validation:
<
parse(line)\loop
parse(error)\loop;
Line 6,482 ⟶ 7,119:
off:0;
wsz:0;
v1: 0; v2: 0; v3: 0;</
Sample input:
Line 6,503 ⟶ 7,140:
=={{header|TUSCRIPT}}==
<
LOOP roman_number="MCMXC'MMVIII'MDCLXVI"
arab_number=DECODE (roman_number,ROMAN)
PRINT "Roman number ",roman_number," equals ", arab_number
ENDLOOP</
{{out}}
<pre>
Line 6,516 ⟶ 7,153:
=={{header|UNIX Shell}}==
<
#!/bin/bash
Line 6,552 ⟶ 7,189:
roman_to_dec MMVIII
roman_to_dec MDCLXVI
</syntaxhighlight>
=={{header|VBA}}==
Convert Romans (i.e : XVI) in integers
<syntaxhighlight lang="vb">
Option Explicit
Line 6,591 ⟶ 7,228:
End If
End Function
</syntaxhighlight>
{{out}}
<pre>III >>> 3
Line 6,614 ⟶ 7,251:
=={{header|VBScript}}==
{{trans|360 Assembly}}
<
Function toRoman(ByVal value)
Line 6,634 ⟶ 7,271:
code=MsgBox(n & vbCrlf & toRoman(n),vbOKOnly+vbExclamation,"Roman numerals/Encode")
If code=vbOK Then ok=1
</syntaxhighlight>
{{out}}
<pre>
Line 6,662 ⟶ 7,299:
=={{header|Vedit macro language}}==
<
//
do {
Line 6,699 ⟶ 7,336:
Reg_Empty(11)
Buf_Quit(OK)
Return</
{{out}}
<pre>iv = 4
Line 6,706 ⟶ 7,343:
MCMXC = 1990
MMXI = 2011</pre>
=={{header|V (Vlang)}}==
{{trans|Kotlin}}
<syntaxhighlight lang="Zig">
const romans = ["I", "III", "IV", "VIII", "XLIX", "CCII", "CDXXXIII", "MCMXC", "MMVIII", "MDCLXVI"]
fn main() {
for roman in romans {println("${roman:-10} = ${roman_decode(roman)}")}
}
fn roman_decode(roman string) int {
mut n := 0
mut last := "O"
if roman =="" {return n}
for c in roman {
match c.ascii_str() {
"I" {n++}
"V" {if last == "I" {n += 3} else {n += 5}}
"X" {if last == "I" {n += 8} else {n += 10}}
"L" {if last == "X" {n += 30} else {n += 50}}
"C" {if last == "X" {n += 80} else {n += 100}}
"D" {if last == "C" {n += 300} else {n += 500}}
"M" {if last == "C" {n += 800} else {n += 1000}}
else {last = c.ascii_str()}
}
}
return n
}
</syntaxhighlight>
{{out}}
<pre>
I = 1
III = 3
IV = 4
VIII = 8
XLIX = 49
CCII = 202
CDXXXIII = 433
MCMXC = 1990
MMVIII = 2008
MDCLXVI = 1666
</pre>
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-fmt}}
<
var decode = Fn.new { |r|
Line 6,740 ⟶ 7,420:
var romans = ["I", "III", "IV", "VIII", "XLIX", "CCII", "CDXXXIII", "MCMXC", "MMVIII", "MDCLXVI"]
for (r in romans) System.print("%(Fmt.s(-10, r)) = %(decode.call(r))")</
{{out}}
Line 6,758 ⟶ 7,438:
=={{header|XLISP}}==
Uses basic list processing and recursion. Probably not amazingly fast, but quite concise and hopefully clear.
<
(define roman '((#\m 1000) (#\d 500) (#\c 100) (#\l 50) (#\x 10) (#\v 5) (#\i 1)))
(defun to-arabic (rn rs a)
Line 6,767 ⟶ 7,447:
(+ a (cadar rs)) ) ) )
(t (to-arabic rn (cdr rs) a)) ) )
(to-arabic (string->list r) roman 0) )</
Test it in a REPL:
<
(1990 2008 1666)</
=={{header|XPL0}}==
<
code CrLf=9, IntOut=11;
Line 6,800 ⟶ 7,480:
IntOut(0, Roman("MMVIII")); CrLf(0);
IntOut(0, Roman("MDCLXVI")); CrLf(0);
]</
{{out}}
Line 6,810 ⟶ 7,490:
=={{header|XQuery}}==
<syntaxhighlight lang="xquery">
xquery version "3.1";
Line 6,858 ⟶ 7,538:
}
)
</syntaxhighlight>
=={{header|zkl}}==
<
L("M", 1000), L("CM", 900), L("D", 500), L("CD", 400), L("C", 100),
L("XC", 90), L("L", 50), L("XL", 40), L("X", 10), L("IX", 9),
Line 6,908 ⟶ 7,556:
}
return(value);
}</
<pre>
toArabic("MCMXC") //-->1990
Line 6,918 ⟶ 7,566:
=={{header|Zoea}}==
<syntaxhighlight lang="zoea">
program: roman_decimal
input: 'XIII'
output: 13
</syntaxhighlight>
=={{header|Zoea Visual}}==
Line 6,928 ⟶ 7,576:
=={{header|zsh}}==
<
#!/bin/zsh
function parseroman () {
Line 6,949 ⟶ 7,597:
parseroman MMVIII
parseroman MDCLXVI
</syntaxhighlight>
|