Java实现四则运算 谢雅淇 袁杏仪

GitHub链接:https://github.com/3216004716/four-operations.git

项目相关要求

  1. 使用 -n 参数控制生成题目的个数,例如

    Myapp.exe -n 10 将生成10个题目。

  1. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如

    Myapp.exe -r 10

    将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。

  1. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2。

  2. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。

  3. 每道题目中出现的运算符个数不超过3个。

  4. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。

    生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:

    1. 四则运算题目1

    2. 四则运算题目2

    其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

  1. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:

    1.答案1

    2.答案2

    特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

  1. 程序应能支持一万道题目的生成。

  2. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:

    Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

    统计结果输出到文件Grade.txt,格式如下:

      Correct: 5 (1, 3, 5, 7, 9)

      Wrong: 5 (2, 4, 6, 8, 10)

    其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

PSP:

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

解题思路:

  • 取随机操作数

  • 取随机操作符

  • 生成表达式

  • 由表达式转换为后缀表达式

  • 后缀表达式入栈,计算

  • 去重

  • 结果写入文件

设计实现过程

  • Utils

    • RandomUtil 生成随机操作数和随机操作符

    • ExpressionUtil 生成表达式

    • CalculateUtil 封装计算的方法

    • FileUtil 生成题目和答案的文档

  • Calculate

    • calculateResult 用于计算结果

  • Expression

    • CheckExpression 检查重复的表达式

    • MyExpression 表达式类

    • PostfixExpression 生成后缀表达式

代码说明

  • RandomUtil类 获取随机操作数,用了Math.random()

// 获取随机操作数
    public static String getRandomOperand(int range) {
        String Operand = null;
        int index = (int) (Math.random() * 4);
        if (index == 0) {// 生成分数
            index = (int) (Math.random() * 3);
            if (index == 2) {// 生成假分数
                Operand = getImproperTractionNumber(range);
            } else {// 生成真分数
                Operand = getTruTractionNumber(range);
            }
        } else {
            Operand = getNaturalNumber(range);// 生成整数
        }
        return Operand;
    }
  • ExpressionUtil类 获取随机表达式

public static MyExpression getRandomExpression(int range) {
        // 获取随机表达式
        MyExpression myExpression = null;
        int index = (int) (Math.random() * 10);
        if (index <= 3) {
            myExpression = getOneOperExp(range);// 一个操作符
        } else if (index == 4) {// 三个操作符
            index = (int) (Math.random() * 2);
            if (index == 0) {
                myExpression = getThreeOperExp(range);
            } else {
                myExpression = getThreeOperExpWithBracket(range);
            }
        } else {// 两个操作符
            index = (int) (Math.random() * 2);
            if (index == 0) {
                myExpression = getTwoOperExp(range);
            } else {
                myExpression = getTwoOperExpWithBracket(range);
            }
        }
        CaculateResult.caculate(myExpression);  // 计算结果
return myExpression;
    }
  • PostfixExpression类 生成后缀表达式

private static ArrayList<String> generatePostfixExpression(String expression) {
        //生成String类型的后缀表达式
        String[] expressionArray = expression.split(" ");
        ArrayList<String> postfixExpression = new ArrayList<String>();
        Stack<String> stack = new Stack<String>();
        for (int i = 0; i < expressionArray.length; i++) {
            String item = expressionArray[i];
            String temp = "";
            switch (item) {
            case "(":
                stack.push(item);
                break;
            case ")":
                while ((stack.size() != 0) && !((temp = stack.pop()).equals("("))) {
                    postfixExpression.add(temp);
                }
                break;
            case "+":
            case "-":
                while ((stack.size() != 0) && !((temp = stack.pop()).equals("("))) {
                    postfixExpression.add(temp);
                }
                if (temp.equals("(")) {
                    stack.push(temp);
                }
                stack.push(item);
                break;
            case "×":
            case "÷":
                while ((stack.size() != 0) && !((temp = stack.pop()).equals("("))) {
                    if (temp.equals("×") || temp.equals("÷")) {
                        postfixExpression.add(temp);
                    } else {
                        stack.push(temp);
                        break;
                    }
                }
                if (temp.equals("(")) {
                    stack.push(temp);
                }
                stack.push(item);
                break;
            default:
                postfixExpression.add(item);
            }
        }
        while (stack.size() != 0) {
            postfixExpression.add(stack.pop());
        }
        return postfixExpression;
    }
  • CalculateResult类 计算后缀表达式

public class CaculateResult {

