小学四则运算
1.PSP表格
| 计划 | 计划完成需要的时间 | 实际完成需要的时间 |
| 估计这个任务需要多少时间,并规划大致工作步骤 | 15 | 10 |
| 需求分析 (包括学习新技术) | 150 | 120 |
| 生成设计文档 | 30 | 20 |
| 设计复审 | 10 | 8 |
| 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
| 具体设计 | 30 | 20 |
| 具体编码 | 20 | 15 |
| 代码复审 | 20 | 10 |
| 测试(自我测试,修改代码,提交修改) | 30 | 30 |
| 测试报告 | 20 | 15 |
| 计算工作量 | 20 | 10 |
| 事后总结 ,并提出过程改进计划 | 10 | 20 |
| 总计 | 365 | 288 |
2.生成四则运算算式和答案
3.代码
package szyx; import java.util.Scanner; public class main { public static void main(String[] args){ System.out.println("请选择功能:"); System.out.println(" 1. 四则运算生成器"); System.out.println(" 2. 答案对比"); System.out.print("请输入你的选择[1/2]:"); int choose = new Scanner(System.in).nextInt(); switch (choose){ case 1: ProducerController producerController = new ProducerController(); producerController.ConstructProblem();;break; case 2: JudgeAnswerController judgeAnswerController = new JudgeAnswerController(); judgeAnswerController.start();;break; default: System.out.println("输入不正确,请输入1或2");main(args);break; } } }
package szyx; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.InputMismatchException; import java.util.Random; import java.util.Scanner; public class ProducerController{ public void ConstructProblem(){ System.out.println("----------欢迎来到四则运算生成器----------\n"); try { Scanner scanner = new Scanner(System.in); System.out.print("请输入生成题目个数:"); int num = scanner.nextInt(); System.out.print("请输入最大自然数:"); int range = scanner.nextInt(); generateProblem(num, range); }catch (InputMismatchException e){ System.out.println("请输入数字。\n\n\n"); ConstructProblem(); } catch (IOException e) { System.out.println("文件创建失败"); } } /** * 输出到文件 * @param num * @param range * @throws IOException */ public void generateProblem(int num, int range) throws IOException { //项目根目录生成 File exercises = new File("Exercises.txt"); File answers = new File("Answers.txt"); if (exercises.exists() || answers.exists()){ exercises.delete(); answers.delete(); } if (exercises.createNewFile() && answers.createNewFile()){ FileOutputStream exercisesOutput = new FileOutputStream(exercises); PrintStream exercisesPrintStream = new PrintStream(exercisesOutput); FileOutputStream answersOutput = new FileOutputStream(answers); PrintStream answersPrintStream = new PrintStream(answersOutput); Random random = new Random(); CreateFraction createFraction = new CreateFraction(); CreateInteger createInteger = new CreateInteger(); String[] problem = new String[2]; for(int i = 1; i <= num; i++){ int choose = random.nextInt(2); if (choose == 0){ problem = createFraction.createProblem(range); }else { problem = createInteger.createProblem(range); } outputFile(i, problem, exercisesPrintStream, answersPrintStream); } exercisesOutput.close(); answersOutput.close(); exercisesPrintStream.close(); answersPrintStream.close(); System.out.println("文件创建成功 "); } } public void outputFile(int i, String problem[], PrintStream... var){ try { var[0].println(i + ". " + problem[0]); var[1].println(i + ". " + problem[1]); }catch (ArrayIndexOutOfBoundsException e){ System.out.println("程序内部出错了"); } } }
package szyx; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class JudgeAnswerController { public void start(){ System.out.print("请输入待验证答案路径:"); Scanner scanner = new Scanner(System.in); String exerciseFilePath = scanner.next(); System.out.print("请输入程序生成答案文件路径:"); String answerFilePath = scanner.next(); try { List<String> exerciseAnswers = exerciseFileReader(exerciseFilePath); List<String> answers = answerReader(answerFilePath); List<String> correct = new ArrayList<>(); List<String> wrong = new ArrayList<>(); int min = Math.min(exerciseAnswers.size(), answers.size()); int num = 1; for (int i = 0; i < min; i++){ if (exerciseAnswers.get(i).equals(answers.get(i))){ correct.add(String.valueOf(num++)); }else { wrong.add(String.valueOf(num++)); } } File grade = new File("Grade.txt"); if (grade.exists()){ grade.delete(); } if (grade.createNewFile()){ FileOutputStream gradeOutput = new FileOutputStream(grade); PrintStream gradePrintStream = new PrintStream(gradeOutput); String corrects = String.join(",", correct); gradePrintStream.println("Correct:" + correct.size() + " (" + corrects + ")"); String wrongs = String.join(",", wrong); gradePrintStream.println("Wrong:" + wrong.size() + " (" + wrongs + ")"); } System.out.println("判定完成"); } catch (FileNotFoundException e) { System.out.println("文件不存在"); } catch (IOException e) { System.out.println("文件读入异常"); } } public List<String> exerciseFileReader(String path) throws IOException { BufferedReader exerciseReader = new BufferedReader(new FileReader(path)); String exerciseAnswer = ""; List<String> exerciseAnswers = new ArrayList<>(); while ((exerciseAnswer = exerciseReader.readLine()) != null){ String[] split = exerciseAnswer.split("="); if (split.length >= 2){ exerciseAnswers.add(split[1]); }else { exerciseAnswers.add(" "); } } return exerciseAnswers; } public List<String> answerReader(String path) throws IOException { BufferedReader answerReader = new BufferedReader(new FileReader(path)); String answer = ""; List<String> answers = new ArrayList<>(); while ((answer = answerReader.readLine()) != null){ String[] split = answer.split(" "); answers.add(split[1]); } return answers; } }
package szyx; import java.util.Random; public class CreateInteger { private static final String[] OPERATOR = {"+", "-", "*", "÷"}; /** * 整数生成器 * @param range */ public String[] createProblem(int range){ Random random = new Random(); int operatorCount = 1 + random.nextInt(3); //随机操作符的个数(1-3个) int operand[] = new int[operatorCount + 1]; //操作数个数 int[] operatorIndex = index(operatorCount, 4, random); for(int i = 0; i < operatorCount + 1; i++){ operand[i] = random.nextInt(range); } String formula = stitchingFormula(operatorCount, operand, operatorIndex); //计算结果 Calculator calculator = new Calculator(); int res = calculator.algorithm(formula); String formulaRes[] = new String[2]; if (res > 0){ formulaRes[0] = formula; formulaRes[1] = String.valueOf(res); }else { return createProblem(range); } return formulaRes; } /** * 随机产生操作符的下标数组 * @param operatorCount * @param operatorTotal * @param random * @return */ public int[] index(int operatorCount,int operatorTotal, Random random){ int similar = 0; int[] operatorIndex = new int[operatorCount]; for(int i = 0; i < operatorCount; i++){ operatorIndex[i] = random.nextInt(operatorTotal); } for (int i : operatorIndex) { if(operatorIndex[0] == i) { similar++; } } if(similar == operatorCount && operatorCount != 1){ return index(operatorCount, operatorTotal, random); //保证一个式子里至少有2个不同的操作符,若所有操作符下标都一样,则重新产生操作符下标 } else { return operatorIndex; } } /** * 拼接式子 * @param operatorCount * @param operand * @param operatorIndex * @return */ public String stitchingFormula(int operatorCount, int operand[], int[] operatorIndex){ int bracketForm = new Random().nextInt(2);//式子形态 StringBuilder formula = new StringBuilder(); switch (operatorCount){ case 1: // 1+2型 formula.append(operand[0]) .append(" ") .append(OPERATOR[operatorIndex[0]]) .append(" ") .append(operand[1]) .append(" ") .append("="); break; case 2:{ // 1+2+3 型 if (bracketForm == 0){ formula.append(operand[0]) .append(" ") .append(OPERATOR[operatorIndex[0]]) .append(" ") .append(operand[1]) .append(" ") .append(OPERATOR[operatorIndex[1]]) .append(" ") .append(operand[2]) .append(" ") .append("="); }else { //1+(2+3)型 formula.append(operand[0]) .append(" ") .append(OPERATOR[operatorIndex[0]]) .append(" ") .append("(") .append(" ") .append(operand[1]) .append(" ") .append(OPERATOR[operatorIndex[1]]) .append(" ") .append(operand[2]) .append(" ") .append(")") .append(" ") .append("="); }break; } case 3:{ if (bracketForm == 0){ //1+((2+3)-4)型 formula.append(operand[0]) .append(" ") .append(OPERATOR[operatorIndex[0]]) .append(" ") .append("((") .append(" ") .append(operand[1]) .append(" ") .append(OPERATOR[operatorIndex[1]]) .append(" ") .append(operand[2]) .append(" ") .append(")") .append(" ") .append(OPERATOR[operatorIndex[2]]) .append(" ") .append(operand[3]) .append(" ") .append(")") .append(" ") .append("="); }else { //(1+2)+(3+4)型 formula.append("(") .append(" ") .append(operand[0]) .append(" ") .append(OPERATOR[operatorIndex[0]]) .append(" ") .append(operand[1]) .append(" ") .append(")") .append(" ") .append(OPERATOR[operatorIndex[1]]) .append(" ") .append("(") .append(" ") .append(operand[2]) .append(" ") .append(OPERATOR[operatorIndex[2]]) .append(" ") .append(operand[3]) .append(" ") .append(")") .append(" ") .append("="); }break; } } return formula.toString(); } }
package szyx; import java.util.Random; public class CreateFraction { private static final String OPERATOR[] = {"+", "-"}; /** * 真分数生成器 * @param range */ public String[] createProblem(int range){ Random random = new Random(); int operatorCount = 1 + random.nextInt(3); //操作符的个数1-3 CreateInteger create = new CreateInteger(); int[] operatorIndex = create.index(operatorCount,2, random); //操作符的下标 //生成第一个操作数 int[] coprimeNumber1 = createCoprimeNumbers(range, random); int x = coprimeNumber1[0]; int y = coprimeNumber1[1]; String s = shamToProperFraction(x, y); for(int i=0; i < operatorCount; i++){ //生成剩下的操作数 int[] coprimeNumber = createCoprimeNumbers(range, random); int numx = coprimeNumber[0]; int numy = coprimeNumber[1]; String currentOpreator = OPERATOR[operatorIndex[i]]; if(currentOpreator.equals("+")){ //加法 x = x * numy + y * numx; y = y * numy; }else { //减法 int count = 0; while(x * numy - y * numx < 0){ //差为负数 coprimeNumber = createCoprimeNumbers(range, random); numx = coprimeNumber[0]; numy = coprimeNumber[1]; count++; if (count >= 5){ numx = x - 1; numy = y; } } x = x * numy - y * numx; y = y * numy; } String num = shamToProperFraction(numx, numy); s += currentOpreator + num; } int greatFactor = greatFactor(x,y); x /= greatFactor; //最终结果化简 y /= greatFactor; String res = shamToProperFraction(x, y); s += "="; String formulaRes[] = {s, res}; return formulaRes; } /** * 求最大公因数 * @param x * @param y * @return */ public int greatFactor(int x,int y) { while(true){ if(x % y == 0){ return y; } int temp = y; y = x % y; x = temp; } } /** * 生成一对互质数 * @param range * @param random * @return */ public int[] createCoprimeNumbers(int range, Random random){ int x = 1 + random.nextInt(range); int y = 1 + random.nextInt(range); int greatFactor = greatFactor(x, y); x /= greatFactor; y /= greatFactor; int numbers[] = {x, y}; return numbers; } /** * 假分数转化为真分数 * @param x 分子 * @param y 分母 * @return */ public String shamToProperFraction(int x, int y){ if (x > y){ int n = x / y; x = (x - n * y); if (x == 0){ return String.valueOf(n); } return n + "'" + x + "/" + y; }else if (x == y){ return "1"; }else if (y == 1){ return String.valueOf(x); }else if (x == 0){ return "0"; } return x + "/" + y; } }
package szyx; import java.util.HashMap; import java.util.Stack; public class Calculator { public int algorithm(String s) { Stack<Integer> numStack = new Stack<>(); //放数字 Stack<String> operatorStack = new Stack<>(); //放操作符 HashMap<String, Integer> hashMap = new HashMap<>(); //存放运算符优先级 hashMap.put("(", 0); hashMap.put("+", 1); hashMap.put("-", 1); hashMap.put("*", 2); hashMap.put("÷", 2); String formula = s.replaceAll(" ", ""); for (int i = 0; i < formula.length();) { StringBuilder digit = new StringBuilder(); //StringBuilder类中的方法主要偏重于对于字符串的变化,例如追加、插入和删除等,这个也是StringBuffer和String类的主要区别。 char c = formula.charAt(i); //将式子字符串切割为c字符 while (Character.isDigit(c)) { //判断字符是否为10进制数字,将一个数加入digit digit.append(c); i++; if (i < formula.length()){ c = formula.charAt(i); }else { break; } } if (digit.length() == 0){ //当前digit里面已经无数字,即当前处理符号 switch (c) { case '(': { operatorStack.push(String.valueOf(c));//如果是( 转化为字符串压入字符栈 break; } case ')': { //遇到右括号了计算,因为(的优先级最高 String stmp = operatorStack.pop(); //如果是),将符号栈栈顶元素取到 while (!operatorStack.isEmpty() && !stmp.equals("(")) { //当前符号栈里面还有+ - * / int a = numStack.pop(); //取操作数a,b int b = numStack.pop(); int result = calculate(b, a, stmp); //计算 if(result < 0) return -1; numStack.push(result); //将结果压入栈 stmp = operatorStack.pop(); //符号指向下一个计算符号 } break; } case '=': { //遇到等号了计算 String stmp; while (!operatorStack.isEmpty()) { //当前符号栈里面还有+ - * /,即还没有算完 stmp = operatorStack.pop(); int a = numStack.pop(); int b = numStack.pop(); int result = calculate(b, a, stmp); if(result < 0) return -1; numStack.push(result); } break; } default: { //不满足之前的任何情况 String stmp; while (!operatorStack.isEmpty()) { //如果符号栈有符号 stmp = operatorStack.pop(); //当前符号栈,栈顶元素 if (hashMap.get(stmp) >= hashMap.get(String.valueOf(c))) { //比较优先级 int a = numStack.pop(); int b = numStack.pop(); int result =calculate (b, a, stmp); if(result < 0) return -1; numStack.push(result); } else { operatorStack.push(stmp); break; } } operatorStack.push(String.valueOf(c)); //将符号压入符号栈 break; } } } else { //处理数字,直接压栈 numStack.push(Integer.valueOf(digit.toString())); //Integer.valueof()返回的是Integer对象,而Integer.parseInt()返回的是int型 continue; //结束本次循环,回到for语句进行下一次循环,即不执行i++(因为此时i已经指向符号了) } i++; } return numStack.peek(); //返回栈底数字即等式的答案。 } private int calculate(int a, int b, String stmp) { //计算a stmp b的值 int res = 0; //存结果 char s = stmp.charAt(0); switch (s) { case '+': { res = a + b; break; } case '-': { res = a - b; //产生负数就不合格 break; } case '*': { res = a * b; break; } case '÷': { if(b==0) return -1; else if(a%b!=0) //产生小数就不合格 return -2; else res = a / b; break; } } return res; } }
4.结果







浙公网安备 33010602011771号