结对项目(calculator java)

Calculator(java)

github项目地址:https://github.com/KID53/cal

简介:命令行程序

项目结对合作成员: 易德康 3118005025 张朝阳 3118005027

一、题目描述

实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能)。

二、说明

自然数:0, 1, 2, …。

  • 真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
  • 运算符:+, −, ×, ÷。
  • 括号:(, )。
  • 等号:=。
  • 分隔符:空格(用于四则运算符和等号前后)。
  • 算术表达式:

e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),

其中e, e1和e2为表达式,n为自然数或真分数。

  • 四则运算题目:e = ,其中e为算术表达式。

三、需求

  1. 可以控制生成题目的数量
  2. 可以控制题目中数值(自然数、真分数和真分数分母)的范围
  3. 题目不重复
  4. 生成的题目和答案中分数为真分数
  5. 整个运算过程不出现负数
  6. 运算符数量小于等于3
  7. 支持一万道题目的生成
  8. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下文件
  9. 支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计

四、效能分析

最开始表达式数都用的是假分数,怎么让表达式转换为真分数思考了很久,还有如何实现分数的计算也是难点.
还有就是中缀转后缀,虽然数据结构里有讲,可惜当时学的不好没有学懂,又只能重新再看去了解.
除此之外,在如何保证生成的题目答案不出现负数的问题下,我俩进行了大量讨论,最后确定下先调用计算方法看结果是否为负数,是负数则重新生成(浪费了不少性能)但也是个有效的方法.
最消耗性能的类应该是生成后缀表达式的类和计算时的类.

五、设计实现过程

六、代码说明

中缀表达式转后缀表达式

public static String creatSuffixExepression(String str) {
		int num=0;
		int tmp=0;
		int stackLen=0;//栈的长度
		String expression="";//输出结果字符串
		char element='a';
		boolean haveNum= false;//是否有数字
		Stack<Character> stack= new Stack<>();//字符栈
		str=str+"!";//为了判断结束方便加入!做为字符串结尾
		for(int i=0;i<str.length();i++) {
			char c = str.charAt(i);
			if(isNUm(c)) {
				haveNum=true;
				tmp=tmp*10+(c-'0');
			}else {
				if(haveNum) {
					haveNum=false;
					expression+=tmp;
					tmp=0;
				}
				if(c=='(') {//遇到左括号无条件进栈
					num++;
					stack.push(c);
				}else if(c=='+'||c=='-'||c=='!') { //因为+-优先级最低所以全部弹出
					if(num>0) {//如果遇到左括号则停止
						stackLen= stack.size();
						for(int j=0;j<stackLen;j++) {
							element = stack.peek();
							if(element=='(') {
								break;
							}
							expression+=stack.pop();
						}
					}else {//全部弹出;
						expression+=' ';
						if(stack.size()!=0) {
							stackLen = stack.size();
							for(int j = 0; j < stackLen; j++ ) {
								expression += stack.pop();
							}
						}
					}
					if(c=='!') {
						break;
					}
					stack.push(c);
					expression+=' ';
				}else if(c=='*'||c=='/') {
					if(str.charAt(i-1)==' '){
						while (!stack.empty() && priority(c) <= priority(stack.peek())){//弹出栈顶优先级大于当前元素的符号;
							expression +=' ';
							expression += stack.peek();
							stack.pop();
						}
						stack.push(c);
					}else {
						expression+=c;
					}
				}else if(c==')') {
					if(stack.size()!=0) {
						stackLen = stack.size();
						for(int j = 0; j < stackLen; j++ ) {
							element = stack.pop();
							if(element=='(') {
								break;
							}
							expression += element;
						}
						num--;
					}
				}else if(c==' ') {//遇到空格则加空格;
					expression+=' ';
				}
			}
		}
		return expression;
	}

中缀表达式的生成

public String timu(){//生成表达式
		 String str = "";
		 String str1=""; 
		 do { 
			str = "";
			str1 = "";
		 int t = 0;
		 Random rand = new Random();
		 t = rand.nextInt(3) + 2;
		 String[] number = new String[t];//存放数字
		 String[] symbol = new String[t-1];//存放运算符号
		 String[] total = new String[4*t-3];//存放式子
		 String[] total1 = new String[4*t-3];
		 for(int i = 0;i < t;i++) {
			 number[i] = Shu();
		 }
		 for(int i = 0;i < t-1;i++) {
			 symbol[i] = fuhao();
		 }
		 for(int i = 0;i < 4*t - 3;i++) {
			 if(i%4 == 0) {
				 total[i] = number[i/4];
				 total1[i] = number[i/4];
			 }
			 else if(i%4 == 2) {
				 int k = (i+2)/4 - 1;
				 total[i] = symbol[k];
				 total1[i] = symbol[k];
			 }
			 else {total[i] = " ";
			       total1[i] = " ";
			 }
		 }
		 for(int i = 0;i < 4*t - 3;i++) {
			 if(total1[i].contains("'")) {
				total1[i] = jiafenshu(total1[i]);
			 }
		 }
		 if(t == 4) {
			 if((symbol[1] == "*"||symbol[1] == "/") && (symbol[0] == "+"||symbol[0] == "-")) {
				                      total[0] = "(" + total[0];
                                      total[4] = total[4] + ")"; 
                                      total1[0] = "(" + total1[0];
                                      total1[4] = total1[4] + ")"; 
			                                    }
			 if((symbol[1] == "*"||symbol[1] == "-") && (symbol[2] == "+"||symbol[2] == "-")) {
				 total[8] = "(" + total[8];
                 total[12] = total[12] + ")";
                 total1[8] = "(" + total1[8];
                 total1[12] = total1[12] + ")";
			 }
		 }
		 for(int i = 0;i < 4*t - 3;i++) {
			 str = str + total[i];
			 str1 = str1 + total1[i];
		 }
		 }while(Count.count(str1).contains("-"));
		 return str+" ="+";"+str1;
	}

