小学四则运算改进版
软件工程第四周作业 —— 四则运算改进
1. 项目要求
1.1 要求阐述
在上一次作业的基础上进行一次升级,如下,至少选择一个升级方向:
- 功能升级
- 性能升级
- 界面升级
- 使用不同语言升级
1.2 详细要求【易知大学】
2. 项目成果
2.1 当前版本:2.0
2.2 GitHub代码【GitHub】
2.3 相比1.0版本
改进之处
- 改进了进入界面
- 增加输入模式的错误判断
- 增加
输出模式
:直接输出、问答模式、文件模式- 弃用字符串而使用
列表
存放算式- 改进中缀表达式的
生成
方式- 改进中缀表达式
转换
后缀表达式的方法- 改进后缀表达式的
计算方法
3. PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 15 |
+ Estimate | + 估计这个任务需要多少时间 | 15 | 15 |
Development | 开发 | 235 | 255 |
+ Analysis | + 需求分析 (包括学习新技术) | 25 | 30 |
+ Design Spec | + 生成设计文档 | 20 | 25 |
+ Design Review | + 设计复审 (和同事审核设计文档) | 20 | 15 |
+ Coding Standard | + 代码规范 (为目前的开发制定合适的规范) | 25 | 25 |
+ Design | + 具体设计 | 15 | 10 |
+ Coding | + 具体编码 | 60 | 75 |
+ Code Review | + 代码复审 | 25 | 20 |
+ Test | + 测试(自我测试,修改代码,提交修改) | 45 | 45 |
Reporting | 报告 | 85 | 80 |
+ Test Report | + 测试报告 | 35 | 35 |
+ Size Measurement | + 计算工作量 | 25 | 25 |
+ Postmortem & Process Improvement Plan | + 事后总结, 并提出过程改进计划 | 25 | 20 |
合计 | 335 | 350 |
4. 代码示例
4.1 ComputeFormular.getPostFormular()方法
def getPostFormular(self, formular_list):
'''
* 中缀表达式转为后缀表达式
* @param formular_list {list} 中缀表达式
* @return {list}
'''
# 运算符优先级
priority = {'×': 3, '÷': 3, '+': 2, '-': 2, '(': 1}
# 运算符栈
operator_stack = []
# 后缀表达式
post_formular_list = []
# 中缀表达式转为后缀表达式
while formular_list:
char = formular_list.pop(0)
if char == '(':
operator_stack.append(char)
elif char == ')':
oper_char = operator_stack.pop()
while oper_char != '(':
post_formular_list.append(oper_char)
oper_char = operator_stack.pop()
elif char in '+-×÷':
while operator_stack and priority[operator_stack[-1]] >= priority[char]:
post_formular_list.append(operator_stack.pop())
operator_stack.append(char)
else:
post_formular_list.append(char)
# 若符号栈不为空则循环
while operator_stack:
post_formular_list.append(operator_stack.pop())
# print(post_formular)
return post_formular_list
4.2 ComputeFormular.compute()方法
def compute(self, char, num01, num02):
'''
* 计算算式的值
* @param char {str} 运算符
* @param num01 {str} 第二个数字,可能为分数
* @param num02 {str} 第二个数字,可能为分数
* @return {str}
'''
if char == '+':
return (Fraction(num02) + Fraction(num01)).__str__()
elif char == '-':
return (Fraction(num02) - Fraction(num01)).__str__()
elif char == '×':
return (Fraction(num02) * Fraction(num01)).__str__()
elif char == '÷':
try:
return (Fraction(num02) / Fraction(num01)).__str__()
except Exception as e:
# print("Error: ", e)
return "NaN"
4.3 ComputeFormular.calcFormular()方法
def calcFormular(self, post_formular_list):
'''
* 计算算式的值
* @param post_formular_list {list} 后缀表达式
* @return {str}
'''
# 操作数栈
operand_stack = []
while post_formular_list:
char = post_formular_list.pop(0)
if char in '+-×÷':
result = self.compute(char, operand_stack.pop(), operand_stack.pop())
if result == "NaN":
return result
operand_stack.append(result)
else:
operand_stack.append(char)
return operand_stack.pop()
5. 单元测试
import unittest
from formula import OPT, GeneralFormular, ComputeFormular
class FormulaUnitTest(unittest.TestCase):
def test_gf_catFormular(self):
'''
* 测试拼接算式
'''
gf = GeneralFormular(OPT())
self.assertEqual(gf.catFormula("12", "+", "34"), "12#+#34")
self.assertEqual(gf.catFormula("23", "+", "456"), "23#+#456")
self.assertEqual(gf.catFormula("12", "+", "32"), "12#+#32")
def test_cf_getPostFormular(self):
'''
* 测试中缀表达式转为后缀表达式
'''
cf = ComputeFormular()
self.assertEqual(cf.getPostFormular(['3', '+', '7']), ['3', '7', '+'])
self.assertEqual(cf.getPostFormular(['3', '×', '(', '7', '+', '2', '+', '1', ')']), ['3', '7', '2', '+', '1', '+', '×'])
self.assertEqual(cf.getPostFormular(['6', '×', '(', '2', '+', '1', ')', '÷', '(', '9', '-', '2', '+', '3', ')']), ['6', '2', '1', '+', '×', '9', '2', '-', '3', '+', '÷'])
self.assertEqual(cf.getPostFormular(['6', '×', '(', '2', '+', '1', ')', '÷', '0']), ['6', '2', '1', '+', '×', '0', '÷'])
def test_cf_calcFormular(self):
'''
* 测试后缀表达式计算为数值
'''
cf = ComputeFormular()
self.assertEqual(cf.calcFormular(['3', '7', '+']), "10")
self.assertEqual(cf.calcFormular(['3', '7', '2', '+', '1', '+', '×']), "30")
self.assertEqual(cf.calcFormular(['6', '2', '1', '+', '×', '9', '2', '-', '3', '+', '÷']), "9/5")
self.assertEqual(cf.calcFormular(['6', '2', '1', '+', '×', '0', '÷']), "NaN")
def test_cf_compute(self):
'''
* 测试计算算式的值
'''
cf = ComputeFormular()
self.assertEqual(cf.compute('+', '29', '0'), '29')
self.assertEqual(cf.compute('-', '19', '0'), '-19')
self.assertEqual(cf.compute('×', '99', '0'), '0')
self.assertEqual(cf.compute('÷', '9', '0'), '0')
self.assertEqual(cf.compute('÷', '0', '9'), 'NaN')
self.assertEqual(cf.compute('÷', '0', '0'), 'NaN')
self.assertEqual(cf.compute('+', '1/4', '3/8'), '5/8')
if __name__ == "__main__":
unittest.main()
6. 性能分析
6.1 GeneralFormular.solve()
6.2 ComputeFormular.calcFormular()
6.3 ComputeFormular.solve()
7. 100万次运行
生成算式 | 计算算式 | |
---|---|---|
version 1.0 | 0:00:49 | 0:01:26 |
version 2.0 | 0:00:37 | 0:01:20 |
从表格来看,改进后的性能差别不是很大,但还是有一小点点的提升。
8. 运行测试
8.1 包含加减乘除、包含分数、直接输出模式
8.2 包含加减、问答模式
8.3 包括加减乘、文件模式