小学生四则混合运算

项目源码地址:https://git.dev.tencent.com/weizh588/sizeyunsuan.git

一、需求分析

  1. 程序可从命令行接收一个输入参数n,然后随机产生n道加减乘除练习题。
  2. 每个数字在0和100之间,运算符3个到5个之间。
  3. 每个练习题至少要包含2种运算符。
  4. 所出的练习题在运算过程中不得出现负数与非整数。
  5. 将学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中。
  6. 支持有括号的运算式,包括出题与求解正确答案。注意,算式中存在的括号必须大于2个,且不得超过运算符的个数。(附加)
  7. 支持真分数的出题与运算(只需要涵盖加减法即可),且支持分数的自动化简。(附加)

二、功能设计

  1. 基本功能:实现四则运算的功能,并能够将题目输出到文本文件中。
  2. 扩展功能:能够随机产生带有括号的运算式。可以生成可以真分数的运算表达式,且分数可以自动化简。

三、设计实现

考虑到程序的可扩展性,我将程序分为以下的几个类

  • Main类:主要是用来控制命令行的输入,以及对输入格式的规定和限制。

  • FileCreate类:主要的功能实现部分。其中的getFile()函数用来生成运算式并生成得到txt文件。

  • Easy类 :实现简单的四则运算逻辑

  • Complex 类:“实现” 加括号的复杂的四则运算

  • calculate 类:做临时的一些运算处理

各类之间的逻辑关系图:

 

四、算法详解

简单的四则运算:

 // 输出看的字符
        List see =new ArrayList<>();
        see.add('*');see.add('+');see.add('÷');see.add('-');
        //计算机能够识别的字符
        List result =new ArrayList<>();
        result.add('*');
        result.add('+');
        result.add('/');
        result.add('-');

        //储存临时运算符号
        List key =new ArrayList<>();
//        key.add(0,"+");
        //先初始化一个key
//        key.set(0,result.get((int)(Math.random()*4)));
        String tosee = "";
        String toresult = "";
        //符号的数量m
        int m = (int) (Math.random() * 3 + 3);
        //用来储存运算数的数组;
//        List num=new ArrayList();
        int[] num = new int[m + 1]; // 数字

        //在0-100中随机生成
        for (int i = 0; i <= m; i++) {
            num[i] = (int) (Math.random() * 101);
        }

        for (int j=0;j<m;j++){
            if(j>0&&key.get(j-1).equals('-')){
                key.add(j,'+');
            }
            else  if (j>0&&key.get(j-1).equals('/')){
                key.add(j,result.get((int)(Math.random()*2)));
            }
            else
            {
                int k=(int)(Math.random()*4);
                System.out.println(k);
                key.add(j,result.get((int)(Math.random()*4)));
            }
            tosee += String.valueOf(num[j]) + String.valueOf(key.get(j));
            toresult += String.valueOf(num[j]) + String.valueOf(key.get(j));
        //开始要判断是否两个数为负数或者为分数
            if (key.get(j).equals('-')){
                num[j+1]= calculate.subtraction(num[j],num[j+1]);
            }
            if (key.get(j).equals('/')){
                num[j+1]= calculate.division(num[j],num[j+1]);
            }

        }
        //接下来要判断运算符是否符合要求

        int count=0;
        for (int i=0;i<key.size()-1;i++){
            if (key.get(i)==key.get(i+1)){
                count++;
            }
        }
        //如果count==运算符数量m  即表示所有的符号都是一样的,重新再来
        if (count==m){
            return arithmetic();
        }
       else {
            tosee+=String.valueOf(num[m]);
            toresult+=String.valueOf(num[m]);
            return tosee + "=" + calculate.result(toresult);

        }

