ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

四则运算

2021-09-19 17:36:11  阅读:183  来源: 互联网

标签:return 四则运算 Fraction new firstNum public append


一. PSP表格

 

 

 

 

二. 项目要求:

  • 能自动生成小学四则运算题目
  • 除了整数以外,还要支持真分数的四则运算

 

三. 解题思路:

  • 了解四则运算的基本法则
  • 利用随机函数随机生成数字以及运算符
  • 用户输入答案程序需要判断答案是否正确
  • 支持真分数运算

四. 符号说明:

自然数: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为算术表达式。

 

 

 

五. 项目功能

  由界面输入参数,实现了题目的生成以及去重,问题与答案的文件保存,用户输入答案文件与标准答案的校对以及结果文件生成

运行示例(Answerfile.txt为用户提交文件):

 

 

 

 

六. 代码设计

 

1. 由于题目设计真分数运算,所以采用分数作为基本的运算单位。使用ExpressionResult类保存每条表达式以及它的运算结果

 1 public class Fraction {
 2     //分子
 3     private Integer numerator;
 4     //分母
 5     private Integer denominator;
 6 
 7     //取最大公因数化简
 8     public Fraction(Integer n, Integer d) {
 9         Integer GCD = Calculator.GCD(n, d);
10         this.numerator = n /= GCD;
11         this.denominator = d /= GCD;
12     }
13 
14 
15     //重写toString方法,以真分数形式表示
16     @Override
17     public String toString() {
18         if (this.numerator > this.denominator && this.denominator != 1 && this.getNumerator() > 0 && this.getDenominator() > 0) {
19             int num = numerator / denominator;
20             return num + "'" + numerator % denominator + "/" + denominator;
21         } else if (denominator == 1) {
22             return numerator.toString();
23         } else return numerator + "/" + denominator;
24     }
25 }

 

 

 1 public class ExpressionResult {
 2 
 3     private String expression;
 4     private String result;
 5 
 6     @Override
 7     public String toString() {
 8         return expression+"="+result;
 9     }
10 }

2. 很多人采用二叉树生成表达式或者中缀转后缀表达式的思路,我则是直接进行表达式的生成与计算,在生成表达式时采用HashSet无法重复的特性来存放表达式达到去重的目的

 1 //表达式的生成,采用HashSet存放表达式,直接去重,可以免去后续检测是否重复
 2     public static HashSet<ExpressionResult> generateExpression(Integer r, Integer n) {
 3         HashSet<ExpressionResult> expressionResultHashSet = new HashSet<>();
 4         for (int i = 0; i < r; i++) {
 5             //生成第一个操作符和操作数,在后面计算中使用firstNum存放计算的结果
 6             char firstOps = GeneratorUtil.getOperator();
 7             Fraction firstNum = GeneratorUtil.getFraction(n);
 8             char secondOps = firstOps;
 9             Fraction secondNum = firstNum;
10             ExpressionResult expressionResult = new ExpressionResult();
11             StringBuilder expression = new StringBuilder().append(firstNum);
12             //生成后续两个操作符并进行表达式的拼接
13             for (int j = 0; j < 2; j++) {
14                 //获取第二个操作数
15                 secondNum = GeneratorUtil.getFraction(n);
16                 switch (secondOps) {
17                     //加法则直接进行拼接,不需要额外操作
18                     case '+':
19                         //将当前运算符保存,后面在优先级比较中会使用到(下同)
20                         firstOps = secondOps;
21                         expression.append(secondOps).append(secondNum);
22                         //保存运算的中间结果(下同)
23                         firstNum = Calculator.ADD(firstNum, secondNum);
24                         //获取下一个操作符(下同)
25                         secondOps = GeneratorUtil.getOperator();
26                         break;
27                     case '-':
28                         firstOps = secondOps;
29                         //由于不能产生负数,所以在减法时要进行比较,如果前数小于后数则将表达式倒置拼接
30                         if (Calculator.CMP(firstNum, secondNum)) {
31                             firstNum = Calculator.SUB(firstNum, secondNum);
32                             expression.append(secondOps).append(secondNum);
33                         } else {
34                             expression = new StringBuilder().append(secondNum).append(secondOps).append(expression);
35                             firstNum = Calculator.SUB(secondNum, firstNum);
36                         }
37                         secondOps = GeneratorUtil.getOperator();
38                         break;
39                     case '×':
40                         //乘法优先级大,在这里判断前面是否有优先级较小的加减操作,有的话将表达式带上括号再拼接乘法运算
41                         if (firstOps == '+' || firstOps == '-') {
42                             expression = new StringBuilder().append("(").append(expression).append(")").append(secondOps).append(secondNum);
43                         } else {
44                             expression.append(secondOps).append(secondNum);
45                         }
46                         //保存运算结果
47                         firstNum = Calculator.MUL(firstNum, secondNum);
48                         firstOps = secondOps;
49                         secondOps = GeneratorUtil.getOperator();
50                         break;
51                     case '÷':
52                         //除法优先级大,在这里判断前面是否有优先级较小的加减操作,有的话将表达式带上括号再拼接乘法运算
53                         if (firstOps == '+' || firstOps == '-') {
54                             expression = new StringBuilder().append("(").append(expression).append(")").append(secondOps).append(secondNum);
55                             firstNum = Calculator.DIV(secondNum, firstNum);
56                         } else {
57                             expression.append(secondOps).append(secondNum);
58                             firstNum = Calculator.DIV(firstNum, secondNum);
59                         }
60                         firstOps = secondOps;
61                         secondOps = GeneratorUtil.getOperator();
62                         break;
63                 }
64             }
65             //将表达式和结果保存,放进HashSet
66             expressionResult.setExpression(expression.toString());
67             expressionResult.setResult(firstNum.toString());
68             expressionResultHashSet.add(expressionResult);
69         }
70         return expressionResultHashSet;
71     }

 

 

