第一次作业

(你没看错,就一个类。。。)

通过正则表达式处理输入的字符串,提取出每一项的系数和指数,在输出的时候,应当考虑到合并同类项和正项提前的问题,使得最终的输出最短。

我第一次作业的代码超级难看,在互测的时候看了别人的代码之后,自己的代码连我自己都看不下去了。在第一次作业的代码中,我只用了一个主类Main,在主方法中用大正则识别表达式、判断合法性、求导,毫无对象概念,根本没有体现出面向对象的特性,同样也在互测环节中被查出来很多bug。所以在第二次作业中,我决定使用面向对象的思想,对代码进行一次彻底的重构。

公测没有查出bug,但是在互测环节被hack惨了。

最主要的问题就是输入x-x或者123这类求导结果为0的公式没有输出的问题,其次还有特殊字符、正则爆栈的问题,其中第一个问题是最明显的问题。这是因为我在写程序的时候没有模块化的概念,完完全全是面向过程式的写法,导致自己的程序很不清晰。在自己写完代码、通过弱侧之后,应当自己编写测试点并测试,而我显然是因为没做好在本地机器上测试的工作,才会出现这么明显的bug。

第二次作业

与第一次作业类似,在输入完公式之后进行化简,使得每一项都是t*x^a*sin(x)^b*cos(x)^c的形式,然后进行求导,最后再合并同类项,把正项提前输出。但是,应当注意+++123是一个合法的公式,可以看作第一个加号是项的符号,第二个加号是"1*"的省略,第三个加号是123的符号,应当特殊处理一下。

我使用了4个类:Main主类;Exp公式类,由很多Term通过加法构成;Term项类,由很多Factor通过乘法构成;Factor因子类,里面有一个枚举变量,用于区分这是什么类型的因子。

公测还是没查出bug,但是在互测环节被别人查出来了。

这一次的bug明显比第一次少了,但是还有bug,在公式末尾为+或-的时候,会产生异常(由于str.indexOf(i)越界了)。

第三次作业

由于这次作业需要支持函数嵌套,因此在第二次作业的基础上,进行了大量的改造。

我使用了5个类:Main主类;Exp公式类,由很多Term通过加法构成;Term项类,由很多Nest通过乘法构成;Nest类,是很多Func的嵌套,还包含了exp代表嵌套在最里层的公式;Func函数类,由第二次作业的Factor改造而成,把常数看作常值函数,仍然用枚举变量的方式区分不同的函数。

对于Exp公式类的求导,就是对其中的Term求导然后相加;对于Term的求导,通过乘法的求导法则,最终返回一个Exp;对于Nest的求导,通过链式法则,最终返回一个Term。

同样地,公测还是全AC,互测被查出来了bug,在Nest最后如果是sin(x) ^ +2这样,^和指数的符号中间有空格的时候会出现问题,是因为我在空格的地方没有处理好。

总结

通过观察这三次作业的UML图和Class Metrics表,可以看出第二、三次作业相比第一次作业的进步很大(第一次作业我就不说什么了),这三次作业的bug全是出现在表中标红的地方,在接下来的程序中,我应当改进程序的逻辑,使得程序质量得到提高,逻辑更加清晰。

互测发现别人bug的策略

我用PowerShell写了一个自动测试的脚本,用Python写了一个表达式求导的程序和判断两个公式是否相等的程序(都是用的Sympy库),在第三次作业中查出了别人求导结果错误的地方。

test.ps1内容如下

$rootPath=$(pwd).Path
$name="sympy","archer","assassin","berserker","caster","lancer","rider","saber"
$entrance="","Main","Main","Main","Main","Main","Main","Main" # 把这里稍微改一下,因为有些人主类不是Main
$ans=0..7
for(;;) {
   cd $rootPath
   $str=Read-Host
   if($str -eq "init") {
       for($i=1;$i -le 7;$i++) {
           echo "Compiling $($name[$i])"
           cd "$rootPath\$($name[$i])\src"
           javac -encoding utf-8 (dir . -recurse -name *.java)
           echo ""
       }
       echo "finish"
       continue
   } elseif($str -eq "exit") {
       exit
   }

   echo "***$($name[0])***:"
   $ans[0]=(echo $str|python $rootPath\ans.py)
   echo $ans[0]
   echo ""

   for($i=1;$i -le 7;$i++) {
       echo "$($name[$i]):"
       cd "$rootPath\$($name[$i])\src"
       $ans[$i]=(echo $str|java $entrance[$i]|Select-Object -First 1)
       echo $ans[$i]
       cd $rootPath
       if($ans[$i] -ne "WRONG FORMAT!") {
           echo $ans[0] $ans[$i]|python check.py
       }
       echo ""
   }
}

ans.py内容如下

from sympy import *
x = Symbol('x')
str = input()
print(diff(str, x))

check.py参考了评测机的评测方式,内容如下

from sympy import *
import random
str1 = input()
str2 = input()
expr1 = simplify(str1)
expr2 = simplify(str2)
flag = true
for i in range(0,100):
   tmp = random.uniform(-10,10)
   r1 = expr1.evalf(subs={'x':tmp})
   r2 = expr2.evalf(subs={'x':tmp})
   if abs(r1-r2) > 0.0001:
       flag = false
       break
if flag == true:
   print("AC")
else:
   print("WA")

重构和改进的措施

对于第一次作业而言,我可以使用Exp公式类和Term项类,而不是我原来的完全面向过程的方式,使得自己在编程的时候不容易出现bug。