    public static void caculate(MyExpression myExpression) {
        PostfixExpression.toPostfixExpression(myExpression);
        ArrayList<String> postfixExpression = myExpression.getPostfixExpression();
        String temp = "";
        Stack<String> s = new Stack<>();

        String rightOperand = null;
        String leftOperand = null;
        int result = 0;
        int a1, a2, b1, b2 = 0;
        int denominator = 0;
        int numerator = 0;
        a: for (int i = 0; i < postfixExpression.size(); i++) {

            String item = postfixExpression.get(i);
            switch (item) {
            case "+":
                rightOperand = s.pop();
                leftOperand = s.pop();
                if (CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    result = Integer.parseInt(rightOperand) + Integer.parseInt(leftOperand);
                    temp = String.valueOf(result);
                } else if (CaculateUtil.isNumeric(rightOperand) && !CaculateUtil.isNumeric(leftOperand)) {
                    denominator = CaculateUtil.getDenominator(leftOperand);
                    numerator = CaculateUtil.getNumerator(leftOperand);
                    numerator = Integer.parseInt(rightOperand) * denominator + numerator;
                    temp = numerator + "/" + denominator;
                } else if (!CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    denominator = CaculateUtil.getDenominator(rightOperand);
                    numerator = CaculateUtil.getNumerator(rightOperand);
                    numerator = Integer.parseInt(leftOperand) * denominator + numerator;
                    temp = numerator + "/" + denominator;
                } else {
                    a1 = CaculateUtil.getDenominator(rightOperand);
                    a2 = CaculateUtil.getNumerator(rightOperand);
                    b1 = CaculateUtil.getDenominator(leftOperand);
                    b2 = CaculateUtil.getNumerator(leftOperand);
                    numerator = a1 * b2 + a2 * b1;
                    denominator = a1 * b1;
                    temp = numerator + "/" + denominator;
                }
                s.push(temp);
                break;

            case "×":
                rightOperand = s.pop();
                leftOperand = s.pop();
                if (CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    result = Integer.parseInt(rightOperand) * Integer.parseInt(leftOperand);
                    temp = String.valueOf(result);
                } else if (CaculateUtil.isNumeric(rightOperand) && !CaculateUtil.isNumeric(leftOperand)) {
                    numerator = CaculateUtil.getNumerator(leftOperand);
                    denominator = CaculateUtil.getDenominator(leftOperand);
                    numerator = numerator * Integer.parseInt(rightOperand);
                    temp = numerator + "/" + denominator;
                } else if (!CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    numerator = CaculateUtil.getNumerator(rightOperand);
                    denominator = CaculateUtil.getDenominator(rightOperand);
                    numerator = numerator * Integer.parseInt(leftOperand);
                    temp = numerator + "/" + denominator;
                } else {
                    a1 = CaculateUtil.getDenominator(rightOperand);
                    a2 = CaculateUtil.getNumerator(rightOperand);
                    b1 = CaculateUtil.getDenominator(leftOperand);
                    b2 = CaculateUtil.getNumerator(leftOperand);
                    numerator = a2 * b2;
                    denominator = a1 * b1;
                    temp = numerator + "/" + denominator;
                }
                s.push(temp);
                break;

            case "-":
                leftOperand = s.pop();
                rightOperand = s.pop();
                int inta, intb = 0;
                if (CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    inta = Integer.parseInt(rightOperand);
                    intb = Integer.parseInt(leftOperand);
                    result = inta - intb;
                    temp = String.valueOf(result);
                } else if (CaculateUtil.isNumeric(rightOperand) && !CaculateUtil.isNumeric(leftOperand)) {
                    inta = Integer.parseInt(rightOperand);
                    numerator = CaculateUtil.getNumerator(leftOperand);
                    denominator = CaculateUtil.getDenominator(leftOperand);
                    numerator = inta * denominator - numerator;
                    temp = numerator + "/" + denominator;
                } else if (!CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    intb = Integer.parseInt(leftOperand);
                    numerator = CaculateUtil.getNumerator(rightOperand);
                    denominator = CaculateUtil.getDenominator(rightOperand);
                    numerator = numerator - intb * denominator;
                    temp = numerator + "/" + denominator;
                } else {
                    a1 = CaculateUtil.getDenominator(rightOperand);
                    a2 = CaculateUtil.getNumerator(rightOperand);
                    b1 = CaculateUtil.getDenominator(leftOperand);
                    b2 = CaculateUtil.getNumerator(leftOperand);
                    numerator = a2 * b1 - a1 * b2;
                    denominator = a1 * b1;
                    temp = numerator + "/" + denominator;
                }
                if (temp.contains("-")||temp.equals("0")) {
                    myExpression.setCheckAnswer(false);
                    break a;
                }
                s.push(temp);
                break;

            case "÷":
                leftOperand = s.pop();
                rightOperand = s.pop();
                int integer_a = 0, integer_b = 0;
                if (CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    integer_a = Integer.parseInt(rightOperand);
                    integer_b = Integer.parseInt(leftOperand);
                    if (integer_b == 0) {
                        break;
                    } else if ((integer_a % integer_b) == 0) {
                        result = integer_a / integer_b;
                        temp = String.valueOf(result);
                    } else {
                        numerator = integer_a;
                        denominator = integer_b;
                        temp = numerator + "/" + denominator;
                    }
                } else if (CaculateUtil.isNumeric(rightOperand) && !CaculateUtil.isNumeric(leftOperand)) {
                    integer_a = Integer.parseInt(rightOperand);
                    numerator = CaculateUtil.getNumerator(leftOperand);
                    denominator = CaculateUtil.getDenominator(leftOperand);
                    int temp1 = numerator;
                    numerator = integer_a * denominator;
                    denominator = temp1;
                    temp = numerator + "/" + denominator;
                } else if (!CaculateUtil.isNumeric(rightOperand) && CaculateUtil.isNumeric(leftOperand)) {
                    integer_b = Integer.parseInt(leftOperand);
                    numerator = CaculateUtil.getNumerator(rightOperand);
                    denominator = CaculateUtil.getDenominator(rightOperand);
                    denominator = denominator * integer_b;
                    temp = numerator + "/" + denominator;
                } else {
                    a1 = CaculateUtil.getDenominator(rightOperand);
                    a2 = CaculateUtil.getNumerator(rightOperand);
                    b1 = CaculateUtil.getDenominator(leftOperand);
                    b2 = CaculateUtil.getNumerator(leftOperand);
                    numerator = a2 * b1;
                    denominator = a1 * b2;
                    temp = numerator + "/" + denominator;
                }
                s.push(temp);
                break;

            default:
                s.push(item);
                break;
            }
        }
        myExpression.setResult(CaculateUtil.reduceFractiong(temp));
    }
}
  • CheckExpression类 检查重复的表达式