3. 随机数和操作符的获取

 1 public class GeneratorUtil {
 2 
 3     private static final char OPERATORS[] = {'+', '-', '×', '÷'};
 4     private static final Random R = new Random();
 5 
 6     public static Fraction getFraction(int maximum) {
 7         //调整随机数为整数或者分数
 8         boolean isFraction = R.nextBoolean();
 9         return isFraction ? new Fraction(R.nextInt(maximum) + 1, R.nextInt(maximum) + 1) : new Fraction(R.nextInt(maximum) + 1, 1);
10     }
11 
12     public static char getOperator() {
13         return OPERATORS[R.nextInt(4)];
14     }
15 
16 }

 

4. 分数的运算操作 

 1 public class Calculator {
 2 
 3     /**
 4      * 化简
 5      */
 6     public static Integer simplify(Integer numerator, Integer denominator) {
 7         if (denominator == 0) return numerator;
 8         return numerator % denominator == 0 ? denominator : simplify(denominator, numerator % denominator);
 9     }
10 
11     //相加
12     public static Fraction ADD(Fraction first, Fraction second) {
13         return new Fraction(first.getNumerator() * second.getDenominator() + first.getDenominator() * second.getNumerator(),
14         first.getDenominator() * second.getDenominator());
15     }
16 
17     //相减
18     public static Fraction SUB(Fraction first, Fraction second) {
19         return new Fraction(first.getNumerator() * second.getDenominator() - first.getDenominator() * second.getNumerator(), first.getDenominator() * second.getDenominator());
20     }
21 
22     //相乘
23     public static Fraction MUL(Fraction first, Fraction second) {
24         return new Fraction(first.getNumerator() * second.getNumerator(), first.getDenominator() * second.getDenominator());
25     }
26 
27     //相除
28     public static Fraction DIV(Fraction first, Fraction second) {
29         return MUL(first, Countdown(second));
30     }
31     //取倒
32     public static Fraction Countdown(Fraction fraction) {
33         return new Fraction(fraction.getDenominator(), fraction.getNumerator());
34     }
35 
36     //比较大小
37     public static boolean CMP(Fraction first, Fraction second) {
38         Fraction result = DIV(first, second);
39         return result.getNumerator() > result.getDenominator() && result.getNumerator() > 0 ? true : false;
40     }
41     //获取最大公因数并约去(辗转相除法)
42     public static int GCD(int a, int b) {
43         if (b == 0) return a;
44         return a % b == 0 ? b : GCD(b, a % b);
45     }
46 }

 

