20175212童皓桢 结对编程项目-四则运算 第二周

需求分析

  • 实现一个命令行程序,要求自动生成小学四则运算题目(加减乘除)

  • 支持多运算符

  • 测试结果的正确性,用户输入错误时给出正解

  • 实现真分数运算

  • 在不需要真分数运算时,将结果整除

  • 统计题目正确率

  • 生成题目输出到文件

  • 从文件写入

设计思路

  • 首先要能够按照按人的一般习惯,生成自左向右计算的加减乘除算式。
  • 随机生成多运算符,并随机生成相对应个数的整数
  • 利用eval方法直接计算随机生成的算式的值,并和用户的输入作比较
  • 将人计算真分数时的通分,约分方法描述成机器语言
  • 在不需要真分数运算时,将结果整除
  • 判断正确率
  • 生成题目至文件
  • 设计测试类,利用JUnit测试各情况下的的四则运算

UML类图

输入图片说明

关键代码

  • 如何生成符合要求格式的运算式
for (i = 0; i < n; i++) {
            int a = random.nextInt(5) + 1;//1-5个运算符
            int[] number = new int[a + 1];//创建一个number数组
            String ex = new String();
            for (int j = 0; j <= a; j++) {//生产a+1个数字,即2-6个数字
                number[j] = random.nextInt(100) + 1;//生成1-100的整数
            }
            for (int j = 0; j < a; j++) {
                int s = random.nextInt(4);//随机生成运算符下标
                ex += String.valueOf(number[j]) + String.valueOf(op[s]);//添加一对数字和运算符

            }
            ex += String.valueOf(number[a]);//在尾端补上一个数字
            System.out.println(ex + "=");
  • 如何验证用户输入答案的正误
int ua = reader.nextInt();//用户输入答案

            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine se1 = manager.getEngineByName("js");
            ScriptEngine se2 = manager.getEngineByName("js");
            String str=ex+"="+"="+ua;//将用户答案逻辑式放在字符串str中
            Boolean result =(Boolean)se1.eval(str);//用eval方法计算用户答案逻辑式
            String ca="="+se2.eval(ex);//生成correct_answer字符串存正确答案
            jud.judgeFormula(result,ca);


  • 如何进行真分数的加减乘运算
if(s==2){//计算真分数乘法运算
                int nu[]=new int[2];
                nu[0]=num[0]*num[2];
                nu[1]=num[1]*num[3];
                ca=ex+f.yuefen(nu[0],nu[1]);//将计算结果约分
            }
            else if(s==0){//计算真分数加法运算
                int nu_1[]=new int[2];
                nu_1[0]= num[0]*num[3]+num[1]*num[2];
                nu_1[1]= num[1]*num[3];
                ca=ex+f.yuefen(nu_1[0],nu_1[1]);
            }
            else {//计算真分数减法运算
                int nu_2[]=new int[2];
                nu_2[0]= num[0]*num[3]-num[1]*num[2];
                nu_2[1]= num[1]*num[3];
                if(nu_2[0]<0){//分子为负数时
                    nu_2[0]=-nu_2[0];//取反
                    ca=ex+"-"+f.yuefen(nu_2[0],nu_2[1]);//加上负号
                }
                else
                    ca=ex+f.yuefen(nu_2[0],nu_2[1]);
            }

  • 如何对分数计算结果进行约分
 public String yuefen(int m,int n){//分数约分
        FundCalculate f=new FundCalculate();
        int temp=f.gcd(m,n);
        m/=temp;
        n/=temp;
        String ca=String.valueOf(m)+"/"+String.valueOf(n);
        return ca;
    }

  • 如何在非真分数情况下构造算式整除
 public int decide(int x,int y){//判断是否整除
        Random random=new Random();
        if(x%y!=0){
            y=random.nextInt(100)+1;
            return decide(x,y);
        }
        else{
            return y;
        }
    }

 for (int j = 0; j < a; j++) {
                    switch(flag){
                        case 0:
                            s[0]= random.nextInt(4);//随机生成运算符下标
                            ex += String.valueOf(number[j]) + String.valueOf(op[s[0]]);//添加一对数字和运算符
                            if(s[0]==3){number[j+1]=f.decide(number[j],number[j+1]);}
                            break;
                        case 1:
                            s[1]= random.nextInt(4);//随机生成运算符下标
                            ex+="("+String.valueOf(number[j]) + String.valueOf(op[s[1]]);//添加左括号和数字和运算符
                            if(s[1]==3){number[j+1]=f.decide(number[j],number[j+1]);}
                            flag++;
                            break;
                        case 2:
                            s[2]=random.nextInt(4);
                            ex+=String.valueOf(number[j]) + ")"+String.valueOf(op[s[2]]);//添加右括号和数字和运算符
                            if(s[2]==3){
                                switch(s[1]){//区分之前括号里运算结果对后面数取整
                                    case 0:
                                        number[j+1]=f.decide(number[j]+number[j-1],number[j+1]);
                                        break;
                                    case 1:
                                        number[j+1]=f.decide(number[j]-number[j-1],number[j+1]);
                                        break;
                                    case 2:
                                        number[j+1]=f.decide(number[j]*number[j-1],number[j+1]);
                                        break;
                                    case 3:
                                        number[j+1]=f.decide(number[j]/number[j-1],number[j+1]);
                                        break;
                                    default:;
                                }
                            }
  • 如何在文件中输入输出
import java.io.*;

public class WAndRFile {
    String ua=new String();//用户答案
    public void writeToFile(String str){
        File fw=new File("practice.txt");//写入的文件
        try{
            Writer out=new FileWriter(fw);//指向目的地输出流
            BufferedWriter bw=new BufferedWriter(out);
            bw.write(str);//写入字符串str
            bw.newLine();//换行
            bw.close();//高级流关闭
            out.close();//关闭底层流
        }
        catch (IOException e){
            e.printStackTrace();
        }
    }
    public String readFromFile(){
        File fr=new File("practice.txt");//读取的文件
        try{
            Reader in=new FileReader(fr);//指向源的输入流
            BufferedReader br=new BufferedReader(in);
            while (br.readLine()!=null)
                ua=br.readLine();
            br.close();
            in.close();;
        }
        catch (IOException e){
            e.printStackTrace();
        }
        return ua;
    }
}

Junit测试

输入图片说明

输入图片说明

运行结果截图

  • 含真分数
    输入图片说明

  • 不含真分数

输入图片说明

  • 输出到文件

输入图片说明

代码托管地址

https://gitee.com/thz666/20175212_tong_haozhen/tree/master/src/四则运算

遇到的困难及解决办法

  • 问题一:真分数计算时,当结果为负数,输入的答案和“正确答案”时常不符,如输入-4/3,“正确答案”为4/-3.
  • 解决方法一:
if(nu_2[0]<0){//分子为负数时
                    nu_2[0]=-nu_2[0];//取反
                    ca=ex+"-"+f.yuefen(nu_2[0],nu_2[1]);//加上负号
                }

重新构造答案结构,使其符合数学标准

  • 问题二:真分数答案没有约分
  • 解决办法:
Boolean result=ua.equals(ca);
            jud.judgeFormula(result,ca);

将上述代码放在循环体中

  • 问题三:非真分数计算时会出现8位及以上小数
  • 解决办法三:事先判断是否整除,如
public int decide(int x,int y){//判断是否整除
        Random random=new Random();
        if(x%y!=0){
            y=random.nextInt(100)+1;
            return decide(x,y);
        }
        else{
            return y;
        }
    }

结对总评及评价

  • 结对学习对于编而言的确是一个很好的方法。因特殊方法的原因,我们的程序编写过程中遇到了许多各式各样的问题,大部分还是超出了知识能力范围,需要我们摸索研究。很难想象没有这样一个好的结对伙伴,这个程序的实现将会有多大的难度!
  • 最后,我希望并且有信心,通过两个人的结对将Java学习的热情和储备提升一个新的台阶。

结对照片

输入图片说明

PSP

PSP Personal Software Process Stages 预估耗时 实际耗时
Planning 计划 30min 20min
Estimate 估计这个任务需要多少时间 10min 10min
Development 开发 10min 10min
Analysis 需求分析 (包括学习新技术) 40min 30min
Coding Standard 代码规范 (为目前的开发制定合适的规范) 5min 10min
Design 具体设计 1h 1h
Coding 具体编码 3h 4h
· Code Review 代码复审 30min 30min
Test · 测试(自我测试,修改代码,提交修改) 1h 1h
Test Report 测试报告 30min 30min
Size Measurement 计算工作量 10min 10min
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 30min 30min
合计 7h35min 8h50min

参考和引用

posted on 2019-04-13 14:57  20175212thz  阅读(152)  评论(0编辑  收藏  举报