新程序包下载(密码: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. January 07th, 2018 Week 01st Sunday

    To remember is to disengage from the present. 铭记过去就是放弃当下. To remember the past doesn't mean we would ...

  2. vue-cli 打包后显示favicon.ico小图标

    第一步:favicon.ico小图标放在static里面 第二步:index.html 文件中引入时需要写 ./ 相对路径 第三部:npm run build 打包 打包完成就可以看到 favicon ...

  3. C#中删除集合中符合条件的元素以及需注意属相

    如果用foreach,会造成被遍历的集合更改后带来异常问题. 此时,用for循环可有效的解决这个问题. for(int i=0;i<List.Count;i++) { if(条件是真) { Li ...

  4. Web应用程序使用说明

    目录 Web应用程序使用说明 1.组织权限概述 a)概述 b)组织权限设置 2.门户的使用 门户-栏目门户配置 3.安全策略功能使用说明 一.概述 二.安全策略设置 Web应用程序使用说明 1.    ...

  5. mocha测试框架-truffle

    https://mochajs.org/
学习网址:
https://www.jianshu.com/p/9c78548caffa
https://www.jb51.net/article/10646 ...

  6. day15 Python全局变量和局部变量

    在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量. 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序. 当全局变量与局部变量同名时: 在定义局部变量的子程序内,局部变 ...

  7. centos7 rpm 安装mysql

    1.wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.22-1.el7.x86_64.rpm-bundle.tar 2.tar ...

  8. 解决VC++6.0打开文件或添加文件到工程出错的问题

    相信很多朋友在安装VC++6.0之后,发现无法使用打开文件命令.同时,打开了工程,却无法实现文件添加到工程的问题.一旦进行如此操作,便会出现应用程序错误,需要关闭应用程序.为此,不胜其烦.更有甚者,以 ...

  9. 新版本grafana添加数据源报错!

    前提: grafana配置的数据源url没有错误. 现象: 1)升级完grafana之后发现原来配置的open-facon数据源无效了,一直提示HTTP ERROR NOT FOUND. 2)安装新版 ...

  10. P4111 [HEOI2015]小Z的房间

    你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子.在一开始的时候,相邻的格子之间都有墙隔着.你想要打通一些相邻房间的墙,使得所有房间能够互相到达.在此过程中,你不能把 ...