Guest User

Untitled

a guest
Dec 15th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.75 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. """ Evaluate given RPN expression. """
  3.  
  4. import sys
  5. import math
  6. import random
  7.  
  8. class RPNCalculator:
  9. """ Reverse Polish Notation calculator. """
  10. # Variable ans holds result of last operation.
  11. ans = 0
  12. def operator(self, tok):
  13. """ Return operator handler if tok is a valid operator. Otherwise return False. """
  14. def stacksum(stack):
  15. """ Return sum of all elements on stack (++ operator). """
  16. acc = 0
  17. while stack:
  18. acc += stack.pop()
  19. return acc
  20.  
  21. def stackproduct(stack):
  22. """ Return product of all elements on stack (** operator). """
  23. acc = 1
  24. while stack:
  25. acc *= stack.pop()
  26. return acc
  27.  
  28. # Operator handlers.
  29. operators = {
  30. '++': stacksum,
  31. '**': stackproduct,
  32. '+': lambda stack: stack.pop(-2) + stack.pop(),
  33. '-': lambda stack: stack.pop(-2) - stack.pop(),
  34. '*': lambda stack: stack.pop(-2) * stack.pop(),
  35. '/': lambda stack: stack.pop(-2) / stack.pop(),
  36. '%': lambda stack: stack.pop(-2) % stack.pop(),
  37. '^': lambda stack: stack.pop(-2) ** stack.pop(),
  38. '!': lambda stack: math.factorial(stack.pop()),
  39. 'e': lambda stack: math.e,
  40. 'pi': lambda stack: math.pi,
  41. 'ln': lambda stack: math.log(stack.pop()),
  42. 'log': lambda stack: math.log(stack.pop(-2), stack.pop()),
  43. 'log2': lambda stack: math.log(stack.pop(), 2),
  44. 'log10': lambda stack: math.log(stack.pop(), 10),
  45. 'rand': lambda stack: random.random(),
  46. 'sqrt': lambda stack: math.sqrt(stack.pop()),
  47. 'exp': lambda stack: math.exp(stack.pop()),
  48. 'sin': lambda stack: math.sin(stack.pop()),
  49. 'cos': lambda stack: math.cos(stack.pop()),
  50. 'tan': lambda stack: math.tan(stack.pop()),
  51. 'sinh': lambda stack: math.sinh(stack.pop()),
  52. 'cosh': lambda stack: math.cosh(stack.pop()),
  53. 'tanh': lambda stack: math.tanh(stack.pop()),
  54. 'arcsin': lambda stack: math.asin(stack.pop()),
  55. 'arccos': lambda stack: math.acos(stack.pop()),
  56. 'arctan': lambda stack: math.atan(stack.pop()),
  57. 'arcsinh': lambda stack: math.asinh(stack.pop()),
  58. 'arccosh': lambda stack: math.acosh(stack.pop()),
  59. 'arctanh': lambda stack: math.atanh(stack.pop()),
  60. 'max': lambda stack: max(stack.pop(), stack.pop()),
  61. 'min': lambda stack: min(stack.pop(), stack.pop()),
  62. 'abs': lambda stack: abs(stack.pop()),
  63. 'ans': lambda stack: self.ans,
  64. }
  65.  
  66. # Return operation handler if exists, otherwise return False.
  67. if tok in operators:
  68. return operators[tok]
  69. return False
  70.  
  71. def eval(self, expr, stack=None):
  72. """ Evaluate RPN expression and return result. """
  73. if stack is None:
  74. stack = []
  75. for token in expr:
  76. # If token is a valid number, push to stack.
  77. try:
  78. num = float(token)
  79. stack.append(num)
  80. continue
  81. except ValueError:
  82. pass
  83.  
  84. # If token is an operator, execute the operation.
  85. operation = self.operator(token)
  86. if operation:
  87. self.ans = operation(stack)
  88. stack.append(self.ans)
  89. continue
  90.  
  91. # Otherwise, raise exception.
  92. raise SyntaxError(f'invalid token "{token}"')
  93.  
  94. if len(stack) != 1:
  95. raise Warning('there should be exactly one element left on stack')
  96. return stack
  97.  
  98. def interactive():
  99. """ Interactive mode. """
  100. calc = RPNCalculator()
  101. stack = []
  102. while True:
  103. try:
  104. expr = input('=> ').split()
  105. if not expr or expr[0] == 'quit':
  106. break
  107. elif expr[0] == 'del':
  108. stack.pop()
  109. else: stack = calc.eval(expr, stack)
  110. except Warning:
  111. # Ignore that there is more than one element left on stack.
  112. pass
  113. except BaseException as error:
  114. # Print error if occurred and continue.
  115. print(f'Error: {error}')
  116. finally:
  117. # Print out the stack.
  118. for i, num in enumerate(stack):
  119. print('{:2<}: {}'.format(i, round(num, 6)))
  120.  
  121. def main():
  122. """ Evaluate expression passed as argument. If no arguments, run interactive mode. """
  123. if len(sys.argv) > 1:
  124. try:
  125. print('ans:', round(RPNCalculator().eval(sys.argv[1:])[0], 6))
  126. except (SyntaxError, Warning) as error:
  127. print(f'Error: {error}')
  128. else: interactive()
  129.  
  130. if __name__ == '__main__':
  131. main()
Add Comment
Please, Sign In to add comment