# R[oman|everse] Polish Notation

It is the year MDLXVII in a world in which the Roman Empire never fell, and the collapse into the dark ages never occurred. Due to the extended period of Pax Romana, the empire's economic stability enabled technology to progress at a rapid rate.

The Romans have begun to dabble with circuitry, and have invented an ingenious calculator that doesn't require the use of an "equals" button. They call it "Roman Polish Notation"

To make a calculation, they enter their operands first, then the operation.

For example, 100 + 11 * 20 would be C XI XX * +.

The Romans have found that they often need to make multiple calculations at the same time, and would prefer for the method to return every value "on the stack" in some sort of array/list/tuple-like structure. (e.g. X I + X I - CC II + would return [11, 9, 202])

The challenge is to develop a calculator program capable of making these computations.

Clarification: Subtractive Notation is required. I hadn't realized it wasn't recognized feature in the Ancient Roman empire. The task was therefore ambiguous, and I apologize.

Minimum Guidelines

• Your output will be in Arabic Numerals.
• You only need to convert from Roman Numerals up to 5000.
• You will need to support +, -, /, * operations (addition, subtraction, division, and multiplication).
• Whether division is floating point based or integer based is implementation specific. Either works for this challenge.
• Your output will need to support numbers up to 4 Billion.
• Shortest answer overall, AND in each language wins. This is a Code Golf Challenge but I love the variety.

In the event of a tie, factors like support for roman numerals above 5000 or additional operations will be considered the earliest submission will win.

• Can we take input as a list of strings, each have either a Roman number or an operator? Dec 31, 2017 at 16:16
• can the input be taken in lowercase, or does it have to be uppercase? Dec 31, 2017 at 16:22
• @JesseDanielMitchell As a note... try not to change rules and invalidate existing answers. Also, (as usual) I suggest posting in the Sandbox. Jan 1, 2018 at 2:42

# Python 2 + roman, 118 bytes

from roman import*
s=[]
for i in input().split():s+=[eval(s.pop(-2)+i+s.pop())if i in"+-/*"elsefromRoman(i)]
print s


### Demo

It cannot be tested online because of the module it makes use of, but you can see how to run this here (a full program accepting input from STDIN – an expression with quotes – and printing the output to STDOUT – in the form of a list, the stack). Uses a slightly older version, because I won't bother to create a new GIF for only a few bytes: To install the package, you can run the following in the Terminal / Command Line:

pip install roman

• pyTester/Py.py ಠ_ಠ Dec 30, 2017 at 22:49
• @totallyhuman It's just a dummy project that I made just for this... Dec 30, 2017 at 22:50

# Haskell, 217 bytes

-13 bytes thanks to Bruce Forte. -73 bytes thanks to Ørjan Johansen.

foldl(!)[].words

# Dyalog APL, 93 bytes

⎕CY'dfns'
a←⍬⋄{0::{a,←⍵}roman⍵⋄f←⍎'+-÷×'⌷⍨'+-/*'⍳⍵⋄r←f/¯2↑a⋄a↓⍨←¯2⋄a,←r}¨{1↓¨⍵⊂⍨⍵∊' '}' ',⍞⋄a


Try it online!

116 bytes without the roman built-in

• Woah, never saw modified assignment in a golf before Dec 31, 2017 at 17:46
• @Zacharý it's the only way I know to modify a variable out of its dfns scope, so it had to be used here. Dec 31, 2017 at 18:05
• Forgive my ignorance, but what is modified assignment? Jan 1, 2018 at 1:52
• @cairdcoinheringaahing var fn←arr - it's equivalent to var ← var fn arr. Here it's used in multiple places, a,←⍵ being one which appends ⍵ to the variable a Jan 1, 2018 at 1:55

# Python 3, 280 206 bytes

N=dict(I=1,V=5,X=10,L=50,C=100,D=500,M=1000)
def d(s):
n=0
for v in map(N.get,s):n+=v-n%v*2
return n
def c(w):
s=[]
for t in w.split():s+=[str(d(t)if tin N else eval(s.pop(-2)+t+s.pop()))]
return s


Try it online!

This time with subtractive notation support. Method c is the main entry point; the other is support.

Edit log:

• You don't need the indentation blocks after if and else. Jan 2, 2018 at 1:12
• Actually, let me offer you this trick I once found: n+=v-n%v*2 Jan 2, 2018 at 1:28
• You can also combine the two str uses. Try it online! Jan 2, 2018 at 1:37

# JavaScipt (ES6), 152 151 bytes

Saved 1 byte thanks to user202729

