RPN Calculator
February 19, 2009
The only difficulty is handling the newline, which the Scheme reader treats as whitespace. The (op token)
function converts token
from a symbol returned by the reader to an operator that can be used to perform arithmetic. The format of the first line of the program is specific to Chez Scheme, but most Scheme systems provide something similar.
#! /usr/bin/scheme –script
(define (next)
(cond ((eof-object? (peek-char)) (exit))
((char=? (peek-char) #\space) (read-char) (next))
((char=? (peek-char) #\newline) (read-char) ‘nl)
(else (read))))
(define (op token) (case token ((+) +) ((-) -) ((*) *) ((/) /)))
(let rpn ((token (next)) (stack ‘()))
(cond ((eq? ‘nl token) (display (car stack)) (newline) (rpn (next) (cdr stack)))
((number? token) (rpn (next) (cons token stack)))
(else (rpn (next) (cons ((op token) (cadr stack) (car stack)) (cddr stack))))))
Although it can’t be run, this program is available as a paste at http://programmingpraxis.codepad.org/fjzlC50x. This exercise was inspired by a web page of Fredrik Arnerup at http://www.stacken.kth.se/~foo/rpn.
Haskell:
I’m using problems on this site to learn haskell. Please do let me know if I could have solved this in a better way.
import Data.List (intercalate)
evaluate :: String -> Float
evaluate str = calculate (tokenize str)
tokenize :: String -> [String]
tokenize = words
calculate :: [String] -> Float
calculate exp = rpn_eval exp [0.0]
rpn_eval :: [String] -> [Float] -> Float
rpn_eval [] stack = stack!!0
rpn_eval (x:xs) stack | isOperator x = rpn_eval xs ((eval_expr x (take 2 stack)) : (drop 2 stack))
| otherwise = rpn_eval xs ((read x :: Float) : stack)
isOperator :: String -> Bool
isOperator token = token `elem` [“+”,”-“,”/”,”*”]
eval_expr :: String -> [Float] -> Float
eval_expr “+” [x,y] = x + y
eval_expr “-” [x,y] = y – x
eval_expr “*” [x,y] = x * y
eval_expr “/” [x,y] = y / x
eval_expr _ [x,y] = undefined
calculateExprs :: String -> String
calculateExprs str = intercalate “\n” (map (show . evaluate) (lines str))
main = do interact calculateExprs
A slight redesign of my previous code:
my Ocaml version.
My haskell version, similar to that of FalconNL, although a bit more verbose
parse :: String -> Either Double (Double -> Double -> Double)
parse s = maybe (Left $ read s) Right (lookup s ops)
where ops = zip ["+","-","*","/"] [(+),(-),(*),(/)]
go :: [Double] -> [String] -> [Double]
go stack [] = stack
go stack (w:ws) = case parse w of
Left x -> go (x:stack) ws
Right f -> go (apply f stack) ws
where apply f (x:y:xs) = (f x y:xs)
eval :: [[String]] -> [Double]
eval = map head . tail . scanl go []
main = getContents >>= mapM_ print . eval . map words . lines
Sorry, I didn’t follow the instruction concerning howto paste code. Here is a link to the formatted code : http://codepad.org/x3Ai1SN2
Here’s my Python solution.
I bet that there’s an easier way to do this in Python. But this is what I came up with.
It’s kind of like an interactive shell. Just enter the RPN expression, and it’ll return the value.
Although the expression we’re supposed to use for testing gives me 222149.08271379699 instead of 85.2974.
I have just began learning Erlang so it is probably far from perfect :)
I’ve just been learning lisp, so I’m giving that a shot first:
(defun split-by-one-space (string)
“Returns a list of substrings of string
divided by ONE space each.
Note: Two consecutive spaces will be seen as
if there were an empty string between them.
Thanks to http://cl-cookbook.sourceforge.net/strings.html”
(loop for i = 0 then (1+ j)
as j = (position #\Space string :start i)
collect (subseq string i j)
while j))
(defun evaluate-rpn(expr)
(loop
with stack = (list)
for token in (split-by-one-space expr)
do (let ((digit (read-from-string token nil))
(*read-eval* nil)) ; By default, read-from-string will evaluate things. Boo!
(cond
((realp digit)
;;Digit is a number
(push digit stack))
(t
;; Gotta pop the two values off the stack
;; and evaluate them, what fun!
(let ((b (pop stack))
(a (pop stack)))
;; If the function is one we can parse, then go ahead and
;; evaluate it
(cond
((find digit ‘(+ – / * mod sin cos atan tan))
(push (funcall digit a b) stack))
(t (format t “Could not parse ~s~%” token)))))))
finally (return (car stack))))
;; Now loop through and actually do it
(loop
(format t “~&> “)
(force-output)
(print (evaluate-rpn (read-line))))
And my undocumented python solution:
[…] is a simple calculator that handles Reverse Polish Notation (RPN) caculations. The problem is givenhere , and my solution in Java is given […]
Ruby example:
Example output:
RPN > 10 2 *
[20.0]
RPN > 5 +
[25.0]
RPN > 5 /
[5.0]
RPN > 3 –
[2.0]
RPN > 1
[2.0, 1.0]
RPN > +
[3.0]
RPN > 19 2.14 + 4.5 2 4.3 / – *
[3.0, 85.2974418604651]
; programming praxis exercise 1 – RPN Calculator
(defn rpn [stack value]
(let [[s1 s2] stack
v (eval (read-string value))]
(cond
(number? v) (conj stack v)
(fn? v) (conj (rest (rest stack)) (v s2 s1))
:else stack)))
(defn calc [stack line]
(let [newstack (reduce rpn stack (.split line " "))]
(println (first newstack))
newstack))
(defn rpn-repl []
(loop [stack ‘()]
(recur (calc stack (read-line)))))
A straightforward perl example with no error handling
Scheme version, worked to make adding new operations easy:
Here’s another ruby version, you can see it fully commented at http://steamcode.blogspot.com/2010/07/rpn-calculator.html
[…] And that is why in the lines to follow I will share my PHP solution to the RPC calculator challenge. […]
Here’s my own version:
A solution in F#: http://stefanoricciardi.com/2010/10/01/a-rpn-calculator-in-f/
My solution (almost ok with the constraints besides the one line thingy) in scheme (Gambit): http://github.com/AlexandreAbreu/programming-praxis-answers/blob/master/001.scm
Ruby – bit of a hack, but fun non-the-less.
[…] This exercise comes from programming praxis. […]
[…] of the earliest Programming Praxis challenges is called RPN Calculator . Our task is to write a RPN module capable of evaluating simple RPN expressions and return the […]
[…] my last article I’ve presented some solutions (scala, java, python) for the RPN Calculator exercise from Programming Praxis . Today I am going to present you the solution in Haskell […]
JScript version of the task
My Python version is somewhat clumsy.
Here’s how I solved it with Python. There’s not any error handling, but it’s a single purpose program so I didn’t really think it was necessary.
operators = ‘+-/*’
def get_input():
input = raw_input(“input: “)
return input
def number(num):
if ‘.’ in num:
return float(num)
elif num not in operators:
return int(num)
def parse_input(text):
text = text.split()
stack = []
for x in text:
if x.isdigit() or number(x):
stack.insert(0, number(x))
elif x in operators:
stack.insert(0, operate(stack, x))
return stack
def operate(nums, operator):
b = nums.pop(0)
a = nums.pop(0)
if operator == ‘+’:
return a + b
elif operator == ‘-‘:
return a – b
elif operator == ‘/’:
return a / b
else: return a * b
if __name__ == ‘__main__’:
answer = parse_input(‘get_input’)[0]
print answer
https://github.com/gcapell/ProgrammingPraxis/blob/master/01_rpn_calculator/RPN.go
Not sure about keeping operators as a map->function (it might be cleaner/simpler just to have a switch).
[…] zadanie to prosty kalkulator do wykonywania podstawowych operacji przy użyciu tzw. odwróconej notacji polskie…, która znakomicie sprawdza się przy traktowaniu danych wejściowych jako stosu (operator […]
Golang
Here is my C++ solution:
/*
* rpn.cpp
*
* Created on: Jun 13, 2012
* Author: amejo
*/
#include “Stack.h”
#include
#include
#include
#include
using namespace std;
/*Cal function will calulate the answer based on the operands */
float cal(float a,float b,char op){
float ans=0;
switch(op){
case ‘+’: ans = a+b;
break;
case ‘*’: ans = a*b;
break;
case ‘/’: ans = a/b;
break;
case ‘-‘: ans = a-b;
break;
case ‘^’:{ans = 1;
for(int i=1;i<=b;i++)
ans *= a;
}
break;
default: ans = 0.0;
break;
}
return ans;
}
bool not_space(char c){
return(!isspace(c));
}
bool space(char c){
return(isspace(c));
}
/* Splitter will split the string based on spaces and pushed in the string array */
void splitter(string s,vector &str){
string::iterator i=s.begin();
string::iterator j;
while(i!=s.end()){
//the below statement will find a character which is not space
i=find_if(i,s.end(),not_space);
//this will find the space character
j = find_if(i,s.end(),space);
if(i!=s.end()){
//using string constructor , word (i,j) is formed
str.push_back(string(i,j));
}
i=j;
}
return;
}
float rpncalculate(Stack &s,string expr){
/*Loop till the end of the string vector*/
vector str;
/* split the string into different strings */
splitter(expr,str);
string::iterator iter;
vector::iterator it=str.begin();
float op1,op2;//two operands
float res,ad;//ad will temp hold the operand
while(it!=str.end()){
/* Check if its an operand or an operator, if an operand push it in the stack
* for that another iterator is used to scan through the strings only 1st character needs
* to be checked if its digit or not*/
iter = (*it).begin();
/* if its digit then using istringstream the float value is read from the string and pushed
* into the stack
*/
if(isdigit(*iter)){
istringstream in (*it,ios::in);
in >> ad;
s.push(ad);
}
else{
/*If it is an operator , pop the two operands from the stack , perform the operation and put the result in the
* stack , in the end only the final result will remain */
op2 = s.pop();
op1 = s.pop();
//cout <<"op1= "<<op1<<" op2= "<<op2<<" operator= "<<*it<<endl;
res = cal(op1,op2,*iter);
s.push(res);
}
iter = (*it).end();
it++;
}
return s.pop();
}
int main(){
cout <<"Enter an expression to be evaluated"<<endl;
string str;
getline(cin,str);
Stack st;
float ans = rpncalculate(st,str);
cout << "ans = "<<ans;
return 0;
}
I know I’m a johnny program lately, but here is the guts of my PHP version.
Update…
Java Solution:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
LinkedList operands = new LinkedList();
String acceptedOperators = “+-*/”;
try {
BufferedReader rdr = new BufferedReader(new InputStreamReader(
System.in));
String inCalcs = rdr.readLine();
String[] inTokens = inCalcs.split(” “);
for (String string : inTokens) {
// try and parse the number and add to operands.
try {
Double operand = Double.parseDouble(string);
operands.push(operand);
}
// not a double, try and add it to operators…
catch (NumberFormatException e) {
// if string is one character, and is an accepted operator.
if (string.length() == 1
&& acceptedOperators.contains(string)) {
Double op2 = operands.pop();
Double op1 = operands.pop();
switch (string) {
case “+”:
operands.push(op1 + op2);
break;
case “-“:
operands.push(op1 – op2);
break;
case “*”:
operands.push(op1 * op2);
break;
case “/”:
operands.push(op1 / op2);
break;
default:
break;
}
System.out.format(“%s %s %s operandQueue: %s\r\n”, op1,
op2, string, operands);
}
}
// do nothing.
catch (NullPointerException e) {
}
}
} catch (IOException e) {
System.out.println(e.toString());
}
}
}
A bit late to the party, but my solution in Java is at http://ianp.org/2013/01/15/programming-praxis/
# -*- coding: utf-8 -*-
from __future__ import division
class Stack(object):
OPERATORS = {“+” : (lambda x, y : x+y),
“-” : (lambda x, y : x-y),
“/” : (lambda x, y : x/y),
“*” : (lambda x, y : x*y),
}
def __init__(self, top=None, value=None):
self.top = top
self.x = value
self.y = None
self.value = None
@staticmethod
def is_num(value):
try:
float(value)
return True
except ValueError:
return False
def push(self, value):
if self.is_num(value):
value = float(value)
if self.x is None:
self.x = value
elif self.y is None:
self.y = value
else:
if not isinstance(self.y, Stack):
self.y = Stack(self, self.y)
self.y.push(value)
elif value in self.OPERATORS:
if isinstance(self.y, Stack):
self.y.push(value)
else:
self.evaluate(value)
def evaluate(self, operator):
self.value = self.OPERATORS[operator](self.x, self.y)
if self.top:
self.top.pop()
else:
self.x = self.value
self.y = None
def pop(self):
self.y = self.y.value
def __repr__(self):
def strify(obj):
return str(obj) if obj is not None else ‘EMPTY’
return “” %(strify(self.x), strify(self.y))
if __name__ == “__main__”:
calc = Stack()
commands = “19 2.14 + 4.5 2 4.3 / – *”.split()
for c in commands:
calc.push(c)
print calc
print calc.value
python 2.7 with simulating stacks for RPN.
My Python solution, though Michael Wilber’s solution above, using the operator library, is better: https://gist.github.com/gmcclure/5475073
#Programming Praxis – RPN Calculator
#Solution by Meenakshi Madan
operators = “+-/%*”
exp_stack = []
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
exp = raw_input(“Enter the expression to be calculated\n”).split(‘ ‘)
for term in exp:
if is_number(term):
exp_stack.append(term)
elif term in operators:
try:
op2 = exp_stack.pop()
op1 = exp_stack.pop()
exp_stack.append(eval(str(op1) + term + str(op2)))
except:
print “Not enough operands. Please check your expression.”
exit()
else:
print “Invalid operators. Please check your expression.”
exit()
print exp_stack[0]
Just join CS class in Udacity.com so my understanding about phyton is very limited, but here is my solution:
def RPN(string):
string = string.split()
operated = []
index0 = 0 – len(string)
while index0 < 0:
if string[index0] == '+':
operated[-2] += operated[-1]
operated.pop()
elif string[index0] == '-':
operated[-2] -= operated[-1]
operated.pop()
elif string[index0] == '*':
operated[-2] *= operated[-1]
operated.pop()
elif string[index0] == '/':
operated[-2] /= operated[-1]
operated.pop()
else:
# Should have a try block here and
# return error if this next line fail
operated.append(float(string[index0]))
index0 += 1
return operated[0]
not sure why operated[-2]+= operated.pop() won't work and I haven't study try block
java:
jUnit tests:
In Golang: http://xojoc.pw/programming-praxis/rpn-calculator.html
using System;
using System.Collections.Generic;
namespace RPN
{
internal class Program
{
private static Stack stack = new Stack();
private static string data = “19 2.14 + 4.5 2 4.3 / – *”;
}