public class CheckExpression {
​
    public static boolean checkRepeated(MyExpression expression1, MyExpression expression2) {
        boolean flag = true;
        if (expression1.getPostfixExpression().size() == expression2.getPostfixExpression().size()) {
            if (expToString(expression1.getPostfixExpression()).equals(expToString(expression2.getPostfixExpression()))
                    || changePosition(expression1).equals(expToString(expression2.getPostfixExpression()))) {
                flag = false;
            }
        }
        return flag;
    }
​
    static String changePosition(MyExpression expression) {
        ArrayList<String> postfixExpression = expression.getPostfixExpression();
        String firstOperator = getFirstOperator(postfixExpression);
        if (firstOperator.equals("+") || firstOperator.equals("×")) {
            int index = postfixExpression.indexOf(firstOperator);
            String temp = postfixExpression.get(index - 1);
            postfixExpression.set(index - 1, postfixExpression.get(index - 2));
            postfixExpression.set(index - 2, temp);
        }
​
        return expToString(postfixExpression);
    }
​
    static String getFirstOperator(ArrayList<String> postfixExpression) {
        String operator = "";
        for (int i = 0; i < postfixExpression.size(); i++) {
            String item = postfixExpression.get(i);
            if (item.equals("+") || item.equals("-") || item.equals("×") || item.equals("÷")) {
                operator = item;
                break;
            }
        }
        return operator;
    }
​
    public static String expToString(ArrayList<String> PostfixExpression) {
        String string = null;
        for (int i = 0; i < PostfixExpression.size(); i++) {
            string += PostfixExpression.get(i);
        }
        return string;
    }
}

运行结果

项目小结

  • 谢雅淇:我觉得这次程序的编写,我只是在为了解决问题而写方法的代码,没有很好地融入面向对象的思想。还有在写代码之前就要把思路理清楚,不然代码就会写的很乱,不仅会浪费时间,还会把代码写得非常冗长,可观性比较差。这次作业的结对队友,从讨论需求到编写代码的过程中都帮助了我很多,我觉得我需要提升的地方还有很多,以后还需要继续努力,多加练习。

  • 袁杏仪:我觉得这次程序的编写,让我对开发程序有了更深入的了解,体会到沟通与合作的重要性,同时也感受到团队开发的乐趣,还收获了真挚的友谊。这次作业,让我感触最深的是我们写完代码后测试时,得出结果然后进行验算,检查出错答案并对源代码进行修改的过程,每一次修改,一步步得出正确的结果,这让我非常有成就感。

posted @ 2018-09-27 13:28  傻气  阅读(192)  评论(0编辑  收藏  举报