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


      本次作业从布置的第一天我就着手做了,不过基础较差,并没有想过怎样实现相关功能,反正都是一步一步做的。我不知道我花了多少时间在这次作业上,但是在空闲的时候我就在琢磨。(今天大概从下午3点开始没课,我坐到在电脑前到8点半,先是修改代码,然后写完博客的大致内容,没去跑步,饭也忘了吃,食堂也关了门,第一次感受到了完成作业的喜悦,也感受到了程序员的艰苦╮(╯▽╰)╭真的是到了废寝忘食的地步)然后回到宿舍接着修改博客修改到宿舍断电。

      博客版式也是参考了同学的,感觉他们的排版与思路都很清晰,我也觉得可以借鉴借鉴o(* ̄︶ ̄*)o

    项目简介:

    Coding.net源码仓库地址:

                https://git.coding.net/francesca/Arithmetics.git

                SSH:git@git.coding.net:francesca/Arithmetics.git

    测试步骤:

    1.进入src文件夹

    2.在命令行输入javac -encoding utf-8 *.java

    3.回车再输入java Main 1000

    4.回车,将会在src同级目录下产生result.txt


    一、需求分析

        1.程序可从命令行接收一个输入参数n,然后随机产生n道加减乘除习题。

        2.每个数字在 0 和 100 之间,运算符3到5个。

        3.每道习题要包含3-5种运算符。

        4.所出的练习题在运算过程中不得出现负数与非整数。

        5.将学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中。

        6.支持有括号的运算式,包括出题与求解正确答案。算式中存在的括号必须大于2个,且不得超过运算符的个数。

     

    二、功能设计

        1.基本功能:

           能够根据用户输入的参数n随机产生n道符合要求的练习题,自动算出答案,并将式子与答案以文档的形式呈现。

      2.扩展功能:

            支持有括号的运算式,包括出题与求解正确答案。

            支持真分数运算,包括出题与解题正确答案。

            (注意,算式中存在的括号必须大于2个,且不得超过运算符的个数。)

     

    三、设计实现

                      

     

     

        BinaryTree:生成二叉树,获取最终表达式,计算并验证表达式

        File:负责产生result.txt文件,并将学号和产生的习题写入文件
        Main:主类,负责接收命令行的参数并启动程序

        Ran:获取随机运算符及随机数

        MakeF:生成真分数并计算结果

        TreeNode:生成节点,并获取每个节点的运算结果,并检验除法和减法每个运算式添加括号,然后根据去括号法则,去掉多余的子式的括号

     

    四、代码展示

       1.不出现负数与非整数

     public String getResult(){
            if(hasChild()){
                switch(str){
                    case "+":
                        return String.valueOf(Integer.parseInt(getLchild().getResult()) + Integer.parseInt(getRchild().getResult()));
                    case "-"://change
                        if(Integer.parseInt(getLchild().getResult()) - Integer.parseInt(getRchild().getResult()) < 0){
                            while(str.equals("-")){
                                str = String.valueOf(Ran.getOperator());
                            }
                            return this.getResult();
                        }
                        else
                            return String.valueOf(Integer.parseInt(getLchild().getResult()) - Integer.parseInt(getRchild().getResult()));
                    case "*":
                        return String.valueOf(Integer.parseInt(getLchild().getResult()) * Integer.parseInt(getRchild().getResult()));
                    case "÷":
                        if(getRchild().getResult().equals("0")){
                            while(str.equals("÷")){
                                str = String.valueOf(Ran.getOperator());
                            }
                            return this.getResult();
                        }
                        /**
                         * 整除运算
                         */
                        else if(Integer.parseInt(getLchild().getResult()) % Integer.parseInt(getRchild().getResult()) != 0){
                            while(str.equals("÷")){
                                str = String.valueOf(Ran.getOperator());
                            }
                            return this.getResult();
                        }
                     
                        else
                            return String.valueOf(Integer.parseInt(getLchild().getResult()) / Integer.parseInt(getRchild().getResult()));
                }
            }
            return str;
        }
    

        2.带括号的表达式

      public String toString(){
            String Lstr = "", Rstr = "", Str = "";
            if(hasChild()){
                //右子树如果有孩子,说明右子树是一个表达式,而不是数字节点。
                if(getRchild().hasChild()){
                    //判断左邻括号的运算符是否为'/'
                    if(str.equals("÷")){
                        //获取右子树的表达式,保留括号
                        Rstr = getRchild().toString();
                    }
                    //判断左邻括号的运算符是否为'*'或'-'
                    else if(str.equals("*") || str.equals("-")){
                        //判断op是否为'+'或'-'
                        if(getRchild().str.equals("+") || getRchild().str.equals("-")){
                            Rstr = getRchild().toString();
                        }
                        else{
                            //获取右子树的表达式,并且去括号
                            Rstr = getRchild().toString().substring(1, getRchild().toString().length()-1);
                        }
                    }
                    else{
                        //右子树除此之外都是可以去括号的。
                        Rstr = getRchild().toString().substring(1, getRchild().toString().length()-1);
                    }
                }
                else{
                    Rstr = getRchild().str;
                }
                //左子树的情况同右子树类似
                if(getLchild().hasChild()){
                    if(str.equals("*") || str.equals("÷")){
                        if(getLchild().str.equals("+") || getLchild().str.equals("-")){
                            Lstr = getLchild().toString();
                        }
                        else{
                            Lstr = getLchild().toString().substring(1, getLchild().toString().length()-1);
                        }
                    }
                    else{
                        Lstr = getLchild().toString().substring(1, getLchild().toString().length()-1);
                    }
                }
                else{
                    Lstr = getLchild().str;
                }
                //获取当前的运算式,并加上括号
                Str = "(" + Lstr + str + Rstr + ")";
            }
            else{
                //若没有孩子,说明是数字节点,直接返回数字
                Str = str;
            }
            return Str;
        }
    

       3.真分数计算

     public String MakeFraction() {
            String str = null;
            String[] op2 = { "+", "-" };// 存储连接分数的操作符的数组
            int denominator = 1;
            int numerator = 1;
            int denominator1 = (int) (Math.random() * 19) + 1;// 生成分母
            int numerator1 = (int) (Math.random() * 20);// 生成分子
            if (numerator1 != 0) {
                if (numerator1 > denominator1) {// 如果分子大于分母,也就是不是真分数时,交换分子分母,使其变成真分数
                    int temp = numerator1;
                    numerator1 = denominator1;
                    denominator1 = temp;
                }
                if (numerator1 == denominator1) {// 如果分子刚好等于分母,重新生成分子
                    numerator1 = (int) (Math.random() * 20);
                }
                int gcd1 = gcd(numerator1, denominator1);// 求分子分母最大公因数,保证分数形式最简
                denominator1 = denominator1 / gcd1;// 化简
                numerator1 = numerator1 / gcd1;// 化简
            }
            String question1 = numerator1 + "/" + denominator1;// 存储题目
            int count = (int) (Math.random() * 2) + 3;// 随机产生运算符的数目
            for (int u = 0; u < count; u++) {// 小于运算符数量时不断产生分数,不断计算
                int denominator2 = (int) (Math.random() * 19) + 1;// 生成分母
                int numerator2 = (int) (Math.random() * 20);// 生成分子
                if (numerator2 != 0) {
                    if (numerator2 > denominator2) {// 避免不是真分数
                        int temp = numerator2;
                        numerator2 = denominator2;
                        denominator2 = temp;
                    }
                    if (numerator2 == denominator2) {// 如果分子等于分母,重新生成分子
                        numerator2 = (int) (Math.random() * 20);
                    }
                    int gcd2 = gcd(numerator2, denominator2);// 化简分式,使其最简
                    denominator2 = denominator2 / gcd2;
                    numerator2 = numerator2 / gcd2;
                }
                int symbol = (int) (Math.random() * 2);// 随机产生运算符
                if (op2[symbol].equals("+")) {// 如果是加号,实现分数加法
                    if (denominator1 == denominator2) {// 如果两个分母相同,直接将分子相加
                        numerator = numerator1 + numerator2;
                    } else {// 通分,相加
                        denominator = denominator1 * denominator2;
                        numerator = numerator1 * denominator2 + numerator2 * denominator1;
                    }
                    if (denominator < numerator) {// 如果运算结果不是真分数
                        u--;// 计数的u减一,也就是重新生成重新计算
                    } else {// 在给定范围内的话,通分运算结果
                        int gcd = gcd(numerator, denominator);
                        denominator = denominator / gcd;
                        numerator = numerator / gcd;
                        question1 += op2[symbol] + numerator2 + "/" + denominator2;// 把题目进行完善
                        denominator1 = denominator;// 储存运算结果到denominator1和numerator1
                        numerator1 = numerator;
                    }
                } else {// 如果是减号,实现减法操作
                    if (denominator1 == denominator2) {// 分母相同直接分子相减
                        numerator = numerator1 - numerator2;
                    } else {// 其他情况,先通分再相减
                        denominator = denominator1 * denominator2;
                        numerator = numerator1 * denominator2 - numerator2 * denominator1;
                    }
                    if (numerator < 0) {// 如果导致结果小于0了,就重新生成
                        u--;
                    } else {// 通分结果化简
                        int gcd = gcd(numerator, denominator);
                        denominator = denominator / gcd;
                        numerator = numerator / gcd;
                        question1 += op2[symbol] + numerator2 + "/" + denominator2;
                        denominator1 = denominator;// 储存通分结果
                        numerator1 = numerator;
                    }
                }
            }
            str = question1 + " = " + numerator + "/" + denominator;
            return str;
            //System.out.println(question1 + " = " + numerator + "/" + denominator);// 输出题目和答案
        }
    

       4、最大公因数

     public int gcd(int x, int y) {// 求最大公因数的函数
            if (x == 0) {
                return y;
            } else {
                return gcd(y % x, x);
            }
        }
    

     

    五、测试运行

     

     

     六、PSP

     

    SP2.1

    任务内容

    计划共完成需要的时间(m)

    实际完成需要的时间(m)

    Planning

    计划

    1500

    2000

    ·        Estimate

    ·   估计这个任务需要多少时间,并规划大致工作步骤

    1000

    1400

    Development

    开发

    1902

    3323

    ·        Analysis

    ·         需求分析 (包括学习新技术)

    90

    123

    ·        Design Spec

    ·         生成设计文档

    0

    0

    ·        Design Review

    ·         设计复审 (和同事审核设计文档)

    0

    0

    ·        Coding Standard

    ·         代码规范 (为目前的开发制定合适的规范)

    0

    0

    ·        Design

    ·         具体设计

    300

    480

    ·        Coding

    ·         具体编码

    1200

    2300

    ·        Code Review

    ·         代码复审

    180

    300

    ·        Test

    ·         测试(自我测试,修改代码,提交修改)

    132

    120

    Reporting

    报告

    360

    380

    ·         Test Report

    ·         测试报告

    300

    320

    ·         Size Measurement

    ·         计算工作量

    30

    30

    ·         Postmortem & Process Improvement Plan

    ·         事后总结, 并提出过程改进计划

    30

    30

     

    七、总结

       1、最开始的随机数和随机符的产生也是琢磨了一小会儿,不过还好,通过百度加深了对java的理解,也更深一步了解了Random类和Math类下的random方法的区别。

       2、是对非整数结果的构思,一开始采用的是比较除数和被除数的大小,然后交换数据,这个更改了好多遍,后来发现可以再次随机产生除了除法以外的运算符,这个花费了好长时间,不过在这个基础下,我接着没几分钟就完成了非负数的完成。

         3、是附加功能中的括号查了很多资料,发现要用中缀转后缀表达式,用堆栈,这个过程比较容易懂,但是代码还是挺难明白的,在请教学长得前提下,终于解决了,收获也很大。

       4、关于真分数的部分是在参考同学的代码中学习到的,也写了另外的类去测试,完成的比较好。

       5、项目大部分功能是在本周三完成的,当时很兴奋。不过后来才去看了题目要求,发现要在命令行测试数据,并写入text文件,看了java教程后发现是File的相关内容,代码完成的比较好,就是命令行是第一次用,从周四晚上开始就在琢磨为什么我电脑的命令行输入会出现乱码,查看了很多博客,没找到一个成功的,到了周五下午,在学长得帮助下才发现之前的环境变量配置错了。

      6、接着是传项目,我自己电脑配置好了git和相关的一些公钥,传项目也很熟练,不过换了台式电脑后,周五下午又花了一个小时弄公钥和传项目,成功传项目有很多方式,最后发现自己写的通过git传到GitHub的博客中的方式最简单。

       总之,通过这次作业,我深刻意识到对java的掌握还不够,相关算法也是查阅很多博客和书籍才实现的。每晚睡觉都还想着怎么实现非负数和非整数,说真的作业很难,不过收获很大,这两周很充实也很疲惫。总之努力就会有收获,很庆幸自己没有放弃,我也会继续努力的ヾ(◍°∇°◍)ノ゙。

      最后非常感谢您的阅读,您辛苦啦!

  • 相关阅读:
    HTML/CSS基础教程 一
    linux鼠标闪烁问题解决
    Linux运行级别(runlevel)
    linux命令——umask
    linux命令——ulimit
    算法学习(二)——二分查找
    c++(一) :从c到c++
    shell编程(二)输入,输出和算术拓展
    shell编程(一)基础
    第二次Soring冲刺计划第一天(团队)
  • 原文地址:https://www.cnblogs.com/tingjuanli/p/8632652.html
Copyright © 2020-2023  润新知