coding.net源码仓库地址:https://git.coding.net/day_light/szysmaster1.git

一、需求分析

    (一)题目:尝试按照《构建之法》第2章中2.3所述PSP流程,使用JAVA编程语言,独立完成一个3到5个运算符的四则运算练习的命令行软件  开发。软件基本功能要求如下:

  • 程序可接收一个输入参数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

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

(二)分析

1.使用random()产生3~5个随机数来做运算符,即产生4~6个随机数来做运算数。

2.由于小学生运算不能产生负数、整数且除数不能为0,解决方案:当出现上述情况时,重新产生随机数。

3.运算结果的计算实现:边产生随机数边计算,不断更新sum。

4.支持括号运算。

5.部分真分数

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

二、功能设计

     (一)基本功能:随机产生n道加减乘除(分别使用符号+-*÷来表示)练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间

     (二)扩展功能:支持括号运算、真分数运算

三、设计实现:设计包括你会有哪些类,这些类分别负责什么功能,他们之间的关系怎样?你会设计哪些重要的函数,关键的函数是否需要画出流程图?函数之间的逻辑关系如何?

 (一)共包含两个类文件,Main为主函数,负责输出到result.txt文件;Lib是辅助类,compute是支持带括号的整数加减乘除运算,fraction是负责真分数加减运算;max求最大公约数。

 (二)调用关系如图所示

四、算法详解

(一)主函数

 1 public class Main {
 2     public static void main(String[] args) {
 3         int n = 0 ;
 4         try 
 5         {
 6             n=Integer.parseInt(args[0]);
 7         }
 8         catch (Exception e) 
 9         {
10             System.out.println("非法字符,请输入1~1000内的整数:");
11         }
12         try {
13             PrintStream ps = new PrintStream("../result.txt");
14             System.setOut(ps);
15         }catch(Exception e) {
16             System.out.println("文件创建失败!");
17         }
18         System.out.println("2016012020");
19         Lib.compute(n);//整数运算
20         Lib.fraction(n);//真分数运算    
21     }
22 }

