结对编程--小学四则运算

0.作业基本信息

这个作业属于哪个课程班级的链接
这个作业要求在哪里作业要求的链接
这个作业的目标实现一个自动生成小学四则运算题目的命令行程序
成员黄华健-3121005294,黄兆康-3121005171
其他参考文献
代码仓库地址

1.PSP表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划6060
· Estimate· 估计这个任务需要多少时间300380
Development开发200300
· Analysis· 需求分析 (包括学习新技术)200200
· Design Spec· 生成设计文档3050
· Design Review· 设计复审3030
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)1010
· Design· 具体设计2030
· Coding· 具体编码300300
· Code Review· 代码复审3040
· Test· 测试(自我测试,修改代码,提交修改)60100
Reporting报告100100
· Test Repor· 测试报告5050
· Size Measurement· 计算工作量2020
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划2020
· 合计14301690

2.效能分析

用pycharm的Profile插件对程序进行性能分析

在这里插入图片描述

程序中消耗最大的函数是to_infix()函数

    def to_show_infix(self, expr):
        expression = Functions.get_show_hou(self, expr)
        stack = []
        for token in expression:
            if token in Functions.operators:
                if len(stack) >= 2:
                    operand2 = stack.pop()
                    operand1 = stack.pop()
                    # 添加括号,保证运算顺序
                    stack.append(f"({operand1} {token} {operand2})")
                else:
                    operand = stack.pop()
                    if len(stack) > 0 and isinstance(stack[-1], list):
                        # 将操作数添加到前一个表达式中
                        stack[-1].append(token)
                        stack[-1].append(operand)
                    elif len(stack) > 0:
                        # 两个操作数和一个运算符组成一个表达式
                        stack.append([stack.pop(), token, operand])
                    else:
                        # 第一个操作数
                        stack.append(operand)
            else:
                # 操作数入栈
                stack.append(token)
        if len(stack) == 1 and isinstance(stack[0], list):
            # 如果只有一个表达式,则返回这个表达式
            stack = stack[0]
        return stack

3.设计与实现过程

3.1设计原理

  为实现小学四则运算题目出题程序,我们用随机生成后缀表达式,判断是否重复后,转换为中缀表达式,计算结果,并输出题目和答案至文档,统计用户的作答情况。

3.2实现过程

1.随机生成后缀表达式
  通过入栈出栈操作组成算式,生成过程中确保除数不为0,确保相邻的操作数之间有运算符,确保最后一个元素不为操作符,使生成的表达式合法,并确保式子结果不为负数。
2.判断后缀表达式是否重复
  每生成一个后缀表达式,就将生成的后缀表达式存入列表,下次生成表达式就先判断列表中是否已存在,存在即重复,重新生成后缀表达式。
3.将后缀表达式转换为中缀表达式
  通过栈类型来实现。
4.输出题目和答案至文档
  为实现分数运算,将所有数字转化为fractions.Fraction类型,将假分数转化为带分数,跟运算符结合成中缀表达式,写入题目文档,计算答案,写入答案文档。
5.读取题目及作答文档并导出作答情况
  读取题目文件内容,将数字读入存为fractions.Fraction类型,将带分数转化为整数加分数,跟运算符结合成中缀表达式,计算结果,与作答结果比较,导出作答情况

一个functions类中主要有5个函数
分别为gen_writ(),get_ans(),generate_expression(),to_show_infix(),gen_fraction()

关键函数为to_show_infix(expression)函数
流程图如下
在这里插入图片描述

4.代码说明

下面是三个重要的函数的

# 生成随机的后缀表达式
    def generate_expression(self, max_num):
        stack = []
        # 随机生成表达式的长度
        for i in range(random.randint(3, 10)):
            if len(stack) >= 2:
                # 随机选择两种操作:加入一个操作符或者进行一次运算
                if random.randint(0, 1) == 1:
                    # 随机选择一个运算符
                    operator = Functions.random_operator(self)
                    operand2 = stack.pop()
                    operand1 = stack.pop()
                    # 确保除数不为0
                    if operator == '÷' and operand2 == '0':
                        operand2 = Functions.gen_number(self, max_num)
                    stack += [operand1, operand2, operator]
                else:
                    # 添加一个操作数
                    # 确保相邻的操作数之间有运算符
                    if isinstance(stack[-1], str):
                        stack.append(Functions.random_operator(self))
                    stack.append(Functions.gen_number(self, max_num))
            else:
                # 第一个操作数
                stack.append(Functions.gen_number(self, max_num))
        # 确保最后一个元素不为操作符
        if isinstance(stack[-1], str):
            stack.pop()
        return stack