第二次作业和第三次作业完全可以使用继承的方式,而不是使用枚举变量,这样可以让我的程序看起来更清晰,更能体现面向对象的思想。

对于第二次作业而言,我可以使用sin(x)^2+cos(x)^2=1这个恒等式,对求导结果进行化简,使得输出长度更短。

对于第三次作业而言,我可以把含有0的Term删除,把所有最终为常数的Nest乘在一起,可以让最终结果更短。

这三次作业的bug都出现在程序特别”面向过程“的部分,我应当对其进行改造。

2019OO第一单元总结的更多相关文章

  1. 2019OO第一单元作业总结

    OO第一单元作业的主题是求导,下面将分三次作业分别总结一下. --------------------------------------------------------------------- ...

  2. OO第一单元作业小结

    前言 第一单元的主题是表达式求导,第一次作业是只带有常数和幂函数的求导,第二次作业加入了正余弦函数,第三次作业又加入了表达式嵌套,难度逐渐提升.总体来说前两次作业还易于应对,而第三次作业做得相对有些艰 ...

  3. BUAA面向对象设计与构造——第一单元总结

    BUAA面向对象设计与构造——第一单元总结 第一阶段:只支持一元多项式的表达式求导 1. 程序结构 由于是第一次接触面向对象的编程,加之题目要求不算复杂,我在第一次作业中并没有很好利用面向对象的特点, ...

  4. 2019_BUAAOO_第一单元总结

    前言 OO第一单元共有三次作业,分别为多项式求导.带有三角函数与幂函数的表达式求导.带有嵌套表达式因子的表达式求导.虽然这三次作业都离不开求导,可是每次作业的复杂度都是大大递增的.对于习惯于面向过程编 ...

  5. OO第一单元作业总结

    oo第一单元的作业是对多项式的求导.下面就是对三次作业分别进行分析. 第一次作业 分析 第一次作业相对来讲比较简单,甚至不用面向对象的思想都能十分轻松的完成(实际上自己就没有使用),包含的内容只有常数 ...

  6. OO第一单元总结

    OO第一单元作业总结 一.前言 开学四周,不知不觉已经做了三次OO作业.事实上,每一次作业对我来说都是很大的挑战,需要花费大量的时间和精力来学习. 虽然学得很艰苦,但最后还是连滚带爬地完成了.(好惨一 ...

  7. 2019OO第二单元总结

    (1)设计策略 电梯第1次作业是一个傻瓜调度电梯,使用先来先服务原则,不用考虑捎带(可以认为电梯的载客量为1),因此比较简单,调度器用一个队列就可以. 使用生产者-消费者模型,输入线程是生产者,电梯是 ...

  8. OO第一次博客作业--第一单元总结

    OO第一单元总结 面向对象设计与构造的第一单元,对“面向对象”的概念还根本不理解不熟悉,只觉得需要“分模块”,但不知道怎么分,分多少模块,怎么根据需要的模块的功能建立类.学习的进度又太慢,根本跟不上出 ...

  9. OO第一单元总结(表达式求导)

    写在前边:第一次接触面向对象语言,编程思想仍然不可避免的有以前面向过程的影子.从第一次作业的完全面向过程,到第二次学会剥离各个类互不影响到第三次作业的先构思面向对象的基本程序架构再编程.虽然程序有些地 ...

随机推荐

  1. java和数据库中日期类型的常见用法

    (1)java中日期类型:Date.Timestamp(2)数据库中:Date.Timestamp(3)字符串和Date之间的格式化转换:    SimpleDateFormat类方法: format ...

  2. PCA,到底在做什么

    很久以前写过一篇 PCA 的小白教程,不过由于当时对 PCA 的理解流于表面,所以只是介绍了一下 PCA 的算法流程.今天在数图课上偶然听到 PCA 在图像压缩上的应用,突然明白了一点实质性的东西,这 ...

  3. 【原创】大叔问题定位分享(17)spark查orc格式数据偶尔报错NullPointerException

    spark查orc格式的数据有时会报这个错 Caused by: java.lang.NullPointerException at org.apache.hadoop.hive.ql.io.orc. ...

  4. django中sqlite迁移mysql

    sqlite数据迁移 1 数据备份 django中打开terminalpython manage.py dumpdata authorization > authorization_data.j ...

  5. 详解HTTPS、TLS、SSL

    HTTPS.TLS.SSL HTTP也称作HTTP over TLS.TLS的前身是SSL,TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3.下 ...

  6. 使用Java方式连接HDFS

    IDEA中新建Maven工程,添加POM依赖, 在IDE的提示中, 点击 Import Changes 等待自动下载完成相关的依赖包. <?xml version="1.0" ...

  7. TensorFlow的Bazel构建文件结构

    目录 说明 分析 全局设定文件:$TF_ROOT/WORKSPACE 外部依赖项入口:tensorflow/workspace.bzl 看看有多少package? 本来是想理解一下TF源码编译过程的, ...

  8. 【Android】setXfermode属性

    1.下面的Xfermode子类可以改变这种行为: AvoidXfermode  指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图). PixelXorXfermode  当覆盖 ...

  9. Imcash科普:没有网络也可以转账比特币?你可能有些误解

    近日,据Bitcoinist消息,比特币解决方案开发商CoinKite联合创始人Rodolfo Novak和OpenBazaar联合创始人Sam Patterson在推特上宣布,两人不借助互联网和卫星 ...

  10. 基于for循环的呼吸灯

    #include "stm32f10x.h" #include "stm32f10x_gpio.h" //#include "led.h" ...