zoukankan      html  css  js  c++  java
  • 2016011990小学四则运算练习软件项目报告

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

     

    项目克隆地址:https://git.coding.net/chenf640/workhome2_2.git

    目录:

    一、需求分析

    二、功能设计

    三、设计实现

    四、算法详解

    五、测试运行

    六、代码展示

    七、psp

    八、总结

    ——————————————————————————————————————————————————

    一、需求分析

    (一)功能需求

     基本功能:

    • 程序可接收一个输入参数n,然后随机产生n道加减乘除(分别使用符号+-*÷来表示)练习题。
    • 每个数字在 0 和 100 之间,运算符在3个到5个之间;
    • 每个练习题至少要包含2种运算符;
    • 所出的练习题在运算过程中不得出现负数与非整数,比如3÷5+2=2.6,2-5+10=7等是不合法的;
    • 练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致;
    • 当程序接收的参数为4时,以下为一个输出文件示例。

    2018010203

    13+17-1=29

    11*15-5=160

    3+10+4-16=1

    15÷5+3-2=4

    扩展功能 

    • 支持有括号的运算式,包括出题与求解正确答案。
    • 扩展程序功能支持真分数的出题与运算(只需要涵盖加减法即可),例如:1/6 + 1/8 + 2/3= 23/24。注意在实现本功能时,需支持运算时分数的自动化简,比如 1/2+1/6=2/3,而非4/6,且计算过程中与结果都须为真分数。

    (二)程序需求

    1、只能使用Java语言。

    2、生成文件时请使用相对路径,生成的txt 文件需在项目的根目录下,可直接查看演示示例。

    3、使用的JDK版本为 jdk8u161,使用的JRE版本为jre8u161。

    4、不得使用除限定版本jdk与jre外的额外依赖包。

     

    二、功能设计

    (一)基本功能

    1、保证输入的是数字或者特定字符,如果不符合要求,会有提示,并且可以重新输入。

    2、当输入一个参数n,随机产生n道加减乘除算术题。保证生成的每个练习题至少要包含2种运算符。且保证在算数过程中,不出现负数,和小数。

    3、将生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致;

    4、为保证随机产生的四则运算更满足用户的需求,当输入参数n决定产生四则运算的个数时,另外输入一个参数m,决定产生的n道四则运算包含运算符的个数(3、4、5)  

    (二)扩展功能

    1、保证生成的分数运算,在运算过程中不产生假分数。并且实现自动化简。

    2、产生带有括号的运算式时保证不产生没有意义的括号。

    三、设计实现

    该程序我的设计思想是一个类实现一个功能,提高代码的重用性,减少冗杂度。让代码更清晰。

    (一)Main类

    功能:是主函数,包含 public static void main(String[] args) 方法。并且包含判断 输入的参数是否为整数的 函数,如果不是函数,可提示用户重新输入。

    目的:确保用户输入满足要求的整数的参数(产生四则运算数量1-1000,每个四则运算包含运算符3-5)

    (二)Algorithm类

    功能:产生符合要求的一个四则运算,不产生括号。该类中包含一个  带参的返回类型为字符串的函数。该函数参数为产生四则运算中包含的符号个数,可以产生包含任意多符号数量的四则运算,在该函数中,为满足用户需求,运算符数量可以为三、四、五,即该函数参数可以为3、4、5。

    目的:产生满足用户需求的四则运算。(包含的参数个数、在运算过程中不能产生负数、小数)

    关系:公有类,可直接调用。

    (三)BracketsAlgo类

    功能:产生符合要求的带有括号的四则运算该类中包含一个  带参的返回类型为字符串的函数。该函数参数为产生四则运算中包含的符号个数,可以产生包含任意多符号数量的四则运算,在该函数中,为满足用户需求,运算符数量可以为三、四、五,即该函数参数可以为3、4、5。

    目的:产生括号,增大运算难度。

    (四)Fraction类

    功能:生成分数运算,保证在运算过程中不产生假分数。并且实现自动化简。该函数参数为产生四则运算中包含的符号个数,可以产生包含任意多符号数量的四则运算,在该函数中,为满足用户需求,运算符数量可以为三、四、五,即该函数参数可以为3、4、5。

    目的:练习分数运算。

    (五)CreatFile类 

    功能:生成规定数量的四则运算,并将运算式与结果输出到result.txt文件中。该类中包含一个带参无返回的函数,该函数参数为要打印四则运算的数量。
    目的:将符合要求的四则运算输出到txt文件中,方便保留与查看。
    关系:公有类,可直接调用。

    (六)Symbol类

    功能:将产生的代表运算符的数字转换为对应的运算符。(0代表“+”,1代表“-”,2代表“*”,3代表“÷”)
    目的:输出符合规范的运算符

    (七)Test测试类

     功能:测试方法。

     

    四、算法详解(具体代码分析)

     (一)重要算法

    1.Algorithm类中的Algorithm算法

    算法功能:产生,符合要求的四则运算(运算过程中不产生负数、小数,每个四则运算至少包括两种运算符)

    算法思想

    1.1.判断产生的运算符不完全相等(至少包括两种)。

    • 用while循环,如果随机产生的数字完全相等,则一直循环,直到不完全一致。
    • 用数字0-3分别代表运算符的加减乘除,将随机生成的数字进行比较,如果四个数字完全相等,则重新生成,最终将满足要求的代表运算符的数字存到数组中。

    1.2.运算符之间优先级比较。

    • 将运算符从前到后两两比较,先计算优先级高的运算符,先乘除后加减,同级运算符从左向右依次计算。
    • 通过运算符两两比较,每循环一次就将生成的结果代替原来的数字,循环结束后,最终的结果会放到数组的最后一位。在计算过程中判断是否产生负数、是否产生小数,是否除数为0等,如果产生不满足要求的运算式,则舍去,重新开始。

    以一次循环为例:这是不完整的流程图,只包含其中一部分情况。

    1.3 .产生包含任意多运算符的四则运算。

    • 只需改变循环的次数

    1.4.将生成的正确的四则运算和结果放到一个字符串中,返回该字符串给 CreatFilel类中的写入文件方法。

    • 为了避免在比较优先级的循环中,改变存放数组与运算符的数组,因此,在进行循环判断前,将运算数与运算符交错放到数组中,如果通过验证证明该四则运算符合要求,则返回给 CreatFilel类中的写入文件方法,写入result.txt文件。
    • 在输出时,用for进行判断,如果是运算数子部分则直接输出,如果是运算符部分,则将数字转化为对应的运算符号进行输出。

    如图所示:

     

     

    2.CreatFile中的creatFile将生成结果写入指定文件

    •  将返回的字符串写入指定路径下的result.txt文件中,并在该文件第一行输出学号。
    • 该算法比较简单,需要导入java.io这个jar包。
    • 通过main方法调用,传入两个参数,生成算法的数量和每个算法包含的运算符数量。

    3.Fraction类中的fractionArithmetic算法

    算法功能:生成符合要求的分数运算式。

    算法实现:

    • 随机产生随机数字(0、1)来代表运算符(+、-)
    • 随机产生两个数字,一个做分母、一个做分子(不能为0)。在运算过程中,不断判断产生的分数是否大于等于一、并不断将分数进行化简。

    (二)其他算法

    1.Symbol方法中的symbol算法

    算法思想:输出运算符时,将数字与字符一一对应。用switch()语句即可完成。

    2.验证输入的为符合要求的整数(包括生成四则运算的数量、生成的四则运算中包含运算符的数量)

    算法思想:将输入的内容进行验证,先验证是否为整数,如果是整数,再验证该整数是否符合要求。若不符合要求,则对用户进行提示,要求重新输入

    在命令行结果如下:

    3.BracketsAlgo类中的bracketsAlgo算法

    算法功能:产生带有括号的符合要求的四则运算

    算法实现:

    • 将随机生成的运算符从左向右两两比较。如果前面的优先级高,则进行运算,保存结果;如果前面运算符的优先级低,则加上括号。
    • 该算法一定是从左向右依次运算。

    缺点:该算法可以生成带有括号的四则运算,但产生括号的数量不能确定。

     五、测试运行

    为了更好地实现用户的要求,在运行代码时需要输入你要打印的题目的具体数量,程序会随机产生包含3-5个运算符的符合要求的四则运算式(不带括号、带括号、分数)。

    1.进入src文件夹;

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

    3.回车再输入java Main 20;

    回车.result.txt文件生成,对应的运算式写入result.txt文件

     运算结果:
    文件内容(一半是带括号的 、一半是分数的):
     

    六、代码展示:

    Algorithm类中的Algorithm算法:

           /* 将运算符从前到后两两比较,先计算优先级高的运算符,先乘除后加减,同级运算符从左向右依次计算
                  在计算过程中判断是否产生负数、是否产生小数,是否除数为0等,如果产生不满足要求的运算式,
                  则舍去,如果符合要求,则打印出来。
                 */
                for (int i = 0; i < m.length; i++) {
                    if ((m1[i] < m1[i + 1]) && (m1[i + 1] == 2)) {
                    /* 包含情况为 0<2;1<2 计算优先级高的(乘法) 区域运算,并将结果放到 存放数字的数组中,运算过的运算符也被取代*/
                        num[i + 2] = num[i + 1] * num[i + 2];
                        num[i + 1] = num[i];
                        m1[i + 1] = m1[i];
                        number++;
                    } else if ((m1[i] < m1[i + 1]) && m1[i + 1] == 3 && m1[i] != 2) {
                    /* 包含情况为 0<3;1<3计算优先级高的(除法) 区域运算,并将结果放到 存放数字的数组中,运算过的运算符也被取代*/
                        if (num[i + 2] != 0) {              //首先除数不能为0
                            int a = num[i + 1] % num[i + 2];  //是否整除
                            if (a == 0) {                  //如果整除,进行除法运算
                                num[i + 2] = num[i + 1] / num[i + 2];
                                num[i + 1] = num[i];
                                m1[i + 1] = m1[i];
                                number++;
                            } else {                     //如果不能整除,重新进行四则运算的产生
                                number = 0;
                                for (int k = 0; k < m.length; k++) {
                                    m[k] = 0;
                                }
                                break;
                            }
                        } else {                       //除数为0,重新进行四则运算的产生
                            number = 0;
                            for (int k = 0; k < m.length; k++) {
                                m[k] = 0;
                            }
                            break;
                        }
                    } else if (m1[i] == 2 && m1[i + 1] == 3) {
                     /* 包含情况为 2<3计算从左向右进行,并将结果放到 存放数字的数组中*/
                        m[i + 1] = m[i] * m[i + 1];
                        number++;
                    } else if ((m1[i] < m1[i + 1]) && (m1[i + 1] == 1)) {
                     /* 包含情况为 0<1  计算从左向右进行,并将结果放到 存放数字的数组中*/
                        m[i + 1] = m[i] + m[i + 1];
                        number++;
                    } else if ((m1[i] > m1[i + 1]) && m1[i] == 3) {
                    /* 包含情况为 3>2;3>1;3>0  计算从左向右进行,并将结果放到 存放数字的数组中*/
                        if (num[i + 1] != 0) {              //被除数不能为0
                            int a = num[i] % num[i + 1];
                            if (a == 0) {                 //能够整除
                                num[i + 1] = num[i] / num[i + 1];
                                number++;
                            } else {
                                number = 0;
                                for (int k = 0; k < m.length; k++) {
                                    m[k] = 0;
                                }
                                break;
                            }
                        } else {                      //被除数为0
                            number = 0;
                            for (int k = 0; k < m.length; k++) {
                                m[k] = 0;
                            }
                            break;
                        }
                    } else if ((m1[i] > m1[i + 1]) && m1[i] == 2) {
                    /* 包含情况为 2>1;1>0  计算从左向右进行,并将结果放到 存放数字的数组中*/
                        num[i + 1] = num[i] * num[i + 1];
                        number++;
                    } else if ((m1[i] > m1[i + 1]) && m1[i] == 1) {
                    /* 包含情况为 1>0  计算从左向右进行,并将结果放到 存放数字的数组中*/
                        if (num[i] > num[i + 1]) {     //是否产生负数
                            num[i + 1] = num[i] - num[i + 1];
                            number++;
                        } else {
                            number = 0;
                            for (int k = 0; k < m.length; k++) {
                                m[k] = 0;
                            }
                            break;
                        }
                    } else {
                    /* 包括情况为0==0;1==1;2==2  3==3*/
                        if (m1[i] == m1[i + 1]) {
                            if (m1[i] == 0) {       //加法
                                num[i + 1] = num[i] + num[i + 1];
                                number++;
                            } else if (m1[i] == 1) {  //减法,判断是否产生负数
                                if (num[i] > num[i + 1]) {
                                    num[i + 1] = num[i] - num[i + 1];
                                } else {
                                    number = 0;
                                    for (int k = 0; k < m.length; k++) {
                                        m[k] = 0;
                                    }
                                    break;
                                }
                            } else if (m1[i] == 2) {    //乘法
                                num[i + 1] = num[i] * num[i + 1];
                                number++;
                            } else {                //除法运算,判断除数不能为0,不能产生小数
                                if (num[i + 1] != 0) {
                                    int a = num[i] % num[i + 1];
                                    if (a == 0) {
                                        num[i + 1] = num[i] / num[i + 1];
                                        number++;
                                    } else {
                                        for (int k = 0; k < m.length; k++) {
                                            m[k] = 0;
                                        }
                                        number = 0;
                                        break;
                                    }
                                } else {
                                    for (int k = 0; k < m.length; k++) {
                                        m[k] = 0;
                                    }
                                    number = 0;
                                    break;
                                }
                            }
                        }
                    }
                }

    2.判断你要打印的题目数量的个数是否为整数

    以打印题目数量为例:

         /**
         * 判断 输入你要打印的题目数量的个数是否为整数
         * @return
         */
        public static int numberTest() {
            Scanner input = new Scanner(System.in);
            int number =0;
            while(number<1||number>1000){
                System.out.print("请输入你要打印的题目数量 (1-1000):");
                String s = input.next();
                while (!(s != null && s.matches("^[0.0-9.0]+$"))) {// [0-9]没办法识别小数,[0.0-9.0]可以识别小数和整数
                    System.out.print("请输入正确的题目数量,类型为整数 (1-1000):");
                    s = input.next();
                }
                number = Integer.parseInt((s));
            }
            return number;
        }

    七、psp:

    本次编码并没有严格计算时间,刚开始也没有预测所有用到的时间,下表所填的时间是估计的,可能不是很准确,下次再做作业时会更加准确的记录时间。

    PSP2.1

    任务内容

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

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

    Planning

    计划

     

    20

    ·        Estimate

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

     

    20

    Development

    开发

    15*60

    27*60

    ·        Analysis

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

     

    60

    ·        Coding Standard

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

     

    30

    ·        Design

    ·         具体设计

     

    60

    ·        Coding

    ·         具体编码

     

    14.5*60

    ·        Code Review

    ·         代码复审

     

    60

    ·        Test

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

     

    9*60

    Reporting

    报告

     

    6.5*60

    ·         Size Measurement

    ·         计算工作量

     

    10

    ·         Postmortem & Process Improvement Plan

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

     

    20

     

    写博客

     

    6*60

     

     

     

     

     

     

     

     

     

     

     

     

    八、总结:

    (一)实现软件的'模块化'原则:

    • 对功能进行分析,并分解成若干子任务,每个函数只实现一种功能,并将一类功能放到一个类中。通过函数之间的调用来实现所有功能。
    • 避免代码冗杂,提高代码的重用性跟规范性。

    (二)缺点:

    虽然实现了作业的基本要求和附加要求,但关于附加功能的第一条完成得不是很好,虽然不会产生无意义的括号,如 (3*4)*5,但是因为符号的产生是随机的 ,所以很难保证括号的数量。而且,自己的代码还是过于冗杂,还有待提高。

    (三)优点:

    • 除了附加一的一些问题,本作业的其他要求都以实现。
    • 代码书写规范
    • 有详细地注释
    • 虽是一个基本功能,但是我用了三种方法去写(从刚开始最复杂的多重循环(Arithmetic3类中的Arithmetic_test()方法到逻辑更加严谨的算法(Algorithm类中的algorithm()方法再到最后更加简洁的(BracketAlgo类中的bracketsAlgo()算法)。虽然看上去浪费了很多时间,但是这也让我认识到了算法的强大,逐渐进步。

    (四)个人感受

           首先,先谈谈我写这个作业的过程。

           对于这次作业,刚开始我是低估了难度的。我认为只要两天左右的课余时间就可以完成。结果,这次实际花的时间远远超过我预想的。并且,由于刚开始我的不恰当的想法,导致我前面浪费了许多时间。后面又用了一种更加简便的方法去做,成功的实现了基本功能中的所有要求。于是我开始去做附加要求,对于附加要求,刚开始并没有什么想法,于是,我上网查了些资料,看了同学们的一些博客,渐渐的发现附加功能并没有自己想的那么难。可能刚开始写的时候思路比较顺畅,这次附加功能并没有占用我很长时间(敲代码时间的三分之一左右)。最后,就是,写博客啦。写博客对我而言还是挺费时间,大概花了六个小时。终于,个人项目完成啦!

           这次项目,于我而言还挺能难的,也挺费时间的,主要还是自己算法不是很好,不能找到最优解,导致自己浪费了一些时间。通过这次项目,我收获最大的就是互相学习、交流的重要性。如果没有看同学们、看网上的博客,没有跟同学们讨论,我可能还会限制在自己的思路中。还有就是在敲代码前一定要有明确的思路,要不然敲了半天可能会是无用功。这做这个项目过程中,debug也花费了很多时间。  

           虽然这周很忙,最后几天忙到晚上两点多,电脑没电了才睡觉。但是我很喜欢这种专注于一件事的感觉,以前没事的时候会看看剧,聊聊天,但是最近这几天,有时间就是敲代码,有时走在路上也会想怎么更好的实现功能,之间的逻辑是什么。在项目最终完成时,很激动也很有满足感。我想,这就是软件工程的魅力吧。

           最后,依旧一句话结尾。也依旧是  越努力、越幸运!

  • 相关阅读:
    面试官是如何筛选简历?
    成为一名架构师得学习哪些知识?
    一个对话让你明白架构师是做什么的?
    教你一招用 IDE 编程提升效率的骚操作!
    80个让你笑爆肚皮的程序员段子,不好笑算我输!
    Java初学者最佳的学习方法以及会遇到的坑(内含学习资料)!
    作为程序员的你,一年看几本技术相关的书
    MEF 插件式开发之 DotNetCore 中强大的 DI
    MEF 插件式开发之 DotNetCore 初体验
    读 《CSharp Coding Guidelines》有感
  • 原文地址:https://www.cnblogs.com/chenf640/p/8630329.html
Copyright © 2011-2022 走看看