p=>p.split .map(c=>s.push(eval("+-/*".indexOf(c)+1?(T=s.pop(),s.pop())+c+T:c.replace(/./g,c=>"+"+{I:1,V:5,X:10,L:50,C:100,D:500,M:1e3}[c]))),s=[])&&s


## Test cases

f=p=>p.split .map(c=>s.push(eval("+-/*".indexOf(c)+1?(T=s.pop(),s.pop())+c+T:c.replace(/./g,c=>"+"+{I:1,V:5,X:10,L:50,C:100,D:500,M:1e3}[c]))),s=[])&&s
console.log(f("C XI XX * +"))
console.log(f("X I + X I - CC II +"))

## Explanation (less golfed)

V={I:1,V:5,X:10,L:50,C:100,D:500,M:1e3}     // Values of the roman numerals
p=>(
s=[],                                      // Initialize the stack
p.split .map(c=>                         // For every part in the input:
"+-/*".indexOf(c)+1?                      //   If the input is an operator:
s.push(eval((T=s.pop(),s.pop())+c+T))    //     Evaluate the operator on the top of the stack
:                                         //   Else (if it is a roman numeral):
s.push(eval(c.replace(/./g,c=>"+"+V[c])))//     Push the sum of the characters' values
),s)                                       // return the stack

• I'm pretty sure that 1e3 also work and save some bytes. Dec 31, 2017 at 11:28

# Jelly, 82 bytes

ị“+-×÷”;”/v®ṫ-¤®ṖṖ¤;©
4Ḷ⁵*p1,5P€
Ḳµ“+-*/”W€i⁸Ñ⁸Ç¤¹?µ€ṛ®Ḋ


Try it online!

Explanation:

Because Jelly doesn't have a stack, I put the stack in the register.

When the program starts, the register value ® is 0, which is treated as  for the purposes of this program.


ị“+-×÷”;”/v®ṫ-¤®ṖṖ¤;©       Link 1: Given an operator index (an
integer in range 1..4), apply it.

ị“+-×÷”                     Index to the string "+-×÷"
;”/                  Concatenate with the character "/",
which is Jelly splat operator.
v   ¤             Evaluate with parameter...
®                  the register's
ṫ                 tail
-                from -1. (2 last items)
®  ¤;        Concatenate with the register value,
ṖṖ            pop twice.
©       Store the result to register.

4Ḷ                  Lowered range of 4, gives [0,1,2,3].
⁵*                Raise to power of 10. Value = 1,10,100,1000.
p1,5            Calculate Cartesian product with [1,5].
Value = [1,1],[1,5],[10,1],[10,5],...
P€          Calculate product of each item.

Alternatively, ×þ1,5F would also work instead of p1,5P€.

“IVXLCDM”iÐ€ị¢µIN‘Ṡæ.µ®;©   Link 3: Given roman number, push it
to the stack (register).
i                  Find index of ...
Ð€                  each character ...
“IVXLCDM”                     in "IVXLCDM".
ị¢              Index to last link. (link 2)
µ             With that value, (consider LIX ->
[50,1,10] for example)
I
Ḳµ“+-*/”W€i⁸Ñ⁸Ç¤¹?µ€ṛ®Ḋ

[TODO complete explanation]



# Python 3, 216 187 bytes

from operator import*
N=dict(I=1,V=5,X=10,L=50,C=100,D=500,M=1000)
def f(w):
s=[]
for t in w.split():s+=[str(sum(map(N.get,t)))if tin N else str(eval(s.pop(-2)+t+s.pop()))]
return s


Try it online!

Because it came up in the comments of both the question and this answer and likely led to down-votes: this submission doesn't support subtractive notation. Rationale: Subtractive notation was rarely used in the Roman Empire and only popularised later (see Subtractive Notation, paragraph 3, last sentence). The task presumes a Roman Empire that developed programmable integrated circuits, not one that underwent the same cultural changes as 13th century Europe. The description doesn't mention subtractive notation and none of the examples uses it.

• Hm... you're not supporting numbers like CIV (104). Dec 31, 2017 at 2:13
• ...can't fault your logic there. :P Dec 31, 2017 at 2:23
• Agh, you were right. I hadn't thought about the possible ambiguity, I wasn't aware subtractive notation wasn't a common feature in the Ancient Roman empire. Dec 31, 2017 at 16:11
• I did actually consider asking about subtractive notation under the OP (and noticed the lack of an example), but got distracted. If you think of definition ambiguities in future challenges, don't hesitate, just ask (answering with a caveat and a link to your comment should do if you want to post). Now a ruling is in you should attempt to fix it up :) Dec 31, 2017 at 18:48