新程序包下载(密码:4kp6)

>>>>>直接上代码,问题出在随机分数的生成上,确实出现了一些非常鱼唇的错误,不过已经提交了就没办法了,在这里发出来仅供参考吧:

修改前:

 public static Fraction nextFrac(int width, Random seed)
{
Random rd = seed;
int down1 = (int)(rd.NextDouble() * (width - ) + );//随机生成低于width的分母
int quo1 = (int)(rd.NextDouble() * (width - ) + );//随机生成低于width-1的带分数整数部分
long up1 = (long)(rd.NextDouble() * (width - ) + );//随机生成低于width的分子 up1 += quo1*down1;
return new Fraction(up1, down1);
}

修改后:

 public static Fraction nextFrac(int width, Random seed)
{
Random rd = seed;
int down1 = (int)(rd.NextDouble() * (width - ) + );//随机生成低于width的分母
long up1 = (long)(rd.NextDouble() * (width *down1-) + );//随机生成低于分母*width的分子 return new Fraction(up1, down1);
}

对于随机数元素的生成范围,第一次要求作业中有如下规定:

使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如

Myapp.exe -r 10

将生成10以内(不包括10)的四则运算题目

对于我之前的处理方法,即 分数 = 整数[1,width-1)+ 分子[1,width)/分母[1,width)

其值域实际上为[1,2*width-2),而且导致生成的分数至少大于1,实际上少了很多种情况...............................................

特别的,当width取2时,由于width-2=0,随机数失去意义,这样取值范围就固定变成了[1,2],这就与老师在课程要求上的说明冲突了;

同理可得:

 int down1 = (int)(rd.NextDouble() * (width - ) + );
long up1 = (long)(rd.NextDouble() * (width *width-) + );

这样的处理方式也是存在问题的,值域实际上变成了[1,width^2)

值得说明的一点是,仍然保留了random*(width-1)+1这一设定,以规避分母或分子为0的情况,主要是为了减少无意义操作数(0)的出现频率和规避一些不合法情况


程序设计过程中出现的其他Bug汇总:

1.  当范围较大,读取表达式计算结果时,容易出现分子超int范围的情况,笔者在之前的博客中已经提到过,为了支持足够的范围,需要采用Long整型存储分子分母,因为计算过程中可能出现超int范围的分子分母结果,因此相应的,读取答案的时候,我们也要采用Int64.Parse来录入结果,并用相应的Long型变量存储,而非常用的Int32.Parse(感谢乾麻提醒)

2.  求最大公约数,也即约分的方法一定要考虑传入参数含0的情况,以及,需要考虑,对于公约数为0的情况,约分时应当怎样处理,是否需要报异常等

3.  对于计算模块,自栈顶向下逐步运算时(从中缀表达式的角度来看就是从右往左算),一定要考虑前一个操作符是否为“-”号,对于没有添加括号的情况,盲目按序运算会导致错误 如 (3-2-1),当计算完一个括号内的值后,需要取前一个运算符判断是否为×或÷,因为在这两个符号后面跟括号的情况下,其运算会被延后,一旦其后所跟的括号内式子得出结果,该运算应当被首先考虑。

需要注意的是,如果不对每个生成的子表达式加上括号,其实际运算优先顺序可能与表达式建立过程不符。 如e=>e1÷e2=>e3÷e4÷e2=>3÷2÷1 (减法同)

非常建议生成一些不加括号,运算符也多于3的中缀表达式,对于检查计算模块的正确性很有帮助

例如:6×5+8÷(3-2) ; 

213'3/5 - 65×(3+5-(2)-4)

为了批量检查计算模块的正确性,可以使用excel,这里分享一下具体的用法:

S1:

我们需要对程序做一点点扩展,使其通过命令行的控制,能够输出同时被excel和计算模块解析的式子

也即:将生成带分数全部转为假分数形式,并括起来(避免除法过程的二义性)

