RPN Calculator - Keeping Boredom Away

Alright, those who know me well are bound to ask, 19 credit hours and you are bored? Answer: Yes. It is still the first week and we don’t seem to have gotten beyond the “introduce your loser self to the other non-interested members of the class” and since I have only 1 programming intensive course this semester, I should have lots of time to kill.

Well, my first script this semester is an RPN calculator. Totally useless for the vast majority of people out there but they know what to expect from someone who likes theoretical computer science.

So, I first began with a stack - in this case an array. I then keep populating it with numbers and every time the state of the stack changes, it prints out the current state.

If an operation is entered (only +, -, * and /), it performs the operation, replaces the appropriate positions in the stack and then prints out the current state.

Here is the code, Its been a while since I wrote any OOP stuff in Python and the “self” especially feels weird after an entire semester of Java…

#!/usr/bin/env python
#Author: Shriphani Palakodety
#Mail: shriphani@shriphani.com
#RPN Calculator

class Machine:
        def __init__(self, stack=[]):
                self.stack = []

        def modifyStack(self, element):
                ‘add to stack if input is float else run operation or complain’

                if self.isOperator(element):
                        self.operate(element)
                        self.printStack()
                elif self.isFloat(element):
                        self.stack.append(element)
                        self.printStack()

                else:
                        print "Only numbers and operators"

        def isFloat(self, char):
                ‘Checks whether the last item entered in the stack is a float or not’
                try:
                        float(char)
                except ValueError:
                        return False
                return True

        def isOperator(self, char):
                ‘Checks whether the last item entered in the stack is an operator or not’
                if char == ‘+’ or char == ‘-’ or char == ‘*’ or char == ‘/’:
                        return True
                else:
                        return False

        def operate(self, operator):
                ‘Perform the stated operation on the last two elements in the stack’
               
                operand1 = float(self.stack[-1])
                operand2 = float(self.stack[-2])

                self.stack.pop(-1)
                self.stack.pop(-1)

                if operator==‘+’:
                        self.stack.append(operand1+operand2)

                elif operator==‘-’:
                        self.stack.append(operand2-operand1)

                elif operator==‘*’:
                        self.stack.append(operand1*operand2)

                elif operator==‘/’:
                        self.stack.append(float(operand2)/float(operand1))

                else:
                        print "God only knows what operation you have typed in"
                        self.stack += [operand2, operand1]
                        self.printStack()

        def printStack(self):
                print self.stack

       
def kickOff():
        calc = Machine()
        while True:
                a = raw_input(‘Input: ‘)
                if a != :
                        calc.modifyStack(a)
                else:
                        calc.printStack()
                        raise SystemExit

print"Press Enter to Quit\n"
kickOff()
 

The calculator in action:

pal-179-083:~ shriphani$ python rpn.py
Press Enter to Quit

Input: 1
['1']
Input: 2
['1', '2']
Input: 3
['1', '2', '3']
Input: 4
['1', '2', '3', '4']
Input: 5
['1', '2', '3', '4', '5']
Input: +
['1', '2', '3', 9.0]
Input: h
Only numbers and operators
Input: -
['1', '2', -6.0]
Input:
['1', '2', -6.0]

In other news, I am really pissed with Picasa since I can’t see how many people have viewed my pics (http://picasaweb.google.com/shriphanip in case you are interested), I have begun filling my playlists with songs played at apple keynotes and in apple ads. Friends say this is an obsession with everything with the Apple stamp on it. I basically don’t care.

There has always been this one question bugging me since last semester. In Java:

 class Test
{
        public static void main(String[] args)
        {
                int a = 012345;
                System.out.println(a);
        }
}
 

When I run this:

pal-179-083:~ shriphani$ java Test
5349
pal-179-083:~ shriphani$

What is happening here?

Anyway, looking forward to this semester. Hope my GPA stays at 4.0

17 comments ↓

#1 Paul Holt on 01.14.09 at 8:47 pm

octal

#2 Kevin McCravy on 01.14.09 at 8:50 pm

For the Java question: By starting the literal with a zero you’ve designated it to be in octal, or base 8. In Python try “print oct(5349)”.

#3 Michael Foord on 01.14.09 at 8:58 pm

The same thing happens in Python. The leading 0 on your integer makes it an octal number.

#4 DavidM on 01.14.09 at 9:07 pm

That is octal format: “012345″

#5 Anonymous on 01.14.09 at 9:19 pm

A leading zero specifies an octal constant. Similarly, a leading 0x specifies a hex constant.

#6 Dave Warner on 01.14.09 at 9:25 pm

You are specifying an octal value (leading ‘zero’ flags value as an octal to the compiler) and println is outputting decimal.

#7 Aaron on 01.14.09 at 9:27 pm

In response to your question:

12345 in octal is 5349 in decimal so perhaps Java takes a “0″ prefix to mean the number is in octal.

This is just a guess as my Java experience ended when I started to learn Python (3+ years ago).

#8 foo on 01.14.09 at 9:39 pm

> int a = 012345;

That would be octal. From http://java.sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html:

“”"
The prefix 0 indicates octal, whereas 0x indicates hexadecimal.


int octVal = 032; // The number 26, in octal
“”"

#9 Jeff on 01.15.09 at 12:03 am

Oh, I know, Octal! ;-)

