结对编程项目报告--四则运算CORE

<!doctype html>css

sw_lab2.md

结对编程项目报告--四则运算CORE

第15组:JL17110067 隆晋威 PB16120853 赵瑞html


项目GitHub地址

https://github.com/NiceKingWei/homework2node

PSP

status stages 预估耗时 实际耗时
Accepted make plan 20 min 20 min
Accepted demand analysis 40 min 40 min
Accepted analysis 45 min 90 min
Accepted code 3 hours 5 hours
Accepted test 2 hours 3 hours
Accepted report 1 hours 2 hours
Sum   8 hours 12 hours

项目需求

像《构建之法》的人物阿超那样,写一个能自动生成小学四则运算题目并给出答案的命令行 “软件”, 若是咱们要把这个功能放到不一样的环境中去(例如,命令行,Windows 图形界面程序,网页程序,手机App),就会碰到困难,由于目前代码的广泛问题是代码都散落在main ( )函数或者其余子函数中,咱们很难把这些功能完整地剥离出来,做为一个独立的模块知足不一样的需求。python

API

  1. setting() function:ios

     
        
        
        
        

    就是能够屡次改变设置,在传入参数的时候,max_opearatorsmax_rangeprecision能够传入值或者-1,传值表明更改该设置,-1表明不变。has_fractionhas_real能够传入1,0,-1;1表明开启,0表明没有,-1表明不变。c++

  2. generate函数:git

     
        
        
        
        

    将参数传进去,运行后结果就存在了string* answer里面。github

 

代码逻辑思路

咱们首先定义了 fraction 类,这是分数类,用于符号计算。web

 
  
  
  
  

fraction 类里面重载了各个运算函数,并在每次计算结束以后经过类中的reduction()函数把分数变为最简分数。编程

而后定义了一些工具函数,如输出函数,判断是不是无效值的函数 is_bad_value

 
  
  
  
  

is_bad_value 是一个判断值是不是坏值的函数。坏值在除零异常时可能会出现,在值超出范围的时候也会出现。坏值具备传递性,坏值和任何值运算的结果都是坏值。这种设计方式的灵感来自函数式语言中的 Maybe Monad ,下面放一下fraction operator / (const fraction x) const;做为例子:

 
  
  
  
  

 

接下来定义抽象语法树的结构。

 
  
  
  
  

每个抽象语法树的节点都包含两个字段,一个是 type,一个是 data。type 的类型是一个枚举值,data 是一个 union 联合体。这种作法的灵感也来自函数式语言。在表示抽象语法树时,tagged union 是一种很好的方式。但由于不肯定能不能使用 c++17,因此咱们并无用类型安全的 std::variant ,而是使用了本身定义的tagged union

以后的事情就比较简单了

 
  
  
  
  

这两个函数产生随机值和随机抽象语法树,根据 setting 的规则产生合适的表达式树。

这两个函数的代码:

 
  
  
  
  

 

 
  
  
  
  

calc_asttree 是递归函数,它递归调用自身,计算左子树和右子树的值,而后再计算当前节点的值,若是有一个结点的type是TYPE_DOUBLE,那么返回给上一层的type就是TYPE_DOUBLE

这两个函数的代码

 
  
  
  
  

ast_eval 是调用 calc_asttree 的函数,它先把 hash_code 设为0,而后调用 calc_asttree

calc_asttree 递归计算的过程当中会产生一个操做序列,这个序列能够刻画当前表达式的特征,例如 1+2+3,在计算过程当中产生的序列是 1+2=3, 3+3 =6,3+(2+1) 在计算过程当中产生的序列为 2+1=3,3+3=6。若定义两个序列等价当前仅当序列中每一个算式在交换律意义下等价。能够发现,题目要求的 “重复” 条件与计算序列的等价条件是等价的。所以,咱们能够用计算序列来去重。

但计算序列的储存比较占空间,所以咱们选择了一个哈希函数,对计算序列进行哈希映射。由于两个序列哈希值相同是两个序列重复的必要条件。所以在实际操做中,只须要两个序列哈希函数不一样,则这两个表达式必然不相等。

接下来是表达式输出函数。

 
  
  
  
  

注释中的内容是咱们的计算表达式的 BNF 范式。由语法产生式,咱们能够很容易地写出以上递归函数,并经过函数间的互相调用完成对表达式的输出,这种输出方式不会产生多余的括号。

 
  
  
  
  

generate 函数生成题目和答案。它先调用 random_ast 生成一颗随机语法树,而后对它进行求值,若是结果是坏值,那就从新生成一个。

特别值得一提的是咱们的 main 函数

 
  
  
  
  

它为每一组数据生成了一行 python 代码,是一句断言。只要断言成立,这组数据就是正确的。只须要简单改改更改参数,咱们就能够得到不少组数据,并能经过脚本进行自动测试。

 
  
  
  
  

发布前,咱们组一共测试了 500万 组数据,均没有出错。

BUG记录

出现了错误的计算结果:

  1. bug缘由:咱们俩搞错了乘方和乘法的运算优先级,
  2. 这个不太容易避免,出错了时候咱们还疑问到底该先算乘方仍是从左到右乘
  3. 大概四十分钟,找到错误样例,研究错误样例就能够了,发现了是逻辑错误,那么改代码就能够了。

第二次出现了错误的结果:

  1. bug缘由:分数运算的中间结果分子溢出了long long的范围
  2. 这个bug是在写函数时候错误的估计了可能用到的范围,没有增强函数的鲁棒性。
  3. 调试方法:用错误样例逐步测试,观察中间结果。
  4. 这种鲁棒性的东西,该加仍是加上,尽可能不要假设前提。

结对编程与我的做业差别

最初,隆晋威同窗扮演驾驶员角色,赵瑞同窗扮演领航员角色。

在完成整个程序的框架后,分工完成模块细节和测试,互相作驾驶员和领航员,在整个程序写完后,一块儿测试这个程序,并debug。

一我的用git很随意,但是两我的的话,就要提早看一下队友的修改。

我的见解

结对编程过程当中,两我的的做息一致性很重要,在刚写完程序的时候,不出意外出了错误结果,咱们开始debug,主要的debug任务是在凌晨完成的。debug到晚上十二点,1000组数据跑对了,后来加到10000又出错了,咱们又debug到1点,10000没问题的时候,当时已经凌晨两点了,若是两我的有一个不习惯熬夜的话,这还真有点不舒服了,还好我俩都很不养生。

两我的的debug的速度果真不是1+1=2的简单加法,速度比一我的debug要快得多。

还有就是一块儿工做在有进展的时候两我的会一块儿以为很开心,分享一下喜悦,比一我的有进展本身心里爽一下还happy,好比亮点debug完咱们觉得大功告成了就很开心(然而次日加大测试量又出现了新的错误样例)。

结对编程过程当中学习的速度时迅速的,这一次结对编程我向隆晋威同窗学到了不少,好比代码规范,GitHub的使用和visual studio code的使用,还有用脚原本测试程序。

会选择结对编程用于解决部分任务。

工做时刻

1523806766472

代码

 
  
  
  
  
相关文章
相关标签/搜索