四则运算的方法

public static Num add(Num a, Num b) { //加法
		Num c= new Num(1,1);
		c.numerator = a.numerator * b.denominator + b.numerator * a.denominator;
		c.denominator = a.denominator * b.denominator;
		return c;
	}
	
	public static Num subtract(Num a, Num b) { //减法
		Num c= new Num(1,1);
		c.numerator = a.numerator * b.denominator - b.numerator * a.denominator;
		c.denominator = a.denominator * b.denominator;
		return c;
	}
	
	public static Num mul(Num a, Num b) { //乘法
		Num c= new Num(1,1);
		c.numerator = a.numerator * b.numerator;
		c.denominator = a.denominator * b.denominator;
		return c;
	}
	
	public static Num division(Num a, Num b) { //除法
		Num c= new Num(1,1);
		c.numerator = a.numerator * b.denominator;
		c.denominator = a.denominator * b.numerator;
		return c;
	}

检查答案与题目

if(path.length>1) {
			FileReader fr1 = new FileReader(path[1]);
			br1 = new BufferedReader(fr1);
		}
		for(int i=0;(line = br.readLine())!=null;i++) {
			path = line.split("=");
			if(path.length>1) {
				line4 = path[1];
			}
			path2 = br1.readLine().split("\\.");
			if(path2.length>1) {
				line5 = path2[1];
			}
			if(line4.equals(line5)){
				line2 = line2 + i+",";
				a++;
			}else {
				line3 = line3 + i+",";
				b++;
			}
		}
		line2=line2.substring(0,line2.length()-1);
		line3=line3.substring(0,line3.length()-1);
		bw.write("Correct: "+ a + line2 +")");
		bw.newLine();
		bw.write("Wrong: "+ b + line3 +")");
		bw.close();
	}	

七、测试运行

一万道题目生成


测试答案与题目的正确数


可执行文件

八、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 45
· Estimate · 估计这个任务需要多少时间 1200 1225
Development 开发 670 1140
· Analysis · 需求分析 (包括学习新技术) 60 90
· Design Spec · 生成设计文档 30 45
· Design Review · 设计复审 (和同事审核设计文档) 15 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 15 35
· Design · 具体设计 60 110
· Coding · 具体编码 400 740
· Code Review · 代码复审 30 50
· Test · 测试(自我测试,修改代码,提交修改) 60 40
Reporting 报告 50 40
· Test Report · 测试报告 10 10
· Size Measurement · 计算工作量 15 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 25 20
合计 1200 1225

九、项目小结

张朝阳:

  • 这次结对项目的双人合作让我获益良多,两个人之间编写各个模块时的交流尤为重要,两人在各自编写的模块中可以根据对方的代码,在自己的代码中做出相应的修改以便在调用彼此的模块更加符合。
  • 比如在我编写生成中缀表达式时,借用合作者设计的计算功能判别生成式子中是否产生负数。总之这次有人带飞,我算是个打杂的,做些较简单的代码设计,重任不在吾身。

易德康:

  1. 结对项目合作起来肯定要比一个人快啦!!!更容易蹦出灵感
  2. 同时对项目的分工大家一起讨论也能很快讨论出一个标准化的东西.
  3. 可以从对方身上学到很多自己没掌握的东西,别人懂得函数你不懂正好可以请教,在测试代码的时候,当局者迷旁观者清,终究是别人找bug比较快.
  4. 线上结对也有麻烦的地方,如果可以面对面交流的话,各个模块的沟通性就比较好,就不会出现写主函数的时候磕磕碰碰的调用了(咱俩的函数都一样),痛苦.
  5. 对于经常用的函数仍然有掌握不清的地方,例如split函数遇到"."是不会有输出的,因为这个也卡了不少时间.
  6. 张朝阳同学对生成表达式的理解比我深刻得多,很快就能找到解决问题的办法,是我还要学习的地方.
posted @   池鱼柳林  阅读(228)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示