2019OO第一单元总结
第一次作业


(你没看错,就一个类。。。)
通过正则表达式处理输入的字符串,提取出每一项的系数和指数,在输出的时候,应当考虑到合并同类项和正项提前的问题,使得最终的输出最短。
我第一次作业的代码超级难看,在互测的时候看了别人的代码之后,自己的代码连我自己都看不下去了。在第一次作业的代码中,我只用了一个主类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第一单元总结的更多相关文章
- 2019OO第一单元作业总结
OO第一单元作业的主题是求导,下面将分三次作业分别总结一下. --------------------------------------------------------------------- ...
- OO第一单元作业小结
前言 第一单元的主题是表达式求导,第一次作业是只带有常数和幂函数的求导,第二次作业加入了正余弦函数,第三次作业又加入了表达式嵌套,难度逐渐提升.总体来说前两次作业还易于应对,而第三次作业做得相对有些艰 ...
- BUAA面向对象设计与构造——第一单元总结
BUAA面向对象设计与构造——第一单元总结 第一阶段:只支持一元多项式的表达式求导 1. 程序结构 由于是第一次接触面向对象的编程,加之题目要求不算复杂,我在第一次作业中并没有很好利用面向对象的特点, ...
- 2019_BUAAOO_第一单元总结
前言 OO第一单元共有三次作业,分别为多项式求导.带有三角函数与幂函数的表达式求导.带有嵌套表达式因子的表达式求导.虽然这三次作业都离不开求导,可是每次作业的复杂度都是大大递增的.对于习惯于面向过程编 ...
- OO第一单元作业总结
oo第一单元的作业是对多项式的求导.下面就是对三次作业分别进行分析. 第一次作业 分析 第一次作业相对来讲比较简单,甚至不用面向对象的思想都能十分轻松的完成(实际上自己就没有使用),包含的内容只有常数 ...
- OO第一单元总结
OO第一单元作业总结 一.前言 开学四周,不知不觉已经做了三次OO作业.事实上,每一次作业对我来说都是很大的挑战,需要花费大量的时间和精力来学习. 虽然学得很艰苦,但最后还是连滚带爬地完成了.(好惨一 ...
- 2019OO第二单元总结
(1)设计策略 电梯第1次作业是一个傻瓜调度电梯,使用先来先服务原则,不用考虑捎带(可以认为电梯的载客量为1),因此比较简单,调度器用一个队列就可以. 使用生产者-消费者模型,输入线程是生产者,电梯是 ...
- OO第一次博客作业--第一单元总结
OO第一单元总结 面向对象设计与构造的第一单元,对“面向对象”的概念还根本不理解不熟悉,只觉得需要“分模块”,但不知道怎么分,分多少模块,怎么根据需要的模块的功能建立类.学习的进度又太慢,根本跟不上出 ...
- OO第一单元总结(表达式求导)
写在前边:第一次接触面向对象语言,编程思想仍然不可避免的有以前面向过程的影子.从第一次作业的完全面向过程,到第二次学会剥离各个类互不影响到第三次作业的先构思面向对象的基本程序架构再编程.虽然程序有些地 ...
随机推荐
- Java并发之Thread类的使用
一.线程的几种状态 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以下这几个状态:创建(new).就绪(runnable).运行(running).阻塞(blocked).time wa ...
- windows的git的安装和配置
下载并安装git(安装过程中采用默认选项) 进入gitbash(gitbash集成了windows和linux的命令) 使用git --version查看是否安装成功: 用vim .gitconfig ...
- Ansible-----条件判断与错误处理
when 在ansible中,条件判断的关键词是when --- - hosts: all remote_user: root tasks: - debug: msg: "System re ...
- ES进阶--02
第11节深度探秘搜索技术_案例实战基于dis_max实现best fields策略进行多字段搜索 课程大纲 1.为帖子数据增加content字段 POST /forum/article/_bulk{ ...
- Codeforces 809E Surprise me! [莫比乌斯反演]
洛谷 Codeforces 非常套路的一道题,很适合我在陷入低谷时提升信心-- 思路 显然我们需要大力推式子. 设\(p_{a_i}=i\),则有 \[ \begin{align*} n(n-1)an ...
- php中echo、print、print_r、var_dump、var_export区别
(1) print和echo是语言结构,echo输出多个值,多个值之间用逗号分隔,无返回值:print只能输出一个值,有返回值.echo和print输出整型和字符串,没法打印布尔型,如果true,打印 ...
- SpringMVC的入门示例---基于注解的配置
注解版的配置,主要的修改就是将原来使用<bean>创建的业务控制器对象,修改为是扫描标签扫描到容器. 1.导入包 2.在 web.xml 配置核心控制器 <?xml version= ...
- vue项目关闭eslint检查
前言 vue项目在用旧版本的vue-cli创建的时候,会询问是否添加eslint的检查, 后来的版本在创建的时候是直接添加了eslint检查. 有时候我们开发习惯不是那么严格的时候, 会不在意这些缩进 ...
- C/C++中const关键字的用法及其与宏常量的比较
1.const关键字的性质 简单来说:const关键字修饰的变量具有常属性. 即它所修饰的变量不能被修改. 2.修饰局部变量 ; ; 这两种写法是等价的,都是表示变量的值不能被改变,需要注意的是,用c ...
- mysql根据分组和条件查询以后如何统计记录的条数
1.子查询,查询出的数据随便起一个别名,然后根据分组和条件查询出的数据,作为一个具有一列的一个表,然后外面的查询查询这个数据表的这一列的总数,即可. SELECT COUNT( * ) FROM ( ...