软件工程 | 计科21级2班 |
---|---|
作业要求 | 结对项目-实现四则运算题目生成 |
作业目标 | 合作完成四则运算题目生成项目 |
成员信息
姓名 | 学号 |
---|---|
杨恒 | 3121005146 |
游烽 | 3121005148 |
Github:https://github.com/wcng010/SoftwareWork2
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
Estimate | 估计这个任务需要多少时间 | 20 | 20 |
Development | 开发 | 480 | 480 |
Analysis | 需求分析 (包括学习新技术) | 120 | 150 |
Design Spec | 生成设计文档 | 30 | 30 |
Design Review | 设计复审 | 30 | 30 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
Design | 具体设计 | 20 | 5 |
Coding | 具体编码 | 180 | 300 |
Code Review | 代码复审 | 20 | 5 |
Test | 测试(自我测试,修改代码,提交修改) | 30 | 30 |
Reporting | 报告 | 30 | 10 |
Test Repor | 测试报告 | 20 | 10 |
Size Measurement | 计算工作量 | 10 | 5 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 10 | 20 |
合计 | 1040 | 1145 |
环境:c++
设计实现过程
设计思路
1.运算式生成使用随机数和随机运算符,需要考虑除法的特殊性、运算符的个数和运算式重复等约束。
2.计算采用基于优先级的四则运算规则,根据括号优先、乘除优先和加减顺序的优先级规则进行运算。
3.文件存取通过调用现有的接口实现。
主要函数
- 自定义运算类
namespace Mymath {
inline int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
class MyFraction {
private:
int numerator;
int denominator;
public:
explicit MyFraction(){}
explicit MyFraction(const int num1,const int num2) :numerator(num1), denominator(num2) {}
//explicit MyFraction(const MyFraction& f) :numerator(f.numerator), denominator(f.denominator) {}
MyFraction operator+(const MyFraction& f) const;
MyFraction operator -(const MyFraction& f) const;
MyFraction operator *(const MyFraction& f) const;
MyFraction operator /(const MyFraction& f) const;
std::string GetValue();
float Get();
int GetNumerator();
int GetDenominator();
void FractionReduction();
bool IsPositive();
virtual ~ MyFraction();
};
}
- 功能函数(字符串格式转换、判别运算式是否符合约束条件等)
std::string Mymath::MyFraction::GetValue()
float Mymath::MyFraction::Get()
int Mymath::MyFraction::GetNumerator()
int Mymath::MyFraction::GetDenominator()
void Mymath::MyFraction::FractionReduction()
bool Mymath::MyFraction::IsPositive()
- 运算函数(加减乘除)
Mymath::MyFraction Mymath::MyFraction::operator +(const MyFraction& f) const
Mymath::MyFraction Mymath::MyFraction::operator -(const MyFraction& f) const
Mymath::MyFraction Mymath::MyFraction::operator *(const MyFraction& f) const
Mymath::MyFraction Mymath::MyFraction::operator /(const MyFraction& f) const
具体实现
- 加减乘除运算
将运算过程封装到函数中,方便调用。
Mymath::MyFraction Mymath::MyFraction::operator +(const MyFraction& f) const
{
MyFraction temp;
temp.numerator = numerator * f.denominator + f.numerator * denominator;
temp.denominator = denominator * f.denominator;
return temp;
}
Mymath::MyFraction Mymath::MyFraction::operator -(const MyFraction& f) const
{
MyFraction temp;
temp.numerator = numerator * f.denominator - f.numerator * denominator;
temp.denominator = denominator * f.denominator;
return temp;
}
Mymath::MyFraction Mymath::MyFraction::operator*(const MyFraction& f) const
{
MyFraction temp;
temp.numerator = numerator * f.numerator;
temp.denominator = denominator * f.denominator;
return temp;
}
Mymath::MyFraction Mymath::MyFraction::operator/ (const MyFraction& f) const
{
MyFraction temp;
temp.numerator = numerator * f.denominator;
temp.denominator = denominator * f.numerator;
return temp;
}
- 单元计算
单元计算模块的设计有三个方面的要求,分别是将完成运算的两个值从分数数组中删除,将结果添加进入数组、将完成运算的运算符删除和将完成运算的运算符优先级删除。
void Mymath::Arithmetic::CalculateSingle(const int& index1, const int& index2)
{
MyFraction fraction;
switch (operatorVec[index1][index2])
{
case add:
fraction = fractionVec[index1][index2] + fractionVec[index1][index2 + 1];
break;
case subtract: fraction = fractionVec[index1][index2] - fractionVec[index1][index2 + 1];
break;
case multiply: fraction = fractionVec[index1][index2] * fractionVec[index1][index2 + 1];
break;
case divide: fraction = fractionVec[index1][index2] / fractionVec[index1][index2 + 1];
break;
default:break;
}
//处理不符合要求的数据
if (fraction.Get()<0 && WrongNum.size() == 0) { WrongNum.emplace_back(index1); }
else if (fraction.Get()<0 && index1 != WrongNum[WrongNum.size() - 1]) { WrongNum.emplace_back(index1);}
//移除计算后的数据
std::vector<operatorType>::iterator it = operatorVec[index1].begin() + index2;
operatorVec[index1].erase(it);
std::vector<operatorPriority>::iterator it1 = operatorPriorityVec[index1].begin() + index2;
operatorPriorityVec[index1].erase(it1);
std::vector<MyFraction>::iterator it2 = fractionVec[index1].begin() + index2;
fractionVec[index1].erase(it2, it2 + 2);
std::vector<MyFraction>::iterator it3 = fractionVec[index1].begin() + index2;
fractionVec[index1].insert(it3, fraction);
}
- 数值提取
std::string Mymath::MyFraction::GetValue()
{
//分母是
/**if (denominator % numerator == 0 && numerator / denominator != 0)
return std::to_string(numerator/denominator);
//分母小于分子
else if (denominator<numerator)
{
int left = numerator/denominator;
int right = numerator % denominator;
return std::to_string(left) + "'" + std::to_string(right) + "/" + std::to_string(denominator);
}
else
{
return std::to_string(numerator) + "/" + std::to_string(denominator);
}*/
//输出前先约分
FractionReduction();
//分子小于分母
if (numerator < denominator)
{
return std::to_string(numerator) + "/" + std::to_string(denominator);
}
//分子大于分母且不成比例
else if (numerator > denominator && numerator % denominator != 0 && denominator != 1)
{
return std::to_string(numerator / denominator) + "'" + std::to_string(numerator % denominator) + "/" + std::to_string(denominator);
}
else if (numerator % denominator == 0)
{
return std::to_string(numerator / denominator);
}
return " ";
}
- 分数计算
void Mymath::MyFraction::FractionReduction()
{
// 分子为0,则分母为1
if (numerator == 0) denominator = 1;
// 如果分母为负数,则分子分母变号
if (denominator < 0)
{
numerator = -numerator;
denominator = -denominator;
}
// 约分: 分子分母同时除以最大公约数
int x = gcd(abs(numerator), abs(denominator));
numerator /= x;
denominator /= x;
}
性能分析和测试
性能分析
生成10道题目时
从图中看出,在生成题目数少的情况下,将计算结果进行输出的函数在程序运行时间中占比很高,进行计算的模块时间占比少,这是合理现象。
函数的调用次数统计。
生成1000道题目时
用于运算的几个函数时间占比高。程序运行速度快。
测试
对整体进行测试
1.输入参数生成运算式
2.输入答案
3.运算式和答案存储在txt文件中
4.统计结果输出到文件Grade.txt
项目小结
杨恒:在结对项目中,充分的交流可以加快项目的进展速度,少走弯路。在这次实践中,我也收获了一些合作的方法,其中一条就是在合作过程中要多沟通,因为如果缺少交流,就有可能会两个人做了重叠的工作。
游烽:当一个人在遇到问题时,及时与伙伴沟通,可以快速解决问题。通过这次项目,我发现在项目开发过程中,对已经实现的模块及时进行测试,而不是等所有模块的代码都完成后在进行测试,效率更高。