5. 题目、答案文件和答案比对结果文件的生成

 1 public static void generateFile(HashSet<ExpressionResult> expressionResultHashSet) throws IOException {
 2         File questionFile = new File("Exercises.txt");
 3         File answerFile = new File("Answers.txt");
 4         if (!questionFile.exists()) {
 5             questionFile.createNewFile();
 6         }
 7         if (!answerFile.createNewFile()) {
 8             answerFile.createNewFile();
 9         }
10         try (BufferedWriter abw = new BufferedWriter(new FileWriter(answerFile));
11              BufferedWriter qbw = new BufferedWriter(new FileWriter(questionFile))) {
12 
13             int count = 1;
14             for (ExpressionResult e : expressionResultHashSet) {
15                 try {
16                     qbw.write(count + "." + e.getExpression());
17                     qbw.newLine();
18                     abw.write(count + "." + e.getResult());
19                     abw.newLine();
20             //将表达式放入队列,在监听线程中拼接到界面中去
21                     GuiForOperator.queue.add(count + "." + e.getExpression() + "=" + e.getResult());
22                     count++;
23                 } catch (IOException e1) {
24                     e1.printStackTrace();
25                 }
26             }
27 
28         }
29     }
 1 public static void CompareAnswers(File answerFile) throws IOException {
 2         List<String> correctList = new ArrayList<>();
 3         List<String> wrongList = new ArrayList<>();
 4         try (BufferedReader qrAnswer = new BufferedReader(new FileReader(answerFile));
 5              BufferedReader qrExercise = new BufferedReader(new FileReader("Answers.txt"))) {
 6             String eStr = null;
 7             String aStr = null;
 8             while ((eStr = qrExercise.readLine()) != null && (aStr = qrAnswer.readLine()) != null) {
 9                 String orderNum = eStr.substring(0, eStr.indexOf("."));
10                 String standardAnswer = aStr.substring(2, aStr.length());
11                 String submitAnswer = eStr.substring(2, eStr.length());
12                 if (standardAnswer.equals(submitAnswer)) {
13                     correctList.add(orderNum);
14                 } else {
15                     wrongList.add(orderNum);
16                 }
17             }
18         }
19         File gradeFile = new File("Grade.txt");
20         if (!gradeFile.exists()) {
21             gradeFile.createNewFile();
22         }
23         try (BufferedWriter bw = new BufferedWriter(new FileWriter(gradeFile))) {
24             StringBuilder correctStr = new StringBuilder().append("Correct: ").append(correctList.size()).append(" (");
25             StringBuilder wrongStr = new StringBuilder().append("Wrong: ").append(wrongList.size()).append(" (");
26             correctList.forEach((e) -> {
27                 correctStr.append(e + ",");
28             });
29             wrongList.forEach((e) -> {
30                 wrongStr.append(e + ",");
31             });
32             bw.write(correctStr.toString().substring(0, correctStr.lastIndexOf(",")) + ")");
33             bw.newLine();
34             if (wrongList.size() != 0) {
35                 bw.write(wrongStr.toString().substring(0, wrongStr.lastIndexOf(",")) + ")");
36             } else {
37                 bw.write(wrongStr.append(")").toString());
38             }
39        //将比对结果放入队列,在监听线程中拼接到界面中去
40             GuiForOperator.queue.add(correctStr.toString().substring(0, correctStr.lastIndexOf(",")) + ")");
41             GuiForOperator.queue.add(wrongStr.toString().substring(0, wrongStr.lastIndexOf(",")) + ")");
42 
43         }
44     }

