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

文章描述了一个团队设计和实现小学四则运算题目的命令行程序的过程。他们使用PSP表格进行个人软件过程管理,关注效能分析,主要函数是将后缀表达式转换为中缀表达式。团队成员通过结对编程,实现了表达式的随机生成、防重复、转换和计算答案等功能,并进行了单元测试以确保代码质量。
摘要由CSDN通过智能技术生成

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
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值