• 2016012087+小学四则运算练习软件项目报告


    项目源码地址:https://git.coding.net/Donsparks/project1.git

    测试效果见src下生成的result.txt文件

    一、需求分析

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

    二、功能设计

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

    三、设计实现

    考虑到程序的可扩展性,我将程序分为两个大类。

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

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

    函数间逻辑关系:Main类中通过new一个新的对象,然后来调用File类中的getFile()方法,从而实现运算式的生成,并得到文本文件。

    四、算法详解

    我采用的算法,是我个人比较擅长的枚举法。通过java中的if语句和switch语句,从而得到随机生成的四则运算。代码如下:

       int a = 0;  //运算式的第一个随机数
        int b = 0;  //运算式的第二个随机数
        int c = 0;  //运算式的第三个随机数
        int d = 0;  //运算式的第四个随机数
        int e = 0;  //运算式的第五个随机数
    
        int num = 0;    //保存运算式结果
        String q = "";  //保存运算式
    
        Random random = new Random();
        int i = 0;
        while (i < x) {
            a = (int) (Math.random() * 100 + 1);
            b = (int) (Math.random() * 100 + 1);
            c = (int) (Math.random() * 100 + 1);
            d = (int) (Math.random() * 100 + 1);
            e = (int) (Math.random() * 100 + 1);
    
            int z = random.nextInt(5) % (5 - 3 + 1) + 3;//产生一个3-5之间的随机数,用来设定运算式的数值个数
            if (z == 3) {
                //3个数,则产生两个运算符
                int A = random.nextInt(4) % (4 - 1 + 1) + 1;
                switch (A) {
                    case 1:
                        num = a + b;
                        q = a + "+" + b;
                        break;
                    case 2:
                        num = a - b;
                        q = a + "-" + b;
                        break;
                    case 3:
                        num = a * b;
                        q = a + "*" + b;
                        break;
                    default:
                        num = a / b;
                        q = a + "/" + b;
                        break;
                }
                int B = random.nextInt(4) % (4 - 1 + 1) + 1;
                switch (B) {
                    case 1:
                        num = num + c;
                        q = q + "+" + c;
                        break;
                    case 2:
                        num = num - c;
                        q = q + "-" + c;
                        break;
                    case 3:
                        num = num * c;
                        q = q + "*" + c;
                        break;
                    default:
                        num = num / c;
                        q = q + "/" + c;
                        break;
                }
    
            ......
    
            }

    五、测试运行

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

    2、生成的txt文件展示:

    六、部分代码展示

    1、片段一:

        int i = 0;
        while (i < x) {
    
        ......
    
        String hush = String.valueOf(jse.eval(q));
        Double result = Double.parseDouble(hush);
    
        if (result < 0 || result % 1 != 0) {
            continue;
        }   //保证结果不为负数或者非整数
    
        fop.write((q + "=" + jse.eval(q)).getBytes());    //写入表达式
        fop.write("
    ".getBytes());   //换行
        System.out.println(q + "=" + jse.eval(q));
        q = "";
        result = (double) 0;
        i++; //重新置为空,重新开始
        }

    此部分代码通过一个while语句,实现了一次循环输出,并且还能够判断结果的数值,保证输出的结果全部是负数或整数。

    此外,这样一来,无论我们要生成多少道题,都可以马上算出来,无论是否超出此次项目的规定的0到1000道。这也是我个人觉得非常不错的一点。但是同样也存在一些不足,比如代码运行效率较低,主要原因还是在于这里是先得到运算结果然后再判断是否符合要求,然后再决定是否保留这一运算式。这样一来,就会程序就需要跑一些没必要的运算式。从而浪费了很多空间和时间,代码效率较低。

    当然,针对这一问题,我也有一些改进的想法,比如可以直接就选择一些能够整除,或者减数小于被减数的数字。从而减少一些没必要的运算。

    2、片段二:

        int a = 0;  //运算式的第一个随机数
        int b = 0;  //运算式的第二个随机数
        int c = 0;  //运算式的第三个随机数
        int d = 0;  //运算式的第四个随机数
        int e = 0;  //运算式的第五个随机数
    
        int num = 0;    //保存运算式结果
        String q = "";  //保存运算式
    
        int i = 0;      //x是通过命令行输入的数字,即要生成的题目数
        while (i < x) {
            a = (int) (Math.random() * 100 + 1);
            b = (int) (Math.random() * 100 + 1);
            c = (int) (Math.random() * 100 + 1);
            d = (int) (Math.random() * 100 + 1);
            e = (int) (Math.random() * 100 + 1);
    
            int z = random.nextInt(5) % (5 - 3 + 1) + 3;//产生一个3-5之间的随机数,用来设定运算式的数值个数
    
            //3个运算数的情况,则产生两个运算符
            if (z == 3) {
                int A = random.nextInt(4) % (4 - 1 + 1) + 1;
                switch (A) {
                    case 1:
                        num = a + b;
                        q = a + "+" + b;
                        break;
                    case 2:
                        num = a - b;
                        q = a + "-" + b;
                        break;
                    case 3:
                        num = a * b;
                        q = a + "*" + b;
                        break;
                    default:
                        num = a / b;
                        q = a + "/" + b;
                        break;
                }
                int B = random.nextInt(4) % (4 - 1 + 1) + 1;
                switch (B) {
                    case 1:
                        num = num + c;
                        q = q + "+" + c;
                        break;
                    case 2:
                        num = num - c;
                        q = q + "-" + c;
                        break;
                    case 3:
                        num = num * c;
                        q = q + "*" + c;
                        break;
                    default:
                        num = num / c;
                        q = q + "/" + c;
                        break;
                }
    
            //4个运算数的情况,则产生三个运算符
            ......
    
            //5个运算数的情况,则产生四个运算符
            ......
            }

    这部分代码是我个人觉得非常精彩的一段代码。虽然仅仅只是用了一个if语句,再加上几个switch语句,但是却完美的实现了运算数和运算符的随机选择。通过一个if语句,选择运算数的个数,然后再通过一个switch语句在“+”、“-”、“*”、“”四个运算符随机选择,有几个运算符,就写几个switch片段。这简简单单的语法,却实现了这么复杂的功能,我突然体会到java语言的魅力,代码的魅力,编程的魅力!

    上面的代码,只列出了三个运算数,也就是两个运算符的情况。不过当我写到五个运算符的情况的时候我不禁想到一个问题,我的项目的可扩展性怎么样。不错,确实是这么个问题,虽然整个代码的逻辑非常清晰易懂。但是整个程序的可扩展性不强。但是经过一番思考,我觉得代码的可扩展性还是可以有所改进,因为每个switch代码段的内容都是一样的,所以可以将那一整段代码封装起来,再利用一个for循环,直接就可以达到我们运算符随机生成的目的,这样一来,无论要生成多少个运算符的运算式,我们都可以轻松实现。

    3、片段三

        ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
        String hush = String.valueOf(jse.eval(q));
        Double result = Double.parseDouble(hush);

    这段代码也是我同样非常喜欢的一段代码,虽然仅仅用了三行语句,但是却解决了一个非常关键的问题,那就是运算符优先级的问题。其实我一开始是想用num去保存运算式的结果,这在我的片段二代码中可以清晰的体现。但是后来发现不可以,因为那样子的话,就忽律了运算符优先顺序的问题,从而使得题目的结果都是错误的(这是一个很严肃的问题!哈哈哈哈哈哈哈哈...)。后来我找到了这个eval()函数,利用它可计算某个字符串,并执行其中的的 JavaScript代码的功能从而得到正确的运算式结果result。而且刚刚好,我在前面已经记录并且表示出了运算式字符串,也就是q,所以这里直接引用即可!

    七、项目总结

    • 编程前:我以模块化的思想去设计,打算将文件生成,运算式产生分成两部分去写,并且我知道最总要的部分还是运算式的产生部分,因为会涉及到较多的算法逻辑,也是整个项目的核心块。

    • 编程过程中:我又把文件生成和运算时的产生两部分放到了File类中,然后再单独写一个Main函数。通过这个Main函数去调用File类中的方法。从而实现模块与模块之间的联系。同时又加强了项目的可读性、可扩展性和可移植性。

    • 测试阶段(代码复审):我以模块去测试,一个一个模块的检查,测试,通过,最后连接在一起,项目跑起来,运行成功的那一刹那,我无比的激动和兴奋,那种感觉是前所未有的。

    八、PSP展示

  • 相关阅读:
    [转]来扯点ionic3[2] 页面一线牵 珍惜这段缘
    [转]ionic工作原理
    [转]禁止浏览器自动保存密码弹框
    [转]git提交代码时遇到代码库有更新以及本地有更新的解决方法
    [转]Angular 4 *ngIf/Else
    [转]Angular4 引用 material dialog时自定义对话框/deep/.mat-dialog-container
    ES之五:ElasticSearch聚合
    Logstash之四:配置说明
    Logstash之三:命令行中常用的命令
    Logstash之二:原理
  • 原文地址:https://www.cnblogs.com/xdhou/p/8641679.html
Copyright © 2020-2023  润新知