笔者做法如下:

 class user {
...
public static bool mixed = false;
...
class program {
...
if (args[i] == "-m")
{
user.mixed = true;//命令行参数控制是否以假分数形式输出
}
...
ExerciseWriter.Write((j + ).ToString() + ". \0\t" + expStr.getExpStr() + "\r\n");
AnswerWriter.Write((j + ).ToString() + ". \0\t" + answer1 + "\r\n");//输出制表符,这样直接粘到Excel里会变成两列,表达式和序号就直接分离了 class Fraction { public String express()
...
long quo = up / down;
long res = up % down;
String s = "";
if (user.mixed) return (s = "(" + up + "/" + down + ")");
else ...//正常输出
...

需要注意的是,因为有制表符的存在,所以读取式子用replace去除空白符应当用“\\s+”匹配而不是空格“ ”

S2

将式子粘到excel里,会发现自动分成两列了(比如A、B两列吧),然后我们用excel自带的查找替换工具,将B列表达式出现的×÷替换为*/;

在C列输入 =”=“&B1,并拖动格式手柄应用到其余行(如果数字太大,就拖滚动条到表格底部,用shift选中底部到头部的所有单元格,按ctrl+d即可)

再按ctrl+c复制,粘贴选择左上角粘贴选项里的 ”粘贴数值——值“,使用查找替换工具,将”=“替换为”=“,所有表达式的值就悉数计算出来了;

S3

采用同样的办法把答案复制到D、E列,并用同样的办法求其值(答案实际上多为分数,可以看成一个简单表达式),用S2的办法求其值;

再在F列中计算C列,E列两列值之差并用sum求和,如sum为0,则基本可以确保程序的计算模块已经完全没有问题了

4.  在用Dictionary<String Answer ,List<String> usedCase>这一数据结构时发现索键求值的过程存在很多数据错误,经过仔细的检查,发现问题在于将List对象Add到Dictionary里的时候,直接传引用作为值放进去了,因为笔者的程序设计的时候,只有一个usedCase随表达式生成函数传入,clear,add,传出,那么无疑所有键的键值都是这一个List,它被修改的话相应的Dictionary里的所有键键值就会被修改,所以实际上作为value传入的时候是需要通过拷贝构造的,至于中间出现的数据混乱情况,可能是在修改这一模块时只修改了一部分所致吧。

5.  计算表达式时,为了避免栈空取值的情况,需要时刻关注栈的容量,但有一个简洁的办法可以改善性能,那就是预置栈底元素(比如#之类的作为标记),这样只需访问栈中的一个值而不是全部

6.  对于负分数的表示形式,应规范成仅分子为负或仅整数部分为负(读入78/-4,转为-20'1/2或-39/2),假分数转换成带分数的时候,因为分子由取余操作产生,其值可能为负,这种情况下,需要手动让分子加上分母的值,然后整数部分-1来简约形式,避免-5’-39/78这种情况的产生,恰恰因为我们的项目要求里对减法做了约定来规避负数的产生,这一点才不容易被发觉,试着生成一些负分数的String表示形式,或者让分子,分母,整数部分取0,看看会有怎样的结果

7.  养成好习惯,随手关门,随手close

Ps:如果输入文件路径无效试着转绝对地址吧,方法为System.IO.Path.GetFullPath(YourAddress),另外输出文件时需统一编码(再次感谢乾麻提醒),如:

StreamWriter GradeWrite = new StreamWriter(Grade, System.Text.Encoding.Unicode);

8.   通过Opnum和OpLim控制表达式的推导生成过程,显然,当Opnum = 0的时候应规避 e=>n的文法规则,当Opnum = OpLim时应规避二元式的生成,并在当前表达式已经被括号括起来的情况下,规避e=>(e)的文法规则来避免括号冗余,以避免增加计算模块负担

9.  一个比较常见的情况是生成表达式的时候,明明用了random却出现了大规模的重复情况,这是因为random生成随机数是基于当前系统时间的,由此生成一个伪随机序列,如果程序执行的效率高,同时又有多个random对象被新建用于生成随机数的话就会出现重复,对于这样的情况,最好的办法是全程只用一个random对象,让其作为随机种子传入即可

10.  暂时只注意到这么多,有新的会补充

【补充】第一次个人项目出现的bug的更多相关文章

  1. AndroidStudio第一次提交项目代码到git服务器/github

    虽然使用AndroidStudio(以下简称as)开发并使用git管理代码已经有很长时间,但是第一次提交项目到git依然会很不顺利,网上的文章或许因为所使用版本比较老,并不一定完全凑效,因此写此笔记做 ...

  2. Linux环境下第一次提交项目

    Linux环境下第一次提交项目: vi 日记 新增一个文件名为“日记”的文件 git status 工作区的状态 git add 日记 建立跟踪 git commit 提交变更 ----------- ...

  3. THE BUG 队第一次团队项目作业

    队名: THE BUG 队 2.队员学号: 杨梓琦 3118005115(队长) 温海源,3118005109 陈杰才,3118005089 李华,3118005097 钟明康,3118005123 ...

  4. [2017BUAA软工]第一次个人项目 数独的生成与求解

    零.Github链接 https://github.com/xxr5566833/sudo 一.PSP表格 PSP2.1 Personal Software Process Stages 预估耗时(分 ...

  5. vue项目开发遇见bug

    1.附件的点击问题,与原生交互的问题: 原生的调用对象和vue的调用对象不同,注意原生方法的位置. 2.10.2以下fetch请求数据的问题(检查是否可以使用 can i use) 10.2以下ios ...

  6. 吸取教训:一段网上找的代码突然爆了,项目出现大BUG

    本人是做游戏服务器开发的,碰到一个需求,给符某些要求的玩家的发送道具奖励,奖励的数量根据离线的天数计算. 这个需求实现起来很简单,只需要在玩家上线的时候计算上次离线时间和当前时间间隔的天数,然后根据策 ...

  7. maven第一次创建项目太慢解决方法

    问题: 第一次用maven创建项目的时候,因为本地仓库中没有jar包,需要从中央仓库下载,所以会比较慢 解决方法: 因为从中央仓库下载默认使用的国外的镜像下载,速度比较慢,我们可以把镜像修改为从阿里云 ...

  8. 第一次react-native项目实践要点总结

    今天完成了我的第一个react-native项目的封包,当然其间各种环境各种坑,同时,成就感也是满满的.这里总结一下使用react-native的一些入门级重要点(不涉及环境).注意:阅读需要语法基础 ...

  9. 软件工程第一次个人项目——词频统计by11061153柴泽华

    一.预计工程设计时间 明确要求: 15min: 查阅资料: 1h: 学习C++基础知识与特性: 4-5h: 主函数编写及输入输出部分: 0.5h: 文件的遍历: 1h: 编写两种模式的词频统计函数: ...

随机推荐

  1. Linux系统如何让显示中文?英文centos切换中文

    登陆centos图形界面之后,找到如下图位置 system---- add/remove software也就是类似windows的添加删除程序\软件   由于添加删除组件需要管理员权限,如果是roo ...

  2. 【PAT】B1052 卖个萌(20 分)

    实在不想写这个题,好费劲,头疼,这是粘的柳婼的代码 ,等我有空再自己用c写吧 #include <iostream> #include <vector> using names ...

  3. LInux下(centos7.2)更新 python3.7

    进入超级管理员目录  su root 下载 wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz 找到下载的文件解压  tar - ...

  4. ccf题库中2015年12月2号消除类游戏

    题目如下: 问题描述 消除类游戏是深受大众欢迎的一种游戏,游戏在一个包含有n行m列的游戏棋盘上进行,棋盘的每一行每一列的方格上放着一个有颜色的棋子,当一行或一列上有连续三个或更多的相同颜色的棋子时,这 ...

  5. android:layout_margin真实含义 及 自己定义复合控件 layout()运行无效的问题解决

    一.关于layout_margin 搞Android时间也不短了.对layout_margin也不陌生了,可近期遇到一个问题让我发现,对它的认识还不够深入全面.大量网络资料上都说,layout_mar ...

  6. php递归无限级

    function getTree($data, $pId) { $tree = ''; foreach($data as $k => $v) { if($v['cate_ParentId'] = ...

  7. oracle 查询归档增长量

    set linesize 200set pagesize 100column day format a15 heading 'Day'column d_0 format a3 heading '00' ...

  8. Android学习之基础知识五—ListView控件(最常用和最难用的控件)

    ListView控件允许用户通过上下滑动来将屏幕外的数据拉到屏幕内,把屏幕内的数据拉到屏幕外. 一.ListView的简单用法第一步:先创建一个ListViewTest项目,在activity_mia ...

  9. Android学习之基础知识四-Activity活动8讲(活动的灵活运用)

    一.判断当前是在哪个活动 1.我们还是接着上一讲的代码,首先创建一个Java类:BaseActivity.java.这个类我们不作为一个活动,也不在AndroidManifest.xml中注册,它只是 ...

  10. Python 爬取 11 万 Java 程序员信息竟有这些重大发现!

    一提到程序猿,我们的脑子里就会出现这样的画面: 或者这样的画面: 心头萦绕的字眼是:秃头.猝死.眼镜.黑白 T 恤.钢铁直男-- 而真实的程序猿们,是每天要和无数数据,以及数十种编程语言打交道.上能手 ...