Java实现小学四则运算练习

 Github项目地址:https://github.com/feser-xuan/Arithmetic.git
1、需求分析
   软件基本功能要求如下:
  • 程序可接收一个输入参数n,然后随机产生n道加减乘除练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。
  • 为了让小学生得到充分锻炼,每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3/5+2=2.6,2-5+10=7等算式。
  • 练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt中,不要输出额外信息文件目录与程序目录一致。
  • 当程序接收的参数为4时,以下为输出文件示例。
  • 软件附加功能要求如下:(请有余力的同学完成)
  • 支持有括号的运算式,包括出题与求解正确答案。注意,算式中存在的括号必须大于2个,且不得超过运算符的个数。
  • 扩展程序功能支持真分数的出题与运算,例如:1/6 + 1/8 + 2/3= 23/24。注意在实现本功能时,需支持运算时分数的自动化简,比如 1/2+1/6=2/3,而非4/6。

2、功能分析

  • 使用Java中提供的Random类,随机产生0-100的正整数,并与随机产生的四则运算符号相结合,构成随机的四则运算。
  • 由于小学并没有接触到负整数,故随机计算结果为负的除去。
  • 当产生符合要求的四则运算题目时,计算正确答案并输出到名为result.txt的文件中。

3、设计实现

4、测试运行

5、核心代码

  • 随机生成四则运算表达式:
 1             int[] number_temp = new int[rand.nextInt(2)+3];
 2             String[] str_temp = new String[number_temp.length-1];
 3             for(int i=0;i<number_temp.length;i++)
 4             {
 5                 if(i<number_temp.length-1)
 6                 {
 7                     number_temp[i]=rand.nextInt(100);
 8                     list_temp.add(String.valueOf(number_temp[i]));
 9                     str_temp[i]=operator[rand.nextInt(4)];
10                     list_temp.add(str_temp[i]);
11                     
12                 }
13                 else
14                 {
15                     number_temp[i]=rand.nextInt(100);
16                     list_temp.add(String.valueOf(number_temp[i]));
17                 }
18             }
  • 用调度场算法产生逆波兰式:
public static ArrayList<String> produce_RPN(ArrayList<String> list_temp)
    {
        int t=0,i=0;
        String tmp;
        Tack mytack = new Tack(20);
        ArrayList<String> lt_temp = new ArrayList<String>();
        while(true)
        {
            tmp = list_temp.get(i++);
            if(isInteger(tmp))
            {
                lt_temp.add(tmp);
            }
            else{
                if(mytack.myisempty())
                {
                    mytack.mypush(tmp);
                }
                    
                
                else{
                    if(isCPriority(tmp, mytack.mypeek()))
                        mytack.mypush(tmp);
                    else{
                        lt_temp.add(mytack.mypop());
                        mytack.mypush(tmp);
                    }
                    
                }
            }
            if(i>=list_temp.size())
            {
                while(!mytack.myisempty())
                    lt_temp.add(mytack.mypop());
                System.out.println(transform_string(list_temp));
                list_temp = lt_temp;
                System.out.println(list_temp);
                return list_temp;
            }
        }
        
        
    }
  • 用逆波兰式,计算表达式的结果:
public static int calculate_RPN(ArrayList<String> list_temp)
    {
        int i=0,t;
        double a=0,b=0;
        String l_temp;
        Stack sk=new Stack(20);
        for(t=0;t<list_temp.size();t++)
        {
            l_temp = list_temp.get(i++);
            if(!isInteger(l_temp))
            {
                b = sk.mypop();
                a = sk.mypop();
                switch(l_temp)
                {
                case "+":sk.mypush(a+b);break;
                case "-":sk.mypush(a-b);break;
                case "*":sk.mypush(a*b);break;
                case "/":
                    if(b==0)
                        return -1;
                    sk.mypush(a/b);break;
                }
                System.out.println("st.mytop: "+sk.mypeek());
            }
            else{
                sk.mypush((double)Integer.parseInt(l_temp));
            }
            
        }
        if(!sk.myisempty())
        {
            a = sk.mypop();
            b = a-(int)a;
            System.out.println("a:  "+a);
            if(a>0 && b==0 )
            {
                return (int)a;
            }
            else
                return -1;
        }
        else
            return -1;
        
    }
  • 当计算结果为正整数时,添加到数组list。反之则重复上述步骤:
       count=calculate_RPN(produce_RPN(list_temp));
            if(count !=-1)
            {
                list_temp.add(" = "+count);
                list.add(transform_string(list_temp));
                number_n--;
                list_temp.clear();
            }
            else
                list_temp.clear();
  • 当产生适当符合要求的表达式时,现将自己的学号、姓名写到result.txt文件中,再将产生的表达式写到result.txt文件中:
try {
        outSTr = new FileOutputStream(file1);
        Buff = new BufferedOutputStream(outSTr);
            try {
                Buff.write("201571030104  丁炜轩".getBytes());
                Buff.write("
".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < list.size(); i++) 
            {
                try {
                    Buff.write(list.get(i).getBytes());
                    Buff.write("
".getBytes());
                } catch (IOException e) {
                    e.printStackTrace();
                    i--;
                }
            }
        Buff.flush();
        Buff.close();
        
        } catch (IOException e) {
            e.printStackTrace();
        }
        //Buff.close();
        try {
            outSTr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
       
        for (int i = 0; i < list.size(); i++) 
        {
            System.out.print(list.get(i));
            System.out.println();
        }
        System.out.print("计算完毕!");
  • 到这时候,result.txt文件中已经就有了我们需要的四则运算表达式,以及正确的结果。
  • 还有几个小的函数,这里简单说一下:
  • 1.判断字符串是否为正整数:
public static boolean isInteger(String str) {    
        for (int i = str.length();--i>=0;){  
                    if (!Character.isDigit(str.charAt(i))){
                        return false;
                    }
                }
                return true;
      } 
  • 2.判断运算符号的优先级顺序:
public static boolean isCPriority(String str,String s) { 
        if((str+s).equals("*+") || (str+s).equals("*-") || (str+s).equals("/+") || (str+s).equals("/-"))
            return true;
        else
            return false;    
      }
  • 3.将动态数组转换为字符串类型:
public static String transform_string(ArrayList<String> list_temp)
    {
        String s="";
        for(int i=0;i<list_temp.size();i++)
        {
            s+=list_temp.get(i);
        }
        return s;
        
    }
  • 在本次实验中,重要用到了栈:
  •  
     static class Stack
        {
            int mytop;
            double stk[];
            
            public Stack(int num) {
                mytop=-1;
                stk=new double[num];
            }
            /*出栈*/
            double mypop()
            {
                double peek=stk[mytop];
                mytop--;
                return peek;
            }
            /*入栈*/
            void mypush(double x)
            {
                mytop++;
                stk[mytop]=x;
                
            }
            /*判空*/
            Boolean myisempty()
            {
                if(mytop==-1)
                    return true;
                else
                    return false;
            }
            /*取栈顶元素*/
            double mypeek()
            {
                double peek=stk[mytop];
                return peek;
            }
            /*栈大小*/
            int mysize()
            {
                return mytop+1;
            }
        }
        
        static class Tack
        {
            int mytop;
            String tk[];
            
            public Tack(int num) {
                mytop=-1;
                tk=new String[num];
            }
            /*出栈*/
            String mypop()
            {
                String peek=tk[mytop];
                mytop--;
                return peek;
            }
            /*入栈*/
            void mypush(String x)
            {
                mytop++;
                tk[mytop]=x;
                
            }
            /*判空*/
            Boolean myisempty()
            {
                if(mytop==-1)
                    return true;
                else
                    return false;
            }
            /*取栈顶元素*/
            String mypeek()
            {
                String peek=tk[mytop];
                return peek;
            }
            /*栈大小*/
            int mysize()
            {
                return mytop+1;
            }
        }

 6、总结

   在本次实验中,主要在代码完成、调试中花了很多时间。我感觉一方面由于长时间不使用Java语言编写程序,对于Java语法结构、类的定义、函数的构造等知识方面都严重匮乏。一方面还是对于软件工程这门课理解略有偏差。不过在老师,以及助教老师的共同帮助下,我学到了一些书本上学不到的知识。值此,由衷的感谢老师们对于我的鼓励、帮助、以及肯定,我会继续发挥自己的长处,弥补自己不足的地方,为了祖国美好的明天,让我们共同努力!

PSP2.1

任务内容

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

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

Planning

计划

30

46

·       Estimate

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

30

46

Development

开发

160

200

··       Analysis

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

20

20

·       Design Spec

·  生成设计文档

15

20

·       Design Review

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

5

10

·       Coding Standard

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

20

20

·       Design

  具体设计

30

30

·       Coding

  具体编码

60

80

·       Code Review

·  代码复审

5

10

·       Test

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

5

10

Reporting

报告

60

80

··       Test Report

·  测试报告

30

40

·       Size Measurement

  计算工作量

15

20

·       Postmortem & Process Improvement Plan

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

15

20

原文地址:https://www.cnblogs.com/dwxuan/p/8613291.html