#10 Marius Gedminas on 01.15.09 at 10:11 am

I won’t mention the word “octal” since nine people before me have already done so. ;-)

A couple of suggestions for the Python code: the de facto standard indentation, also blessed by the official style guide (PEP 8) is 4 spaces per level, not 8.

You can express the operator check more concisely as
return char in ['+', '-', '*', '/']

Also, ‘char’ is not a particularly good name since it may well be a multi-character string containing a floating point number.

list.pop() defaults to popping the last item, so passing -1 is redundant.

You’ve already converted both operands to floats when you extracted them from the stack (personally, I’d convert them when inserting into the stack, but whatever), so there’s no need for a repeated conversion where you’re implementing division. On the other hand, this may be a place where explicit is better than implicit.

Machine.__init__ ignores the stack argument. Also beware of using mutable types such as lists for default argument values, you can easily end up sharing objects without intending to do so.

I’d also use ‘return’ in place of ‘raise SystemExit’.

#11 Marius Gedminas on 01.15.09 at 10:13 am

Small clarification: it was supposed to be “PEP 8″ (http://www.python.org/dev/peps/pep-0008/) followed by a closing parenthesis, and not a smiley at all.

#12 xtian on 01.15.09 at 1:08 pm

Octal octal, octal octal octal. Octal octal octal; octal.

Oc tal octaaaaaaaaaaaallllllll!

#13 Shriphani on 01.15.09 at 2:40 pm

Marius:
Thanks for your comments. Will keep them in mind.

Everyone Else
Thanks for answering my question.

#14 Dethe Elza on 01.15.09 at 5:09 pm

Someone suggested that the leading 0 will produce octal content in Python. While this used to be true, it has been fixed in more recent versions (I tested in Python 2.5.2). To interpret a string as an octal value in Python you now are expected to pass the base to int, thus:

>>> int(’012345′)
12345

but

>>> int(’012345′, 8)
5349

“Explicit is better than implicit” strikes again

#15 Dethe Elza on 01.15.09 at 5:11 pm

If you’re going to have folks talking about code, turning off automatic smiley’s would be a good step. The second example above should have ended with an eight (8) followed by a closing parenthesis.

#16 rcriii on 01.15.09 at 8:16 pm

May I suggest adding this to __init__:

self.operations = {'+':lambda o1, o2:o1+o2,
                              '-':lambda o1, o2:o1-o2,
                              '*':lambda o1, o2:o1*o2,
                              '/':lambda o1, o2:o1/o2,
                              '^':lambda o1, o2:o1**o2}

The isOperator becomes:
def isOperator(self, char):
                """Checks whether the last item entered in the stack is an operator or not"""
                if char in self.operations.keys():
                        return True
                else:
                        return False

and Operate() becomes:

def operate(self, operator):
                """"Perform the stated operation on the last two elements in the stack"""
                operand1 = float(self.stack[-1])
                operand2 = float(self.stack[-2])

                self.stack.pop()
                self.stack.pop()

                    self.stack.append(self.operations[operator](operand1, operand2))

And adding operators becomes quite easy.

#17 Shriphani on 01.16.09 at 1:50 am

I’ve disabled automatic smileys. That shouldn’t be a problem anymore.

Dethe Elza:
Thanks a lot for mentioning that.

rcriii:
That looks cool. Thanks for posting your version.

Leave a Comment