四则运算(java) 王哲文 邹庭和
github地址:https://github.com/3116004655/simple-calculator/tree/master
一、题目:实现一个自动生成小学四则运算题目的命令行程序
功能:
1. 使用 -n 参数控制生成题目的个数,例如
Myapp.exe -n 10,将生成10个题目。【已实现】
2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如
Myapp.exe -r 10,将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。【已实现】
3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2。【减法未实现】
4. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。【已实现】
5. 每道题目中出现的运算符个数不超过3个。【已实现】
6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。
生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:
1. 四则运算题目1
2. 四则运算题目2
……
其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。【检测重复部分未实现】
7. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
1. 答案1
2. 答案2
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。【已实现】
8. 程序应能支持一万道题目的生成。【已实现】
9. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。【未实现】
二、设计实现
1. 数值生成
题目要求生成的数要带上分数,设计方面是通过随机产生分子和分母的整数值两数相除,然后进行有关分数方面的操作,例如约分,假分数化为带分数和分数之间运算等操作,最后转化为字符输出。这些方法用一个分数类Fraction()来保存。
2. 算术表达式生成
题目要求不超过三个运算符,所设计时则通过生成一个随机数,然后进行循环随机数运算,通过另生成一个随机数进行switch选择生成随机运算符且再生成一个随机数控制运算符个数随机,每次循环用字符保存,从而循环生成一个字符算式,再用一个字符数组循环保存每个算式,最后再进行输出。其中,用num、max分别控制生成的算式题目数及数值范围,以达到控制题目目的。
三、用户使用说明
举例:
-n [数值] 使用 -n 参数控制生成题目的个数。
-r [数值] 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围。
四、关键代码
1. 分数生成
1 package arithmetic; 2 /** 3 * 4 * @author Administrator 5 */ 6 7 public class Fraction { 8 private int a; //分子 9 private int b; //分母 10 11 public Fraction(String string) { 12 string = string.trim(); 13 int char1 = string.indexOf("'"); 14 int char2 = string.indexOf("/"); 15 if (char1 != -1) { // 数字为带分数 16 int z = Integer.valueOf(string.substring(0, char1)); 17 b = Integer.valueOf(string.substring(char2 + 1)); 18 a = z * b + Integer.valueOf(string.substring(char1 + 1, d)); 19 } else if (char2 != -1) { // 数字为真分数 20 b = Integer.valueOf(string.substring(char2 + 1)); 21 a = Integer.valueOf(string.substring(0,char2)); 22 } else { // 数字为整数 23 a = Integer.valueOf(string); 24 b = 1; 25 } 26 build(a, b); 27 } 28 public Fraction(int a, int b) { 29 build(a, b); 30 } 31 32 // 数字形式转换为字符串形式 33 public String toString() { 34 if (b == 1) { 35 return String.valueOf(a); 36 } else { 37 int i = a / b; 38 if (i != 0) { 39 return String.format("%d'%d/%d", i, a - b * i, b); 40 } else { 41 return String.format("%d/%d", a, b); 42 } 43 } 44 } 45 46 // 给定分子分母构造分数 47 private void build(int a, int b) { 48 if (b == 0) { 49 throw new RuntimeException("分母不能为0"); 50 } 51 int c = comfactor(a, b); 52 this.a = a / c; 53 this.b = b / c; 54 } 55 56 // 公约数 57 private int comfactor(int a, int b) { 58 int mod = a % b; 59 return mod == 0 ? b : comfactor(b, mod); 60 } 61 62 // a + b 63 public Fraction add(Fraction fraction) { 64 return new Fraction(this.a * fraction.b + fraction.a * this.b, this.b * fraction.b); 65 } 66 67 // a - b 68 public Fraction subtraction(Fraction fraction) { 69 return new Fraction(this.a * fraction.b - fraction.a * this.b, this.b * fraction.b); 70 } 71 72 // = a x b 73 public Fraction multiplication(Fraction fraction) { 74 return new Fraction(this.a * fraction.a, this.b * fraction.b); 75 } 76 77 // a/b 78 public Fraction division(Fraction fraction) { 79 return new Fraction(this.a * fraction.b, b * fraction.a); 80 } 81 82 public double getDouble() { 83 return a / b; 84 } 85 86 }
2. 表达式生成及计算(仅显示带分数部分)
1 package arithmetic; 2 3 import java.util.Random; 4 5 import javax.script.ScriptEngine; 6 import javax.script.ScriptEngineManager; 7 import javax.script.ScriptException; 8 9 10 //带真分数四则运算 11 public class createQuestion1 { 12 public void testQuestion(String num,String max) { 13 fileUnit fileunit=new fileUnit(); 14 int num1=Integer.parseInt(num); 15 int max1=Integer.parseInt(max); 16 String result=null; 17 String operator1=null; 18 String txt=null; 19 String txt1=null; 20 int operator,operatorNum; 21 //int[] a=new int[10000]; 22 Fraction [] arr=new Fraction[10000]; 23 Fraction [] arr1=new Fraction[4]; 24 String [] Result = new String [10000]; 25 System.out.println("生成的带真分数四则运算试题为:"); 26 27 for(int j=1;j<=num1;j++) { 28 //a[0]=(int)(Math.random()*max1); 29 //result=a[0]+""; 30 result=null; 31 Random c = new Random(); 32 Random d = new Random(); 33 Fraction e = new Fraction(c.nextInt(max1)+1,d.nextInt(max1)+1); 34 arr1[0]=e; 35 operatorNum=(int)(Math.random()*max1%4); 36 while(operatorNum==0) { 37 operatorNum=(int)(Math.random()*max1%4); 38 } 39 for(int i=1;i<operatorNum+1;i++) 40 { 41 // a[i]=(int)(Math.random()*max1); 42 Fraction b = new Fraction(c.nextInt(max1)+1,d.nextInt(max1)+1); 43 operator=(int)(Math.random()*max1%4); 44 switch(operator) { 45 case 0:operator1="+";arr1[i]=arr1[i-1].add(b);break; 46 case 1:operator1="-";arr1[i]=arr1[i-1].subtraction(b);break; 47 case 2:operator1="*";arr1[i]=arr1[i-1].multiplication(b);break; 48 case 3:operator1="/";arr1[i]=arr1[i-1].division(b);break; 49 } 50 if(i==1) { 51 result="("+e+")"+operator1+"("+b+")"+""; 52 } 53 else { 54 result="("+result+")"+operator1+"("+b+")"+""; 55 } 56 } 57 arr[j]=arr1[operatorNum]; 58 System.out.println("题目"+j+":"+"result="+result); 59 if(txt==null) { 60 txt="result="+result+"\n"; 61 } 62 else { 63 txt=txt+"result="+result+"\n"; 64 } 65 Result[j]=arr[j]+""; 66 if(txt1==null) { 67 txt1="result="+Result[j]+"\n"; 68 } 69 else { 70 txt1=txt1+"result="+Result[j]+"\n"; 71 } 72 } //下面注释部分因为没有考虑优先级而出现错误,未实现。 73 /* 74 ScriptEngineManager manager = new ScriptEngineManager(); 75 ScriptEngine engine = manager.getEngineByName("js");//可以通过这个来调用JS模块的函数 76 for(int k=1;k<=num1;k++) { 77 Object result2; 78 try { 79 result2 = engine.eval(Result[k]); 80 if(txt1==null) { 81 txt1="result="+result2+"\n"; 82 } 83 else { 84 txt1=txt1+"result="+result2+"\n"; 85 } 86 87 } catch (ScriptException e) { 88 // TODO Auto-generated catch block 89 e.printStackTrace(); 90 } 91 } 92 */ 93 String fileName="c:\\Exercises.txt"; 94 System.out.println("练习题目已生成,存储路径为:"+fileName); 95 fileunit.WriteTextFile(fileName,"题目"+"\n"); 96 fileunit.WriteTextFile(fileName, txt); 97 String fileName1="c:\\Answers.txt"; 98 System.out.println("练习题目答案已生成,存储路径为:"+fileName1); 99 fileunit.WriteTextFile(fileName1,"答案"+"\n"); 100 fileunit.WriteTextFile(fileName1, txt1); 101 102 } 103 }
五、测试运行结果截图
结果出来的时候有些bug,上面有说明。
五、PSP
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
35 |
45 |
· Estimate |
· 估计这个任务需要多少时间 |
35 |
45 |
Development |
开发 |
930 |
1290 |
· Analysis |
· 需求分析 (包括学习新技术) |
70 |
120 |
· Design Spec |
· 生成设计文档 |
25 |
25 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
40 |
80 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
25 |
25 |
· Design |
· 具体设计 |
70 |
110 |
· Coding |
· 具体编码 |
600 |
780 |
· Code Review |
· 代码复审 |
50 |
50 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
50 |
100 |
Reporting |
报告 |
90 |
90 |
· Test Report |
· 测试报告 |
25 |
25 |
· Size Measurement |
· 计算工作量 |
15 |
15 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
50 |
50 |
合计 |
|
1055 |
1425 |
六、经验小结
这次四则运算作业做的并不成功,基本功能部分已实现,有些关键部分没有实现。主要原因是没有做好充分的准备和思考不够周到。在计算结果的时候直接用循环去做,导致了没有考虑运算符号的优先级,直接从左往右进行运算,所以得出了错误的结果。检测出错误之后,虽然考虑到了用栈的方式去计算结果,但是因为要花费很长时间研究而且没有充分准备,所以没时间修改。
邹庭和主要负责算数表达式的生成和计算,我主要负责数值中分数的设定和生成,通过这次编程我体会到了这次的编程要用到以前学的知识,例如数据结构,数据结构主要内容是关于数据的不同存储方式,应用很广泛。这次因为最后才想到数据结构的栈,导致准备并不充分,最后结果出现了错误。
经过反思之后,我们意识到“never stop coding”的重要性,平常代码还是要练的,以前的知识还是要回顾一下的,希望在以后的编程中能再提高自己。