# 将后缀表达式转换为中缀表达式
    def to_show_infix(self, expr):
        expression = Functions.get_show_hou(self, expr)
        stack = []
        for token in expression:
            if token in Functions.operators:
                if len(stack) >= 2:
                    operand2 = stack.pop()
                    operand1 = stack.pop()
                    # 添加括号,保证运算顺序
                    stack.append(f"({operand1} {token} {operand2})")
                else:
                    operand = stack.pop()
                    if len(stack) > 0 and isinstance(stack[-1], list):
                        # 将操作数添加到前一个表达式中
                        stack[-1].append(token)
                        stack[-1].append(operand)
                    elif len(stack) > 0:
                        # 两个操作数和一个运算符组成一个表达式
                        stack.append([stack.pop(), token, operand])
                    else:
                        # 第一个操作数
                        stack.append(operand)
            else:
                # 操作数入栈
                stack.append(token)
        if len(stack) == 1 and isinstance(stack[0], list):
            # 如果只有一个表达式,则返回这个表达式
            stack = stack[0]
        return stack


# 计算运算结果
    def get_ans(self, expr, note=1):
        frac = "Fraction("
        if note == 1:  # 生成表达式时使用
            infix_expression = Functions.to_show_infix(self, expr)  # 后缀转中缀
            expression = infix_expression[0]
        else:  # 读取表达式时使用
            expression = expr
        # print("中缀表达式:", infix_expression)
        formul1 = Functions.tranc(self, expression)  # x换成*
        # print(formul1)
        formul1 = Functions.first(self, formul1)  # 分数的/换,
        formul2 = ''
        flag = 0
        length = len(formul1)
        for i in range(length):  # 将带分数的‘换为+
            if formul1[i] == "'":
                formul2 += '+'
                continue
            if formul1[i] not in Functions.numb and formul1[i] != "'":
                formul2 += formul1[i]
                continue
            if formul1[i] in Functions.numb and formul1[i - 1] not in Functions.numb:  # 读取到的数拼接成分数函数,并看情况加括号
                formul2 = formul2 + '(' + frac + formul1[i]
                if formul1[i + 1] not in Functions.numb and formul1[i + 1] != "'":
                    formul2 = formul2 + ')' + ')'
                elif formul1[i + 1] not in Functions.numb and formul1[i + 1] == "'":
                    formul2 += ')'
                    flag = 1
                continue
            elif formul1[i] in Functions.numb:
                formul2 = formul2 + formul1[i]
                if formul1[i + 1] not in Functions.numb and formul1[i + 1] != "'":
                    if flag == 1:
                        formul2 = formul2 + ')' + ')' + ')'
                        flag = 0
                    else:
                        formul2 = formul2 + ')' + ')'
                elif formul1[i + 1] not in Functions.numb and formul1[i + 1] == "'":
                    formul2 = formul2 + ')'
                    flag = 1
                continue
        formul2 = Functions.tranz(self, formul2)  # ÷换成/
        # print(formul2)
        ans = eval(formul2)
        return ans

5.测试运行

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.单元测试

测试代码

import unittest
import random
import math
from fractions import Fraction
from functions import *


class MyTestCase(unittest.TestCase):
    def test_something(self):
        function = Functions()
        exerc = open('Exercises.txt', 'w').close()
        exerc = open('Exercises.txt', 'w')
        ans = open('Answers.txt', 'w').close()
        ans = open('Answers.txt', 'w')
        s = ['1', '2', '3', '+', '6', '×', '+', '3', '4', '*', '-']
        formul = "(1+((2+3)×6)-3×4)"
        self.assertEqual(function.get_ans(formul, 0), 19)
        self.assertEqual(function.gen_writ(exerc, ans, 2, 10), 0)
        self.assertEqual(function.check(), 0)

if __name__ == '__main__':
    unittest.main()

代码覆盖率
在这里插入图片描述

7.项目小结

1.结对编程需要考虑代码的可读性。团队协作当中,代码需要成员之间相互理解,制定一些标准,在必要的地方给出合适的注释是非常有必要的。
2.要合理分配工作,发挥团队效益。结对编程需要有合理的分工,发挥团队作用,提高彼此之间的沟通能力和团队协作能力,这些是个人编程所欠缺的。
3.兆康的资料搜索能力较强,但是python语言需要再系统学习一下。华健算法的设计思维较好,但是编码能力和成员沟通能力还需强化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值