软件工程作业2

一、Github项目地址

https://github.com/000cxl000/Calculate/commit/0cbbbe90cb04241ce9ee5dcdc5ff43544ed98107

二、PSP

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

10

8

· Estimate

· 估计这个任务需要多少时间

10

8

Development

开发

660

800

· Analysis

· 需求分析 (包括学习新技术)

30

50

· Design Spec

· 生成设计文档

30

40

· Design Review

· 设计复审 (和同事审核设计文档)

10

15

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

5

5

· Design

· 具体设计

40

60

· Coding

· 具体编码

5h*60

7h*60

· Code Review

· 代码复审

1h*60

1.5h*60

· Test

· 测试(自我测试,修改代码,提交修改)

3h*60

4h*60

Reporting

报告

290

330

· Test Report

· 测试报告+博客

4h*60

4.5h*60

· Size Measurement

· 计算工作量

10

10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

35

50

合计

 

965

1273

 

三、项目要求

  1. 参与运算的操作数(operands)除了max_num(10)以内的整数以外,还要支持真分数的四则运算。操作数必须随机生成。
  2. 运算符(operators)+, , ×, ÷ 运算符的种类和顺序必须随机生成。
  3. 使用 -n 参数控制生成题目的个数

5. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 e2的子表达式,那么e1 e2

6. 每道题目中出现的运算符个数不超过5个。

7. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 45 + 23 = 是重复的题目

8. 在生成题目的同时,计算出所有题目的答案,并根据用户输入的结果进行判断对错,回答错误会有正确答案提示,并且统计得分。

 

四、解题思路

这个题目可以被划分为以下三个问题:

  1. 列出随机的四则运算表达式。
  2. 计算所列出四则运算的结果。
  3. 接受用户输入并比较结果是否正确,并在命令行中表现出来。

 

如何解决:

问题1

表达式生成

u 表达式的操作数比四则运算符数目多一个

u 操作数的个数可以随机

u 0 不能作为除数

计算过程中不能在某一步中出现负数(负数检测最终在计算器中实现)

  利用列表先随机生成1~5个运算符存入一个列表,通过列表长度生成对应个数的操作数,如果除号后的操作数等于0则重新生成一个。

  操作数的类型统一为分数类型(Fraction类),整数的分母为1,但由于整数,带分数,真分数的显示格式不同,所以定义了一个str_num()的方法将分数转换为符合标准的字符串。

 

括号的插入:

 

  插空法在运算符数组中随机成对插入括号,通过检测前后的运算符优先级判断是否需要插入括号。

 

问题2

通过将字符串表达式转换成逆波兰表达式和栈的操作实现表达式的优先级区分和具体计算。(具体的四则运算集成在Fraction类中不需要自己实现)

 

问题3

判断用户输入情况只需接受用户输入比较统计得分即可。由于要求采用命令行界面完成,该部分主要需要控制及美化命令行界面。

 

五、代码说明

1.项目文件结构如下:

模块

功能

main.py

主函数

stack.py

栈实现

ariExpression.py

生成表达式

infixTosuffix.py

将中缀表达式转成后缀表达式

Calculate.py

计算

 

核心函数为ariExpression(生成随机表达式)和Calculate(计算结果)

ariExpression

def __init__(self, max_num):

        self.init_operators()

        self.init_nums(max_num)

        self.init_expression()

 

    def init_num(self, max_num):

        '''随机生成数'''

        denominator = random.randint(1, max_num)

        numerator = random.randint(0, max_num)

        return Fraction(numerator, denominator)

 

def insert_bracket(self):

        '''插入括号'''

        bracket = ['(', 'null', ')']

        if len(self.operators) > 1:

            x = random.randint(0, len(self.operators))

            while x < len(self.operators):

                y = random.randint(x, len(self.operators))

                low = False

                for a in self.operators[x:y+1]:

                     if a in ['+', '-']:

                         low = True

                         break

                try:

                    if self.operators[y+1] in ['×', '÷'] and low:

                        self.operators.insert(x, '(')

                        self.operators.insert(y+2,')')

                except IndexError:

                    pass

                x = y+2

            

 

    def init_operators(self):

        '''随机生成一个运算符并随机插入括号'''

        self.operators = []

        operator = ['+', '-', '×', '÷', 'null']

        for x in range(5):

            if x == 1:

                self.operators.append(random.choice(operator[:-2]))

            else:

                y = random.choice(operator)

                if y != 'null':

                    self.operators.append(y)

        self.insert_bracket()

    

    def init_nums(self, max_num):

        self.nums = []

        self.nums.append(self.init_num(max_num))

        for x in range(len(self.operators)):

            y = self.init_num(max_num)

            if self.operators[x] == '÷':

                while y.numerator == 0:

                    y = self.init_num(max_num)

            self.nums.append(y)

 

Calculate

def getResult(expression):

    '''储存结果'''

    stackValue = []

    for item in expression:

        if item in ["+", "-", "×", "÷"]:

            n2 = stackValue.pop()

            n1 = stackValue.pop()

            result = cal(n1, n2, item)

            if result < 0:

                return -1

            stackValue.append(result)

        else:

            stackValue.append(item)

    return stackValue[0]

 

def cal(n1, n2, op):

    '''计算结果'''

    if op == "+":

        return n1 + n2

    if op == "-":

        return n1 - n2

    if op == "×":

        return n1 * n2

    if op == "÷":

        return n1 / n2

 

六、测试运行

运行结果如下所示:

 

 

七、效能分析

首先考虑到用户输入会影响效能分析中的时间因素,去掉了主函数中接受用户输入并比较的部分,直接改成由代码随机生成算式然后计算结果

 

 

效率不高的原因:

一条参数中使用很多方法嵌套。如:main()函数中:

real_res = Calculate.getResult(inf.str_to_fraction(inf.to_suffix_expression(ari.str)))

u 调用类中的其他函数。

 

 

posted @ 2019-03-20 18:30  000cxl000  阅读(201)  评论(0编辑  收藏  举报