20175212童皓桢 结对编程项目-四则运算 第二周
需求分析
-
实现一个命令行程序,要求自动生成小学四则运算题目(加减乘除)
-
支持多运算符
-
测试结果的正确性,用户输入错误时给出正解
-
实现真分数运算
-
在不需要真分数运算时,将结果整除
-
统计题目正确率
-
生成题目输出到文件
-
从文件写入
设计思路
- 首先要能够按照按人的一般习惯,生成自左向右计算的加减乘除算式。
- 随机生成多运算符,并随机生成相对应个数的整数
- 利用
eval
方法直接计算随机生成的算式的值,并和用户的输入作比较 - 将人计算真分数时的通分,约分方法描述成机器语言
- 在不需要真分数运算时,将结果整除
- 判断正确率
- 生成题目至文件
- 设计测试类,利用JUnit测试各情况下的的四则运算
UML类图
关键代码
- 如何生成符合要求格式的运算式
for (i = 0; i < n; i++) {
int a = random.nextInt(5) + 1;//1-5个运算符
int[] number = new int[a + 1];//创建一个number数组
String ex = new String();
for (int j = 0; j <= a; j++) {//生产a+1个数字,即2-6个数字
number[j] = random.nextInt(100) + 1;//生成1-100的整数
}
for (int j = 0; j < a; j++) {
int s = random.nextInt(4);//随机生成运算符下标
ex += String.valueOf(number[j]) + String.valueOf(op[s]);//添加一对数字和运算符
}
ex += String.valueOf(number[a]);//在尾端补上一个数字
System.out.println(ex + "=");
- 如何验证用户输入答案的正误
int ua = reader.nextInt();//用户输入答案
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine se1 = manager.getEngineByName("js");
ScriptEngine se2 = manager.getEngineByName("js");
String str=ex+"="+"="+ua;//将用户答案逻辑式放在字符串str中
Boolean result =(Boolean)se1.eval(str);//用eval方法计算用户答案逻辑式
String ca="="+se2.eval(ex);//生成correct_answer字符串存正确答案
jud.judgeFormula(result,ca);
- 如何进行真分数的加减乘运算
if(s==2){//计算真分数乘法运算
int nu[]=new int[2];
nu[0]=num[0]*num[2];
nu[1]=num[1]*num[3];
ca=ex+f.yuefen(nu[0],nu[1]);//将计算结果约分
}
else if(s==0){//计算真分数加法运算
int nu_1[]=new int[2];
nu_1[0]= num[0]*num[3]+num[1]*num[2];
nu_1[1]= num[1]*num[3];
ca=ex+f.yuefen(nu_1[0],nu_1[1]);
}
else {//计算真分数减法运算
int nu_2[]=new int[2];
nu_2[0]= num[0]*num[3]-num[1]*num[2];
nu_2[1]= num[1]*num[3];
if(nu_2[0]<0){//分子为负数时
nu_2[0]=-nu_2[0];//取反
ca=ex+"-"+f.yuefen(nu_2[0],nu_2[1]);//加上负号
}
else
ca=ex+f.yuefen(nu_2[0],nu_2[1]);
}
- 如何对分数计算结果进行约分
public String yuefen(int m,int n){//分数约分
FundCalculate f=new FundCalculate();
int temp=f.gcd(m,n);
m/=temp;
n/=temp;
String ca=String.valueOf(m)+"/"+String.valueOf(n);
return ca;
}
- 如何在非真分数情况下构造算式整除
public int decide(int x,int y){//判断是否整除
Random random=new Random();
if(x%y!=0){
y=random.nextInt(100)+1;
return decide(x,y);
}
else{
return y;
}
}
for (int j = 0; j < a; j++) {
switch(flag){
case 0:
s[0]= random.nextInt(4);//随机生成运算符下标
ex += String.valueOf(number[j]) + String.valueOf(op[s[0]]);//添加一对数字和运算符
if(s[0]==3){number[j+1]=f.decide(number[j],number[j+1]);}
break;
case 1:
s[1]= random.nextInt(4);//随机生成运算符下标
ex+="("+String.valueOf(number[j]) + String.valueOf(op[s[1]]);//添加左括号和数字和运算符
if(s[1]==3){number[j+1]=f.decide(number[j],number[j+1]);}
flag++;
break;
case 2:
s[2]=random.nextInt(4);
ex+=String.valueOf(number[j]) + ")"+String.valueOf(op[s[2]]);//添加右括号和数字和运算符
if(s[2]==3){
switch(s[1]){//区分之前括号里运算结果对后面数取整
case 0:
number[j+1]=f.decide(number[j]+number[j-1],number[j+1]);
break;
case 1:
number[j+1]=f.decide(number[j]-number[j-1],number[j+1]);
break;
case 2:
number[j+1]=f.decide(number[j]*number[j-1],number[j+1]);
break;
case 3:
number[j+1]=f.decide(number[j]/number[j-1],number[j+1]);
break;
default:;
}
}
- 如何在文件中输入输出
import java.io.*;
public class WAndRFile {
String ua=new String();//用户答案
public void writeToFile(String str){
File fw=new File("practice.txt");//写入的文件
try{
Writer out=new FileWriter(fw);//指向目的地输出流
BufferedWriter bw=new BufferedWriter(out);
bw.write(str);//写入字符串str
bw.newLine();//换行
bw.close();//高级流关闭
out.close();//关闭底层流
}
catch (IOException e){
e.printStackTrace();
}
}
public String readFromFile(){
File fr=new File("practice.txt");//读取的文件
try{
Reader in=new FileReader(fr);//指向源的输入流
BufferedReader br=new BufferedReader(in);
while (br.readLine()!=null)
ua=br.readLine();
br.close();
in.close();;
}
catch (IOException e){
e.printStackTrace();
}
return ua;
}
}
Junit测试
运行结果截图
-
含真分数
-
不含真分数
- 输出到文件
代码托管地址
https://gitee.com/thz666/20175212_tong_haozhen/tree/master/src/四则运算
遇到的困难及解决办法
- 问题一:真分数计算时,当结果为负数,输入的答案和“正确答案”时常不符,如输入-4/3,“正确答案”为4/-3.
- 解决方法一:
if(nu_2[0]<0){//分子为负数时
nu_2[0]=-nu_2[0];//取反
ca=ex+"-"+f.yuefen(nu_2[0],nu_2[1]);//加上负号
}
重新构造答案结构,使其符合数学标准
- 问题二:真分数答案没有约分
- 解决办法:
Boolean result=ua.equals(ca);
jud.judgeFormula(result,ca);
将上述代码放在循环体中
- 问题三:非真分数计算时会出现8位及以上小数
- 解决办法三:事先判断是否整除,如
public int decide(int x,int y){//判断是否整除
Random random=new Random();
if(x%y!=0){
y=random.nextInt(100)+1;
return decide(x,y);
}
else{
return y;
}
}
结对总评及评价
- 结对学习对于编而言的确是一个很好的方法。因特殊方法的原因,我们的程序编写过程中遇到了许多各式各样的问题,大部分还是超出了知识能力范围,需要我们摸索研究。很难想象没有这样一个好的结对伙伴,这个程序的实现将会有多大的难度!
- 最后,我希望并且有信心,通过两个人的结对将Java学习的热情和储备提升一个新的台阶。
结对照片
PSP
PSP | Personal Software Process Stages | 预估耗时 | 实际耗时 |
---|---|---|---|
Planning | 计划 | 30min | 20min |
Estimate | 估计这个任务需要多少时间 | 10min | 10min |
Development | 开发 | 10min | 10min |
Analysis | 需求分析 (包括学习新技术) | 40min | 30min |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 5min | 10min |
Design | 具体设计 | 1h | 1h |
Coding | 具体编码 | 3h | 4h |
· Code Review | 代码复审 | 30min | 30min |
Test | · 测试(自我测试,修改代码,提交修改) | 1h | 1h |
Test Report | 测试报告 | 30min | 30min |
Size Measurement | 计算工作量 | 10min | 10min |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30min | 30min |
合计 | 7h35min | 8h50min |