小学四则运算改进版

软件工程第四周作业 —— 四则运算改进

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 包括加减乘、文件模式


8.4 测试错误输入

posted @ 2020-09-27 14:40  步平凡  阅读(302)  评论(0编辑  收藏  举报