(二)整数计算使用边生成,边计算的方式,每一次运算均更新sum并输出arr1 = "" + oper[s1] + "" + b1;以下为核心代码,完整代码见coding.net

 1 for (int i = 1; i < th; i++) {
 2 
 3                 int s1 = random.nextInt(5);
 4                 int b1 = random.nextInt(100);
 5                 a = sum;  //更新sum
 6                 if (oper[s1] == ' ') {
 7                     s1++;
 8                 }
 9                 if (oper[s1] == '-') {
10                     while (a - b1 < 0) {
11                         b1 = random.nextInt(100);
12                     }
13                     sum = a - b1;
14                 }
15                 if (oper[s1] == '/') {
16                     if (b1 == 0)
17                         b1++;
18                     while (a % b1 != 0) {
19                         b1 = random.nextInt(99) + 1;
20                     }
21                     sum = a / b1;
22                 }
23                 if (oper[s1] == '+')
24                     sum = a + b1;
25                 if (oper[s1] == '*')
26                     sum = a * b1;
27                 String arr1 = "";
28                 arr1 = "" + oper[s1] + "" + b1;

(三)使用fraction类方法实现真分数出题实现:生成四个随机数,分别表示分子、分母;当分子大于分母时(即假分数出现时),交换分子分母,当分子分母有公因数时,调用max方法实现化简,当中间的计算结果出现假分数时,重新出题。

 

 1 //真分数运算
 2     static public void fraction(int n) { // a为分子1,b为分子2
 3         for (int j = 0; j < n; j++) {
 4             Random rand = new Random();
 5             int a = rand.nextInt(10) + 1;
 6             int Fm1 = rand.nextInt(10) + 1;// 分母1
 7             if (a > Fm1) {
 8                 int t = a;
 9                 a = Fm1;
10                 Fm1 = t;
11             }
12             char[] oper = { '+', '-' };
13             int s = rand.nextInt(2);
14             int b = rand.nextInt(10) + 1;
15             int Fm2 = rand.nextInt(10) + 1;// 分母2
16             if (b > Fm2) {
17                 int t = b;
18                 b = Fm2;
19                 Fm2 = t;
20             } // 化简
21             int ha = a / max(a, Fm1);
22             int hFm1 = Fm1 / max(a, Fm1);
23             int hb = b / max(b, Fm2);
24             int hFm2 = Fm2 / max(b, Fm2);
25             if (oper[s] == '+') {
26                 a = a * Fm2 + b * Fm1;
27                 int F = Fm1 * Fm2;
28                 if (a > F) {
29                     a = rand.nextInt(6) + 1;
30                     Fm1 = rand.nextInt(6) + 1;// 分母1
31                 }
32                 a = a / max(a, F);
33                 Fm1 = F / max(a, F);
34             }
35             if (oper[s] == '-') {
36                 a = a * Fm2 - b * Fm1;
37                 int F = Fm1 * Fm2;
38                 if (a > F || a < 0) {
39                     a = rand.nextInt(10) + 1;
40                     Fm1 = rand.nextInt(10) + 1;// 分母1
41                 }
42                 a = a / max(a, F);
43                 Fm1 = F / max(a, F);
44             }
45             System.out.print(ha + "/" + hFm1 + oper[s] + b + "/" + Fm2);
46             int th = (int) (Math.random() * 2) + 3;// 3~5个运算符
47             for (int i = 1; i < th; i++) {
48                 Random random = new Random();
49                 int s1 = random.nextInt(2);
50                 int b1 = random.nextInt(10) + 1;
51                 int Fmt = random.nextInt(10) + 1;// 分母2
52                 if (a > Fm1) {
53                     int t = a;
54                     a = Fm1;
55                     Fm1 = t;
56                 }
57                 if (b1 > Fmt) {
58                     int t = b1;
59                     b1 = Fmt;
60                     Fmt = t;
61                 } // 化简
62                 int a1 = a / max(a, Fm1);
63                 int Fm11 = Fm1 / max(a, Fm1);
64                 int hb1 = b1 / max(b1, Fmt);
65                 int hFmt = Fmt/ max(b1, Fmt);
66                 if (oper[s1] == '+') {
67 
68                     a = a * Fmt + b * Fm1;
69                     int F = Fm1 * Fmt;
70 
71                     if (a > F) {
72                         a = rand.nextInt(10) + 1;
73                         Fm1 = rand.nextInt(10) + 1;// 分母1
74                     }
75                     a = a / max(a, F);
76                     Fm1 = F / max(a, F);
77                 }
78                 if (oper[s1] == '-') {
79 
80                     a = a * Fmt - b * Fm1;
81                     int F = Fm1 * Fmt;
82                     if (a > F || a < 0) {
83                         a = rand.nextInt(10) + 1;
84                         Fm1 = rand.nextInt(10) + 1;// 分母1
85                     }
86                     a = a / max(a, F);
87                     Fm1 = F / max(a, F);
88                 }
89                 String arr1 = "";
90                 if (a < Fm1 && a >= 0) {
91                     arr1 = oper[s1] + "" + hb1 + "/" + hFmt;
92                     System.out.print(arr1);
93                 }
94             }
95             System.out.println("=");
96             // System.out.println("=" + a + "/" + Fm1);
97         }
98     }

 

五、测试运行

  (一)命令行测试:

        

 

    (二)输出到result.txt文件

            

(三)生成文件位置

六、比较独特的的代码片段

  括号优先级的判定

 1      char[] oper = { '+', '-', ' ', '*', '/' };
 2                 if (i == 1) {
 3                     k = s;
 4                     if (s1 - k >= 2) {
 5                         System.out.print(")" + arr1);
 6                     } else {
 7                         System.out.print(arr1);
 8                     }
 9                 }
10 
11                 if (i != 1) {
12                     if (s1 - k >= 2) {
13                         System.out.print(")" + arr1);
14                     } else {
15                         System.out.print(arr1);
16                     }
17                     k = s1;
18                 }

七、总结:你设计的程序如何实现软件设计的'模块化'原则。

        1.整个项目分为两个源文件,Main和Lib辅助类,实现了整体的模块化。

        2.在Lib辅助类中调用了fractoin和caculate方法,在fraction方法中使用了max函数,求最大公约数,实现了辅助类里的模块化。

采用模块化编程,方便调试,当运行报错时,可以分别测试每一个模块;还有利于移植,当编程时需要实现相同或相似的功能,可以只做小部分改动,减小了代码的冗余度。

八、展示PSP

 

任务内容

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

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

Planning

计划

8

6

·        Estimate

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

3天

4天

Development

开发

82

88

·        Analysis

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

30

45

·        Design Spec

·         生成设计文档

5

8

·        Design Review

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

4

6

·        Coding Standard

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

10

15

·        Design

·         具体设计

10

30

·        Coding

·         具体编码

180

240

·        Code Review

·         代码复审

8

20

·        Test

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

60

120

Reporting

报告

9

6

·         Test Report

·         测试报告

3

2

·         Size Measurement

·         计算工作量

2

1

·         Postmortem & Process Improvement Plan

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

10

10

九、总结

    因为之前没有进行过单元测试,所以总结了自己在进行单元测试时遇到的问题。

 (一)找不到或无法加载主类

  查阅网上资料出现此种情况,有两类原因:

  1.环境配置

  (1)检验方法:输出java、javac、java -version

  2.在你在eclipse写的时候里面会有package,把它删掉就可以了(我属于这种情况)

   PS:同时要注意编译的java源文件有没有包含Main函数

 (二)当源文件不止一个时,所有源文件要一起编译,即javac *.java

十、反思与不足 

  在编程时有时会为了加快编程进度,使用的方法不够简洁高级,忽略了代码的质量,导致后期功能扩展时很困难,有时觉得自己省了时间,实际上到了要实现后期功能时举步维艰,反而延长了整体编程的时间。

   在扩展功能上,实现了”)“而非”()“;未能成功输出真分数的计算结果。

十一、参考博客

【1】初学者利用git 上传代码到Coding的简单操作步骤

【2】错误提示:fatal: remote origin already exists.

【3】解决提交到github报错Please tell me who you are

【4】coding.net使用指南

posted on 2018-03-24 19:29  时&光  阅读(342)  评论(6编辑  收藏  举报