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


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

     

    Coding.net原码仓库地址:https://git.coding.net/Ai_Code/Work.git

     

     

     目录:

    一、需求分析

    二、功能设计

    三、设计实现

    四、算法详解

    五、测试运行

    六、代码

    七、总结

    八、PSP

    九、不足


    一、需求分析:

    (一)功能需求

    1、基本功能:

    程序可接收一个输入参数n,然后随机产生n道加减乘除练习题。

    2、扩展功能

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

    支持真分数的出题与运算。

    (二)非功能需求

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

    2、所出的练习题在运算过程中不得出现负数与非整数,比如3÷5+2=2.6,2-5+10=7等是不合法的。

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

    4、真分数只需要涵盖加减法

    5、支持运算时分数的自动化简,且计算过程中与结果都须为真分数。

    6、格式要求如下:

    当程序接收的参数为4时,以下为一个输出文件示例。

    2018010203

    13+17-1=29

    11*15-5=160

    3+10+4-16=1

    15÷5+3-2=4

    (三)设计需求

    1、只能使用Java语言。

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

    3、使用的JDK版本为 jdk8u161。

    4、使用的JRE版本为jre8u161。

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

    6、时间限制:15天。

    二、功能设计:

    (一)基本功能

    1、能生成文件,假如文件生成有误,会报错,会有提示。为了方便用户的查找错误和使用。

    2、输入的保证是数字,如果不是数字,会有提示,并且可以重新输入。为了不用重新启动程序,方便输入。

    3、输入一个参数n,然后随机产生n道加减乘除算术题。保证加减乘除四个运算符的相对平衡,出现的次数相对均等。尽量能出现连除,连减的算术题。且保证在算数过程中,不出现负数,和小数。

    4、在没仔细看要求之前,我打算生成一个窗口,同学可以输入答案,并且可以进行判断正误,然后给出结果。

    (二)扩展功能

    1、在生成括号的过程中,打算随机生成括号,并且保证括号的合法性。比如(3*8)+5=29;  6+(7)*8=62;  (2*3+4)=10; 等式子是不合法的。

    2、在生成分数的过程中,保证生成真分数,并且化成最简的。

    3、在计算真分数的过程中,保证过程中不会出现假分数和负数。因为没有乘除运算,所以不用考虑优先级,可以边生成边运算。且保证结果是最简真分数。

    三、设计实现

    在设计实现中,我把总的程序分成三个模块:两个函数和一个主函数。便于实现功能,减少工作量。

    (一)优先级类

    功能:此类是一个带参的有返回值的类,返回的是一个整数(int)。

    目的:通过返回来的int的大小,从而来判断符号的优先级。

    关系:此类是一个内部类,可以直接调用使用。

    此类较简单,未画流程图。

    (二)gcd 类

    功能:此类是一个带参的有返回值的类,返回的是一个整数,此整数是两个数的最大公因数。

    目的:此类通过辗转相除法计算两个数的最大公因数,为了生成最简真分数和化简最终结果。

    关系:此类还是一个内部类,可以直接调用。

    流程图

    (三)两个函数相互独立。

    四、算法详解

    (一)文件生成

    要求:能生成文件,假如文件生成有误,会报错,会有提示。

    要完成这个功能,需要使用PrintStream类,为了生成的txt 文件需在项目的根目录下,则需要直接使用"result.txt",不加任何路径。

    1 try {
    2     PrintStream ps = new PrintStream("../result.txt");//生成文件
    3     System.setOut(ps);
    4 }catch(Exception e) {
    5     System.out.println("文件生成错误");//提示
    6 }

    (二)输入整数

    要求:输入的保证是数字,如果不是数字,会有提示,并且可以重新输入。

    要实现这个功能,需要使用Integer.parseInt(args[0]);语句,在命令行中输入,如果有错误会有提示

    1 try 
    2 {
    3     n=Integer.parseInt(args[0]);//命令行输入
    4     if(n<=0)System.out.println("输入的不是正整数,请重新输入!");
    5 }
    6 catch (Exception e) 
    7 {
    8     System.out.println("输入的不是正整数,请重新输入!");
    9 }

     运行结果如下:

    (三)随机数的使用

    要求:保证加减乘除四个运算符的相对平衡,出现的次数相对均等,不出现负数,和小数。需要使用“数组+随机数”。

    程序过程是:一个数组中存储有('+','-','*','/'),然后随机生成一个0-3的数,从而运算符可以随机生成;当a%b≠0时,会进入循环,重新生成a,b,直到整除为止。负数的处理与之类似。

     1 char[] arr= {'+','-','*','÷'};
     2 int temp=rand.nextInt(4);
    3 charArr=arr[temp]; 4
    5 int a0=rand.nextInt(100);//数字范围 0-99 6 int a1=rand.nextInt(100); 7 while(a0%a1!=0)//为了保证整除 8 { 9 a0=rand.nextInt(100); 10 a1=rand.nextInt(99)+1;//为了保证不出现0 11 } 12 while(a0<a1)//保证不出现负数 13 { 14 a0=rand.nextInt(100); 15 a1=rand.nextInt(100); 16 }

    如果不能整除或者a0-a1<0,则会重新生成随机数。

    (四)保证括号的合法性

    为了不生成(3*8)+5=29;  6+(7)*8=62;  (2*3+4)=10;此类括号。我们需要对优先级进行判断,如果前者优先级低于后者,则会生成括号。比如6-4*2;因为后者优先级高于前者,所以会生成括号,即(6-4)*2;

     1 if(panduan(charArr)<panduan(charArr2))//优先级判断
     2 {
     3     if(charArr2=='÷')
     4     {
     5         if(b0==0)b0++;
     6         while(sum%b0!=0)//如果不能整除 重新生成随机数
     7         {
     8             b0=rand.nextInt(99)+1;
     9         }
    10         sum=sum/b0;//计算
    11     }
    12     if(charArr2=='*')sum=sum*b0;
    13     brr="("+brr+")"+""+charArr2+""+b0;//满足条件 生成括号
    14 }

    【注释】panduan()是一个内部类,用来判断符号优先级。

    (五)panduan——优先级类的实现

    1 public static int panduan(char c)//判断优先级
    2 {
    3     if(c=='(')return 0;
    4     if(c=='+'||c=='-')return 1;
    5     if(c=='*'||c=='÷')return 2;
    6     return -1;
    7 }

    (六)最大公因数——gcd类

    要求:在生成分数的过程中,保证生成真分数,并且化成最简的。需要使用辗转相除法求最大公因数,然后分子分母同除以最大公因数化简。保证是真分数的代码和保证非负数的代码类似,就不写出来了。(辗转相除法就是,当a%b==0时,则b就是最大公因数,证明略)。

     1 public static int gcd(int x,int y)//求最大公因数
     2 {
     3     while(true)
     4     {
     5         if(x%y==0)return y;
     6         int temp=y;
     7         y=x%y;
     8         x=temp;
     9     }
    10 }

    (七)符号的多样性

    题目要求:每道题的符号数至少2个,实现这个算法比较简单,思路就是如果一道题中所有的符号都一样,那么则题目重新生成

    1     ......
    2     if (charArr != charArr2)//如果和前一个符号不相同,则标记为1.此式子合法,生成此式子
    3         flag3 = 1;
    4     charArr = charArr2;
    5 }
    6 if (flag3 == 1)
    7     System.out.println(brr + "=" + sum);
    

     五、测试运行

     

    六、代码

    整数运算

    在计算值得过程中,用到了栈的思想。但是我的思路主要还是,边生成边运算。即生成完毕后,结果就直接出来了。首先保证第一个数和第二个数能够整除或者相减大于0。如果是6-4,当下一个字符的优先级高于当前优先级时,即6-4*2,则会生成括号。保证在计算过程中不出现负数,即为(6-4)*2。在生成*2之前会用sum记录下当前过程值,即sum=6-4;然后和下一个运算符进行运算,即sum=sum*2。当生成完毕之后,结果也就出来了。

     1 for(int i=1;i<charCoun;i++)
     2 {
     3     int temp1=rand.nextInt(4);
     4     char charArr2=arr[temp1];
     5     int b0=rand.nextInt(100);
     6     if(panduan(charArr)<panduan(charArr2))//优先级判断
     7     {
     8         if(charArr2=='÷')
     9         {
    10             if(b0==0)b0++;
    11             while(sum%b0!=0)//如果不能整除 重新生成随机数
    12             {
    13                 b0=rand.nextInt(99)+1;
    14             }
    15             sum=sum/b0;//计算
    16         }
    17         if(charArr2=='*')sum=sum*b0;
    18         brr="("+brr+")"+""+charArr2+""+b0;//满足条件 生成括号
    19     }
    20     else
    21     {
    22         if(charArr2=='÷')
    23         {
    24             if(b0==0)b0++;
    25             while(sum%b0!=0)//同上 保证整除
    26             {
    27                 b0=rand.nextInt(99)+1;
    28             }
    29             sum=sum/b0;//计算
    30         }
    31         if(charArr2=='-')
    32         {
    33             while(sum<b0)//同上保证大于0
    34             {
    35                 b0=rand.nextInt(100);
    36             }
    37             sum=sum-b0;
    38         }
    39         if(charArr2=='+')sum=sum+b0;//计算
    40         if(charArr2=='*')sum=sum*b0;//计算
    41         brr=brr+""+charArr2+""+b0;
    42     }
    43     charArr=charArr2;
    44 }

     

    真分数的运算

     

     1 for(int i=1;i<charCoun1;i++)
     2 {
     3     temp1=rand.nextInt(2);
     4     charArr=arr1[temp1];
     5     int num2x=rand.nextInt(20);
     6     int num2y=rand.nextInt(19)+1;//同上
     7     while(num2x>=num2y)
     8     {
     9         num2x=rand.nextInt(20);
    10         num2y=rand.nextInt(19)+1;//分母不能大于0
    11         g=gcd(num2x,num2y);
    12         num2x/=g;
    13         num2y/=g;
    14     }
    15     if(charArr=='-')
    16     {
    17         while(sumx*num2y-sumy*num2x<0)//相减之后,如果小于0,重新生成
    18         {
    19             num2x=rand.nextInt(20);
    20             num2y=rand.nextInt(19)+1;
    21             g=gcd(num2x,num2y);
    22             num2x/=g;
    23             num2y/=g;
    24         }
    25         sumx=sumx*num2y-sumy*num2x;//计算 分子
    26         sumy=sumy*num2y;//计算分母
    27     }
    28     if(charArr=='+')
    29     {
    30         while(sumx*num2y+sumy*num2x>sumy*num2y)
    31         {
    32             num2x=rand.nextInt(20);
    33             num2y=rand.nextInt(19)+1;
    34             g=gcd(num2x,num2y);
    35             num2x/=g;
    36             num2y/=g;
    37         }
    38         sumx=sumx*num2y+sumy*num2x;//同上
    39         sumy=sumy*num2y;
    40     }
    41     brr2=brr2+""+charArr+""+num2x+"/"+num2y;//生成式子
    42 }
    43 g=gcd(sumx,sumy);
    44 if(sumx==0)System.out.println(brr2+"="+sumx);
    45 else System.out.println(brr2+"="+sumx/g+"/"+sumy/g);
    46         

     

    生成括号

     1 if(panduan(charArr)<panduan(charArr2))//优先级判断
     2 {
     3     if(charArr2=='÷')
     4     {
     5         if(b0==0)b0++;
     6         while(sum%b0!=0)//如果不能整除 重新生成随机数
     7         {
     8             b0=rand.nextInt(99)+1;
     9         }
    10         sum=sum/b0;
    11     }
    12     if(charArr2=='*')sum=sum*b0;
    13     brr="("+brr+")"+""+charArr2+""+b0;//满足条件 生成括号
    14 }

    七、总结

    1、对任务进行逐步分解和细化,分成若干个子任务,每个子任务只完成部分完整功能,并且可以通过函数来实现;比如此四则运算中的panduan类和gcd类。通过生成两个内部类,使程序模块化,来简化代码。最后在主函数中进行调用实现。

    2、降低耦合,控制了程序设计的复杂性,提高了代码的重用性。但是由于个人编程习惯问题,仍有一些功能没有进行模块化。之后我会对博客和代码进行更新。

    3、此程序最大的难点在于,生成运算式;仅仅生成运算式很简单,如果加上不能出现负数和小数等限制条件后,度就大大增加了。因为我们无法保证是否能整除,我们可以通过重新生成,保证整除;但是不一定保证没有负数,虽然可以重新生成随机数,使其大于0,但是你又不能保证是否可以整除了。所以这一点有点难。

    4、有的同学会说,我先可以生成,如果满足条件再让其输出。这样的话,你很难保证字符均衡。意思就是说。你生成的算数式中,多以'+','*'为主,因为能整除的概率实在太小了。

    5、还有一种方法,就是限制条件。就是让'-','/'等运算符不能连续出现。这种方法的缺点在于:生成的式子不能多元化了,比较单一。

    6、括号的生成也是一个难点,一是我们要括号的生成随机化,二是我们要生成的括号合法化。很难保证两者都很完美。

    7、真分数,这个比较简单。因为他只需要进行加减运算,所以在保证合法的情况下,可以边生成边运算,直接得到结果。

    8、整数的计算也是一个难点。需要用到栈的思想,和优先级的判断,如果在C++中,它直接有栈的容器,比较简单。(java不太清楚)

    八、PSP

    PSP

    任务内容

    计划时间(min)

    完成时间(min)

    Planning

    计划

    3

    3

         Estimate

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

    3

    3

    Development

    开发

    150

    310

        Analysis

        需求分析

    10

    15

        Design Spec

        生成文档

    0

    0

        Design Review

        设计复审

    0

    0

        Coding Standard

        代码规范

    5

    5

        Design

        具体设计

    30

    50

        Coding

        具体编码

    90

    60

        Code Review

        代码复审

    0

    0

        Test

        测试

    15

    180

    Reporting

    报告

    123

    213

        Test Report

        测试报告

    0

    0

        Size Measurement

        计算工作量

    3

    3

       Postmortem& ProcessImprovement Plan

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

    120

    210

    1、因为没有生成文件等一系列过程,导致在具体设计和代码编写的时候花了大量时间。尤其是测试,一直出现bug,调bug花了我大量时间。不是不能保证整除,就是出现负数。有时候还报除0异常,当时就要崩溃了。。。。

    2、因为是个人项目,所以感觉自己能看懂就行,不用管其他人,所以一些过程就直接略过了。在以后团队工作中,我会认真完成各项工作,方便未来的修改。

     九、不足

     此程序的不足之处在于:此程序无法生成这类式子:2+6*3=20。原因在于后者优先级高于前者,在生成过程中会产生(2+6)*3=24 种式子。之后我会继续进行修改和更新,谢谢大家观看!(求赞)。

     

  • 相关阅读:
    [BAT]用BAT自作开机后自动启动截屏软件
    [TFS]如何彻底删除TFS上的团队项目
    [GIT]如何删除Git本地仓库
    [SQL] update select 查询的结果集
    [VS]反编译_DllToC#_REFLECTOR8.5
    Docker容器开机自动启动
    公告:开通csdn博客,敬请关注!
    1018 Public Bike Management
    微信红包算法
    LRU Cache
  • 原文地址:https://www.cnblogs.com/xia520/p/8615109.html
Copyright © 2020-2023  润新知