6. 界面:包括传入参数、文件以及结果显示

 1 public class GuiForOperator extends JFrame {
 2    // 使用队列存放表达式,起线程监听,有则取出并显示
 3     public static BlockingQueue<String> queue = new LinkedBlockingQueue<>();
 4 
 5     private JPanel contentPane;
 6     private JTextField textField;
 7     private JTextField textField_1;
 8     public JTextArea textArea;
 9     public JScrollPane scrollPane;
10 
11 
12     /**
13      * Create the frame.
14      */
15     public GuiForOperator() {
16         setTitle("\u56DB\u5219\u8FD0\u7B97");
17         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
18         setBounds(100, 100, 706, 495);
19         contentPane = new JPanel();
20         contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
21         setContentPane(contentPane);
22         contentPane.setLayout(null);
23 
24         JLabel label = new JLabel("\u9898\u76EE\u6570\u91CF\uFF1A");
25         label.setBounds(55, 43, 76, 18);
26         contentPane.add(label);
27 
28         textField = new JTextField();
29         textField.setBounds(163, 35, 282, 35);
30         contentPane.add(textField);
31         textField.setColumns(10);
32 
33         JLabel label_1 = new JLabel("\u6700\u5927\u968F\u673A\u6570\uFF1A");
34         label_1.setBounds(55, 91, 125, 18);
35         contentPane.add(label_1);
36 
37         textField_1 = new JTextField();
38         textField_1.setBounds(163, 83, 282, 35);
39         contentPane.add(textField_1);
40         textField_1.setColumns(10);
41 
42 
43         scrollPane = new JScrollPane(textArea);
44         textArea = new JTextArea();
45         textArea.setEditable(false);
46         textArea.setBounds(55, 167, 591, 255);
47         textArea.setLineWrap(true);
48         scrollPane.setBounds(55, 167, 591, 255);
49         scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
50         contentPane.add(scrollPane);
51         scrollPane.setViewportView(textArea);
52 
53 
54         JButton button = new JButton("\u786E\u5B9A");
55         button.addActionListener(e -> {
56             String r = textField.getText();
57             String n = textField_1.getText();
58             textArea.setText("");
59             try {
60                 //传入参数生成表达式写入文件
61                 HashSet<ExpressionResult> expressionResults = Generator.generateExpression(Integer.valueOf(r), Integer.valueOf(n));
62                 Generator.generateFile(expressionResults);
63             } catch (IOException e1) {
64                 e1.printStackTrace();
65             }
66         });
67         button.setBounds(533, 87, 113, 27);
68         contentPane.add(button);
69         JButton btnNewButton = new JButton("选择文件");
70         btnNewButton.addActionListener(arg0 -> {
71 
72             JFileChooser jfc = new JFileChooser();
73             jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
74             jfc.showDialog(new JLabel(), "选择");
75             File file = jfc.getSelectedFile();//得到文件
76             if (file.isDirectory()) {
77                 System.out.println("文件夹:" + file.getAbsolutePath());
78             } else if (file.isFile()) {
79                 System.out.println("文件:" + file.getAbsolutePath());
80             }
81             try {
82                 //传入比对文件
83                 Generator.CompareAnswers(file);
84             } catch (IOException e) {
85                 e.printStackTrace();
86             }
87         });
88         btnNewButton.setBounds(533, 39, 113, 27);
89         contentPane.add(btnNewButton);
90     }

 

7. 程序入口

 1 public class AppEntry {
 2     public static void main(String[] args) {
 3         //新建窗口并显示
 4         GuiForOperator frame = new GuiForOperator();
 5         frame.setVisible(true);
 6         //启动线程监听队列取出表达式进行显示
 7         new Thread(() -> {
 8             while (true) {
 9                 try {
10                     String expression = GuiForOperator.queue.take();
11                     if (expression != null) {
12                         frame.textArea.append(expression + "\r\n");
13                     }
14                 } catch (InterruptedException e) {
15                     e.printStackTrace();
16                 }
17             }
18         }).start();
19     }
20 }

 

 

七. 性能分析

 

生成一万道题目,数值在一万以内;生成十万道题目,数值在十万以内;生成一百万道题目,数值在一百万以内;

 

  

 

标签:return,四则运算,Fraction,new,firstNum,public,append
来源: https://www.cnblogs.com/hrunjie/p/15312147.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有