Python implements a simple arithmetic calculator, python
I. Algorithms
1. The main idea of the algorithm is to convert an Infix expression into a Postfix expression, and then use the stack's simple data structure, returns the result of an expression.
2. The detailed description of how to convert a common expression to a suffix expression and how to process a suffix expression and calculate the result is not described here.
Ii. Simple Calculator
Instructions for use
A simple example of using this calculator class is as follows:
# usagec = Calculator()print('result: {:f}'.formart(c.get_result('1.11+2.22-3.33*4.44/5.55')))# output:result: 0.666000
Test Case
To effectively test the calculator, several groups of test cases are designed. The test results are as follows:
Test No.1: (1.11) = 1.110000Test No.2: 1.11+2.22-3.33*4.44/5.55 = 0.666000Test No.3: 1.11+(2.22-3.33)*4.44/5.55 = 0.222000Test No.4: 1.11+(2.22-3.33)*(4.44+5.55)/6.66 = -0.555000Test No.5: 1.11*((2.22-3.33)*(4.44+5.55))/(6.66+7.77) = -0.852992Test No.6: (1.11+2.22)*(3.33+4.44)/5.55*6.66 = 31.048920Test No.7: (1.11-2.22)/(3.33+4.44)/5.55*(6.66+7.77)/(8.88) = -0.041828Test No.8: Error: (1.11+2.22)*(3.33+4.44: missing ")", please check your expressionTest No.9: Error: (1.11+2.22)*3.33/0+(34-45): divisor cannot be zeroTest No.10: Error: 12+89^7: invalid character: ^
Implementation Code
Stack implementation
The stack is actually a restricted table. All operations can only be performed at the top of the stack (for example, inbound and outbound stacks). The following is a simple stack implemented using Python code:
class Stack(object): """ The structure of a Stack. The user don't have to know the definition. """ def __init__(self): self.__container = list() def __is_empty(self): """ Test if the stack is empty or not :return: True or False """ return len(self.__container) == 0 def push(self, element): """ Add a new element to the stack :param element: the element you want to add :return: None """ self.__container.append(element) def top(self): """ Get the top element of the stack :return: top element """ if self.__is_empty(): return None return self.__container[-1] def pop(self): """ Remove the top element of the stack :return: None or the top element of the stack """ return None if self.__is_empty() else self.__container.pop() def clear(self): """ We'll make an empty stack :return: self """ self.__container.clear() return self
Calculator implementation
In the calculator class, we put the expression legality verification in a single function, but in fact, you can also directly put it in a function with an infix expression to a suffix expression, in this way, you only need to traverse the expression once to complete verification and conversion at the same time. However, in order to keep the structure clear, it is better to implement the function separately. It is more practical to do the best thing possible for each function.
In this calculator class, there are many extreme cases that are not taken into account, because the entire implementation code will be more. However, you can continue to expand the entire class at a later stage. It is also possible to add new functions. Currently, the main framework is implemented, including basic error detection and computation. The focus is to use the seemingly simple but powerful data structure of stack to solve the problem.
class Calculator(object): """ A simple calculator, just for fun """ def __init__(self): self.__exp = '' def __validate(self): """ We have to make sure the expression is legal. 1. We only accept the `()` to specify the priority of a sub-expression. Notes: `[ {` and `] }` will be replaced by `(` and `)` respectively. 2. Valid characters should be `+`, `-`, `*`, `/`, `(`, `)` and numbers(int, float) - Invalid expression examples, but we can only handle the 4th case. The implementation will be much more sophisticated if we want to handle all the possible cases.: 1. `a+b-+c` 2. `a+b+-` 3. `a+(b+c` 4. `a+(+b-)` 5. etc :return: True or False """ if not isinstance(self.__exp, str): print('Error: {}: expression should be a string'.format(self.__exp)) return False # Save the non-space expression val_exp = '' s = Stack() for x in self.__exp: # We should ignore the space characters if x == ' ': continue if self.__is_bracket(x) or self.__is_digit(x) or self.__is_operators(x) \ or x == '.': if x == '(': s.push(x) elif x == ')': s.pop() val_exp += x else: print('Error: {}: invalid character: {}'.format(self.__exp, x)) return False if s.top(): print('Error: {}: missing ")", please check your expression'.format(self.__exp)) return False self.__exp = val_exp return True def __convert2postfix_exp(self): """ Convert the infix expression to a postfix expression :return: the converted expression """ # highest priority: () # middle: * / # lowest: + - converted_exp = '' stk = Stack() for x in self.__exp: if self.__is_digit(x) or x == '.': converted_exp += x elif self.__is_operators(x): converted_exp += ' ' tp = stk.top() if tp: if tp == '(': stk.push(x) continue x_pri = self.__get_priority(x) tp_pri = self.__get_priority(tp) if x_pri > tp_pri: stk.push(x) elif x_pri == tp_pri: converted_exp += stk.pop() + ' ' stk.push(x) else: while stk.top(): if self.__get_priority(stk.top()) != x_pri: converted_exp += stk.pop() + ' ' else: break stk.push(x) else: stk.push(x) elif self.__is_bracket(x): converted_exp += ' ' if x == '(': stk.push(x) else: while stk.top() and stk.top() != '(': converted_exp += stk.pop() + ' ' stk.pop() # pop all the operators while stk.top(): converted_exp += ' ' + stk.pop() + ' ' return converted_exp def __get_result(self, operand_2, operand_1, operator): if operator == '+': return operand_1 + operand_2 elif operator == '-': return operand_1 - operand_2 elif operator == '*': return operand_1 * operand_2 elif operator == '/': if operand_2 != 0: return operand_1 / operand_2 else: print('Error: {}: divisor cannot be zero'.format(self.__exp)) return None def __calc_postfix_exp(self, exp): """ Get the result from a converted postfix expression e.g. 6 5 2 3 + 8 * + 3 + * :return: result """ assert isinstance(exp, str) stk = Stack() exp_split = exp.strip().split() for x in exp_split: if self.__is_operators(x): # pop two top numbers in the stack r = self.__get_result(stk.pop(), stk.pop(), x) if r is None: return None else: stk.push(r) else: # push the converted number to the stack stk.push(float(x)) return stk.pop() def __calc(self): """ Try to get the result of the expression :return: None or result """ # Validate if self.__validate(): # Convert, then run the algorithm to get the result return self.__calc_postfix_exp(self.__convert2postfix_exp()) else: return None def get_result(self, expression): """ Get the result of an expression Suppose we have got a valid expression :return: None or result """ self.__exp = expression.strip() return self.__calc() """ Utilities """ @staticmethod def __is_operators(x): return x in ['+', '-', '*', '/'] @staticmethod def __is_bracket(x): return x in ['(', ')'] @staticmethod def __is_digit(x): return x.isdigit() @staticmethod def __get_priority(op): if op in ['+', '-']: return 0 elif op in ['*', '/']: return 1
Summary
The above is the use of Python to implement all the content of the simple arithmetic calculator. I hope the content in this article will be helpful for your study or work. If you have any questions, please leave a message.
Reference
Description of algorithms in data structure and algorithm (c)