复制代码有括号的四则运算:

 /**
     * 带有括号的四则运算
     */
    public static String bracket() {

        int flag = 0; // 用来防止出现除0错误
        int brack_left = 0; // 记录未匹配的左括号个数
        int count = 0; // 括号个数
        int op;
        char result[] = { '+', '-', '*', '/' };
        char see[] = { '+', '-', '*', '÷' };
        String temp1 = "";
        String temp2 = "";
        int n = (int) (Math.random() * 3 + 4); // 数字个数
        int[] num = new int[n];
        for (int j = 0; j < n; j++) {
            num[j] = (int) (Math.random() * 101); // 数字
        }
        int i;
        for (i = 0; i < (n - 2); i++) { // 循环生成算式
            if (flag == 1) { // 若此时需要生成的数字前的符号是'/',则需要特判此次生成的数字不能为0
                flag = 0;
                num[i] = (int) (Math.random() * 100 + 1);//不为0
            } else if (flag == 2) {
                flag = 0;
                num[i] = calculate.subtraction(num[i - 1], num[i]); // 确保能够相减
            }
            temp1 += num[i];
            temp2 += num[i];
            int tmpcnt = brack_left;
            for (int j = 0; j < tmpcnt; j++) { // 若当前有未匹配的左括号,则对每一个未匹配的左括号,都有一定概率生成相应右括号。
                if ((int) (Math.random() * 5) > 1) { // 生成右括号概率为0.6
                    brack_left--;
                    temp1 += ")";
                    temp2 += ")";
                }
            }

            op = (int) (Math.random() * 4); // 生成运算符
            temp1 += result[op];
            temp2 += see[op];
            if (op == 3) // 若生成了除号,则需要置相应标志位
                flag = 1;
            else if (op == 1) // 若生成了减号,则需要置相应标志位
                flag = 2;
            if (((count * 2) <= (n - 1)) && (((int) (Math.random() * 2)) == 0)) { // 以一定概率生成左括号,概率为1/2
                temp1 += "(";
                temp2 += "(";
                count++;
                brack_left++;
                temp1 += num[++i]; // 生成左括号后必须生成一个数字和运算符,不然可能出现(15)这样的错误
                temp2 += num[i];
                op = (int) (Math.random() * 4);
                temp1 += result[op];
                temp2 += see[op];
                if (op == 3)
                    flag = 1;
                else if (op == 1)
                    flag = 2;
            }
        }
        while (i != (n - 1)) { // 判断是否为最后一个数
            if (flag == 1) {
                flag = 0;
                num[i + 1] = (int) (Math.random() * 100 + 1);
            } else if (flag == 2) {
                flag = 0;
                num[i + 1] = calculate.subtraction(num[i], num[i + 1]);
            }
            temp1 += num[i];
            temp2 += num[i];
            op = (int) (Math.random() * 4);
            temp1 += result[op];
            temp2 += see[op];
            i++;
        }


        if (flag == 1) { // 最后不生出运算符
            flag = 0;
            num[n - 1] = (int) (Math.random() * 100 + 1);
        } else if (flag == 2) {
            flag = 0;
            num[n - 1] = calculate.subtraction(num[n - 2], num[n - 1]);
        }
        temp1 += num[n - 1];
        temp2 += num[n - 1];
        while ((brack_left) != 0) { // 补全右括号
            temp1 += ")";
            temp2 += ")";
            brack_left--;
        }
        temp2 += "=";
        String result1 = String.valueOf(calculate.result(temp1));
        if (calculate.judgeIsDecimal(result1) || result1.contains("Infinity") || result.equals("NaN")) {
            return bracket();// 小数、无穷、非数处理
        } else {
            int result0 = Integer.valueOf(result1);
            if (result0 < 0) {
                return bracket();// 负数处理
            } else {
                return temp2 + result1;
            }
        }
    }

 

五、测试运行

1、在命令行中的运行结果展示:

 

 

Complex单元测试:

cmd测试:

 

 

2、生成的txt文件展示:

 

六、项目总结

这个项目呢,主要是想说下第二部分的问题,也就是带括号的那部分,一开始我是把简单的四则实现并且成功通过测试,然后我就想直接把生成的四则运算直接用来添加括号直接生成带括号的四则运算,结果发现这个方法并不可行,比如,原本的运算是合法的:5+1-9 这样子是合法的,但是加上括号后,(5+1)-9就出现了符号,因为运算过程中不能出现负数,所以这个生成的子运算列是不合法的,还有就是除法的时候,加上括号后,除数为0,也是不合法的,因此经过思考后,最终还是采取边生成边加括号边检验的方式来解决这个难题。

 

七、PSP展示

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值