More powerful version of the RPN code in development, treat as unstable expect to use most of your available program memory. Additions over the simple RPN version are; str and rcl for storing and recalling a memory value; auto for standard format numbers; fix for setting fixed decimal notation (push a number to the stack first for the number of places, i.e. 2 fix for rounding to two decimal places); eng for engineering notation (where the exponent is in powers of a thousand); si for displaying International System units (G, M, k, m, u, n, etc).
from math import * from random import random ops = {'+': [2,lambda x,y: x+y], '-': [2,lambda x,y: x-y], '*': [2,lambda x,y: x*y], '/': [2,lambda x,y: x/y], 'pow': [2,lambda x,y: pow(x,y)], 'sqr': [1,lambda x: x*x], 'recip': [1,lambda x : 1/x], '!': [1,lambda x: fact(int(round(x)))], 'deg': [1,lambda x: degrees(x)], 'rad': [1,lambda x: radians(x)], 'log': [1,lambda x: log(x)], 'log10': [1,lambda x: log10(x)], 'sqrt': [1,lambda x: sqrt(x)], 'sin': [1,lambda x: sin(x)], 'cos': [1,lambda x: cos(x)], 'tan': [1,lambda x: tan(x)], 'asin': [1,lambda x: asin(x)], 'acos': [1,lambda x: acos(x)], 'atan': [1,lambda x: atan(x)], 'pi': [0,pi], 'e': [0,e], 'rnd': [0,random()]} def evaluate(tokens, s, mem): for t in tokens: if t == 'swap': if len(s) >= 2: a = s.pop(); b = s.pop() s.append(a); s.append(b) elif t == 'roll': if len(s) >= 2: s.insert(0, s.pop()) elif t == 'drop': if len(s) >= 1: s.pop() elif t == 'clr': s = [] elif t == 'sto': if len(s) >= 1: mem = s[-1] elif t == 'rcl': s.append(mem) elif t in ops: op = ops[t][1] q = ops[t][0] if q == 0: s.append(op) elif q == 1 and len(s) >= 1: a = s.pop() try: s.append(op(a)) except: print("Err"); s.append(a) elif q == 2 and len(s) >= 2: a = s.pop(); b = s.pop() try: s.append(op(b,a)) except: print("Err"); s.append(b); s.append(a) elif set(t).issubset(set("0123456789.-")): s.append(float(t)) else: print("Err %s" % t) return s, mem def p(s): print(s, end='') def fact(n): f = 1 while n > 0: f *= n; n -= 1 return f def eng_not(n, fix): for exp in range(-24, 25, 3): if abs(n) < pow(10, exp): break return '{}E{}'.format(n/float(pow(10, exp-3)), exp-3) def si_not(n, fix): i = 0 for exp in range(-24, 25, 3): if abs(n) < pow(10, exp): break i += 1 u = 'yzafpnum kMGTPEZY'[i-1] if u == ' ': u = '' return '{}{}'.format(n/float(pow(10, exp-3)), u) s = [] mem = 0.0 fix = 3 mode = 0 while True: expr = input('> ') if expr == 'q': break elif expr == 'fix': if len(s) >= 1: fix = abs(int(round(s.pop()))); auto = False elif expr == 'auto': mode=0 elif expr == 'eng': mode=1 elif expr == 'si': mode=2 elif expr == '?': print('Help:', end=' ') w = 0 for o in sorted(list(ops.keys()) + ['fix','eng','si','auto','sto','rcl','?','q','clr','swap','roll','drop']): print(o, end=' '); w += 1 if w > 5: print(); w = 0 if w != 0: print() continue elif len(expr) == 0: continue else: s, mem = evaluate(expr.split(), s, mem) print('[', end='') for i in s: if mode==0: p(i) elif mode==1: p(eng_not(i, fix)) elif mode==2: p(si_not(i, fix)) else: p('{:.{p}f}'.format(i, p=fix)) if i is not s[-1]: p(', ') else: print(']')