结对编程项目阶段性进展
第一阶段目标 - 能把计算的功能封装起来,通过测试程序和API 接口测试其简单的加法功能。
因为原本的设计,就设计了计算器类,将其封装好了,所以直接跳过了第一阶段。
第二阶段目标 - 通过测试程序和API 接口测试其简单的加减乘除功能。并能看到代码覆盖率。
可以从图中看出,正负小数,正负分数等结果的计算正确性
而计算器类的使用也非常方便,如下代码
Calculator cal("1+1"); //初始化计算器类 cal.recalculator("1+1"); //可重复调用的计算函数 cal.run(); //计算结果 cal.getMyResult(); //获得计算结果,为string类型
第三阶段目标 - 通过测试程序和API 接口测试对于各种参数的支持。并能看到代码覆盖率。
第三阶段中加入了三个辅助计算的参数,故对此修改计算器类,此部分代码还添加了出错处理,后续部分会说明,添加代码如下:
public: MyError setDateRange(int type){ //设置数据范围 if(0<type){ daterange=type; return ERROR_NO; } else Error=ERROR_SET; return ERROR_SET; } MyError setMaxUnit(int num){ //设置最大识别数量 if(0<num&&num<=80){ maxunit=num; u=new unit[maxunit]; //清空后缀表达式 this->num=0; return ERROR_NO; } else Error=ERROR_SET; return ERROR_SET; } MyError setAccuracy(int a){ //设置精度 if(a>=-1&&a<=6){ accuracy=a; return ERROR_NO; } else Error=ERROR_SET; return ERROR_SET; } private: //非辅助计算参数,设置后,除非重复设置,否则不会被clear之类的清除 int daterange; //算式参数中数据的范围 int maxunit; //算式参数最多能识别的字符数量 int accuracy; //小数精确位数,-1为不精确,即去掉所有末尾的0,其他数字即小数点后保留的位数
daterange参数,表示计算器类只能计算-daterange到daterange之间的数据,故如果计算结果超出范围,就会报超出范围的错,默认为100000
maxunit参数,代表输入的算式参数最多含有几个字符,超出字符会报非法算式的错误,默认为80
accuracy参数,代表最后输出的计算结果的精度,-1代表原样输出,0-6代表,具体保留几位小数,采取四舍五入。
enum MyError{ERROR_NO=0,ERROR_SET=1,ERROR_OPERATOR=2,ERROR_ZERO=4,ERROR_STRING=8,ERROR_RANGE=16};
新定义的错误枚举类型,包含了所有计算器类会报的错误,并且将原本计算器类中的bool类型的error替换成了MyError类型的Error,里面存储的上一个错误类型,默认为ERROR_NO(没错误)
并且将原先所有返回-1的代码,全部替换成了返回具体错误类型
在程序最开始调用了cal.setDateRange(1); 函数,即设置计算器类只能计算-1到1的数,结果如上图,只有第一题还能计算,余下所有题目会报错,并会显示错误类型,其他错误类型也是如此,就不过多展示了
第四阶段目标 -界面模块,测试模块和核心模块的松耦合。
因为,界面模块的代码还没有写完,所以,第四阶段为下一周的任务,我会和同组的一起攻克这一阶段的目标的
下面是目前所有的代码
1 #include <iostream> 2 using namespace std; 3 #include <string.h> 4 #include <stack> 5 #include <sstream> 6 #include <fstream> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <math.h> 10 11 enum MyError{ERROR_NO=0,ERROR_SET=1,ERROR_OPERATOR=2,ERROR_ZERO=4,ERROR_STRING=8,ERROR_RANGE=16}; 12 13 void printError(MyError me){ 14 if(me==ERROR_NO){ 15 cout<<"没有错误"; 16 } 17 else if(me==ERROR_SET){ 18 cout<<"设置参数非法"; 19 } 20 else if(me==ERROR_OPERATOR){ 21 cout<<"操作符非法"; 22 } 23 else if(me==ERROR_ZERO){ 24 cout<<"除0错误"; 25 } 26 else if(me==ERROR_STRING){ 27 cout<<"算式非法"; 28 } 29 else if(me==ERROR_RANGE){ 30 cout<<"计算结果超出范围"; 31 } 32 else{ 33 cout<<"未定义的错误类型"; 34 } 35 cout<<" 错误代码:"<<me<<endl<<endl; 36 } 37 38 class unit //后缀表达式用,单元类 39 { 40 public: 41 char op; 42 double num; 43 int kind; 44 unit(){ 45 kind=0; 46 } 47 void set(char c){ 48 op=c; 49 kind=1; 50 } 51 void set(double d){ 52 num=d; 53 kind=2; 54 } 55 }; 56 57 class fenshu //分数类 58 { 59 public: 60 int fz; 61 int fm; 62 fenshu(int a,int b){ 63 fz=a;fm=b; 64 yuefen(); 65 } 66 void yuefen(){ 67 if(fz==0) 68 return; 69 int t; 70 int a=fz; 71 int b=fm; 72 if (a < b) { 73 t = a; 74 a = b; 75 b = t; 76 } 77 while (t = a % b) { 78 a = b; 79 b = t; 80 } 81 if(b!=1){ 82 fz/=b; 83 fm/=b; 84 } 85 if(fm<0){ 86 fz=-fz; 87 fm=-fm; 88 } 89 } 90 void print(){ 91 cout<<fz<<"/"<<fm; 92 } 93 string getfenshu(){ 94 char s[20]; 95 if(fm==1){ 96 sprintf(s,"%d",fz); 97 } 98 else{ 99 sprintf(s,"%d/%d",fz,fm); 100 } 101 string ss=s; 102 return ss; 103 } 104 fenshu operator +(fenshu &fs){ 105 fenshu f(fz*fs.fm+fs.fz*fm,fm*fs.fm); 106 f.yuefen(); 107 return f; 108 } 109 fenshu operator -(fenshu &fs){ 110 fenshu f(fz*fs.fm-fs.fz*fm,fm*fs.fm); 111 f.yuefen(); 112 return f; 113 } 114 fenshu operator *(fenshu &fs){ 115 fenshu f(fz*fs.fz,fs.fm*fm); 116 f.yuefen(); 117 return f; 118 } 119 fenshu operator /(fenshu &fs){ 120 if(fs.fz==0){ 121 fenshu f1(0,1); 122 return f1; 123 } 124 fenshu f(fz*fs.fm,fm*fs.fz); 125 f.yuefen(); 126 return f; 127 } 128 void operator =(fenshu &fs){ 129 fz=fs.fz; 130 fm=fs.fm; 131 } 132 bool operator ==(fenshu &fs){ 133 return fz==fs.fz&&fm==fs.fm; 134 } 135 }; 136 137 class Calculator //核心计算器类 138 { 139 public: 140 //辅助计算参数 141 double result; //计算结果 142 fenshu fresult; //分数计算结果 143 MyError Error; //计算过程中是否有错误 144 string str; //存放中缀表达式 145 146 Calculator(string s):fresult(1,1){ //计算器初始化 147 u=new unit; 148 clear(); 149 str=s; 150 accuracy=-1; 151 maxunit=80; 152 daterange=100000; 153 } 154 155 MyError run(){ //计算表达式的值,存入result 156 MyError temperror=zzh(str); 157 if(temperror!=ERROR_NO){ 158 Error=temperror; 159 result=-11111; 160 return Error; 161 } 162 int i; 163 bool b=true; 164 for(i=0;i<str.size();i++){ //没有小数点,就计算分数结果 165 if(str[i]=='.'){ 166 b=false; 167 break; 168 } 169 170 } 171 172 if(b){ 173 temperror=getFResult(); 174 if(temperror!=ERROR_NO){ 175 fenshu f(-1,-1); 176 fresult=f; 177 Error=temperror; 178 return Error; 179 } 180 else if(abs(fresult.fz)>daterange||abs(fresult.fm)>daterange){ 181 Error=ERROR_RANGE; 182 return Error; 183 } 184 } 185 else{ 186 temperror=getResult(); 187 if(temperror!=ERROR_NO){ 188 Error=temperror; 189 result=-11111; 190 return Error; 191 } 192 else if(abs(result)>daterange){ 193 Error=ERROR_RANGE; 194 return Error; 195 } 196 } 197 return ERROR_NO; 198 } 199 200 void clear(){ //清空计算器一切辅助计算参数 201 num=0; 202 Error=ERROR_NO; 203 result=0; 204 fenshu f(1,1); 205 fresult=f; 206 str=""; 207 delete u; 208 u=new unit[maxunit]; 209 } 210 211 void recalculator(string s){ //重启计算器对象 212 clear(); 213 str=s; 214 } 215 216 string getMyResult(){ //获得计算结果,小数结果或者分数结果 217 int i=0; 218 char s[20]; 219 string ss; 220 for(;i<str.size();i++){ 221 if(str[i]=='.'){ 222 if(accuracy!=-1) //判断精度并输出 223 sprintf(s,"%.*lf",accuracy,result); 224 else 225 sprintf(s,"%g",result); 226 ss=s; 227 return ss; 228 } 229 } 230 ss=fresult.getfenshu(); 231 return ss; 232 } 233 234 MyError setDateRange(int type){ //设置数据范围 235 if(0<type){ 236 daterange=type; 237 return ERROR_NO; 238 } 239 else 240 Error=ERROR_SET; 241 return ERROR_SET; 242 } 243 244 MyError setMaxUnit(int num){ //设置最大识别数量 245 if(0<num&&num<=80){ 246 maxunit=num; 247 u=new unit[maxunit]; //清空后缀表达式 248 this->num=0; 249 return ERROR_NO; 250 } 251 else 252 Error=ERROR_SET; 253 return ERROR_SET; 254 } 255 256 MyError setAccuracy(int a){ //设置精度 257 if(a>=-1&&a<=6){ 258 accuracy=a; 259 return ERROR_NO; 260 } 261 else 262 Error=ERROR_SET; 263 return ERROR_SET; 264 } 265 266 private: 267 //非辅助计算参数,设置后,除非重复设置,否则不会被clear之类的清除 268 int daterange; //算式参数中数据的范围 269 int maxunit; //算式参数最多能识别的字符数量 270 int accuracy; //小数精确位数,-1为不精确,即去掉所有末尾的0,其他数字即小数点后保留的位数 271 272 //辅助计算参数 273 unit *u; //存储后缀表达式 274 int num; //后缀表达式unit数量 275 276 MyError zzh(string s){ //中缀表达式转后缀表达式 277 if(s.size()>maxunit){ 278 return ERROR_STRING; //error,传入的算式长度超过设置的最大识别数量 279 } 280 char c; 281 char *temp1=new char[maxunit]; 282 double temp; 283 string stemp; 284 stack<char> st; 285 while(!s.empty()){ //如果字符串不为空则继续循环 286 c=s[0]; 287 if(isoperator(c)){ //是操作符 288 s.erase(0,1); //从string中删除操作符 289 if(pushintostack(c,&st)==ERROR_OPERATOR) 290 return ERROR_OPERATOR; 291 } 292 else if(isnum(c)){ //是数字 293 stringstream sst(s); 294 sst>>temp; 295 sprintf(temp1,"%g",temp); 296 stemp=temp1; 297 s.erase(0,stemp.size()); //从string中删除数字 298 sst.clear(); 299 u[num++].set(temp); //存储数字到栈中 300 } 301 else{ 302 return ERROR_STRING; 303 } 304 } 305 if(pushintostack('#',&st)==ERROR_OPERATOR) 306 return ERROR_OPERATOR; 307 return ERROR_NO; 308 } 309 310 bool isoperator(char c){ //判断是否是操作符 311 if(c=='+') 312 return true; 313 if(c=='-') 314 return true; 315 if(c=='*') 316 return true; 317 if(c=='/') 318 return true; 319 if(c=='(') 320 return true; 321 if(c==')') 322 return true; 323 return false; 324 } 325 326 bool isnum(char c){ 327 if(c>='0'&&c<='9') 328 return true; 329 return false; 330 } 331 332 int youxian(char c1,char c2){ //判断两操作符优先级 333 if(c2=='#') //结束符 334 return 0; 335 if(c2=='(') 336 return 1; 337 if(c2==')') 338 if(c1=='(') 339 return 2; 340 else 341 return 0; 342 if(c1=='(') 343 if(c2=='+'||c2=='-'||c2=='*'||c2=='/') 344 return 1; 345 if(c1=='*'||c1=='/') 346 return 0; 347 if(c1=='+'||c1=='-') 348 if(c2=='*'||c2=='/') 349 return 1; 350 else if(c2=='+'||c2=='-') 351 return 0; 352 return -1; //非法运算符 353 } 354 355 MyError pushintostack(char c,stack<char> *st){ //将操作符执行一系列入栈判断操作 356 char a; 357 int y=0; 358 while(!st->empty()){ 359 a=st->top(); 360 y=youxian(a,c); 361 if(y==0){ //后来的操作符优先级小 362 st->pop(); 363 u[num++].set(a); 364 } 365 else if(y==1){ //后来的操作符优先级大 366 break; 367 } 368 else if(y==2){ //俩操作符是'('和')' 369 st->pop(); 370 return ERROR_NO; 371 } 372 else 373 return ERROR_OPERATOR; 374 } 375 st->push(c); 376 return ERROR_NO; 377 } 378 379 void test(){ //输出后缀表达式,测试用(暂留) 380 int i; 381 cout<<num<<endl; 382 for(i=0;i<num;i++){ 383 if(u[i].kind==1) 384 cout<<u[i].op<<" "; 385 else if(u[i].kind==2) 386 cout<<u[i].num<<" "; 387 } 388 } 389 390 MyError getResult(){ //由run函数调用,获取小数结果,存入result中 391 int i; 392 char op; 393 double num1,num2; 394 stack<double> st; 395 for(i=0;i<num;i++){ //处理后缀表达式 396 if(u[i].kind==2){ //如果是数字则入栈 397 st.push(u[i].num); 398 } 399 else if(u[i].kind==1){ //如果是操作符,则出栈两个数字 400 op=u[i].op; 401 if(st.empty()) 402 return ERROR_STRING; //算式非法 403 num2=st.top(); 404 st.pop(); 405 if(st.empty()) 406 return ERROR_STRING; //算式非法 407 num1=st.top(); 408 st.pop(); 409 switch(op){ 410 case '+': 411 st.push(num1+num2); 412 break; 413 case '-': 414 st.push(num1-num2); 415 break; 416 case '*': 417 st.push(num1*num2); 418 break; 419 case '/': 420 if(num2==0) 421 return ERROR_ZERO; //除0错误 422 st.push(num1/num2); 423 break; 424 } 425 } 426 else 427 return ERROR_STRING; //算式非法 428 } 429 result=st.top(); 430 return ERROR_NO; 431 } 432 433 MyError getFResult(){ //由run函数调用,获取分数结果,存入fresult中 434 int i; 435 char op; 436 fenshu f1(1,1),f2(1,1); 437 stack<fenshu> st; 438 for(i=0;i<num;i++){ 439 if(u[i].kind==2){ //如果是数字则入栈 440 st.push(fenshu(u[i].num,1)); 441 } 442 else if(u[i].kind==1){ //如果是操作符,则出栈两个数字 443 op=u[i].op; 444 if(st.empty()) 445 return ERROR_STRING; //算式非法 446 f2=st.top(); 447 st.pop(); 448 if(st.empty()) 449 return ERROR_STRING; //算式非法 450 f1=st.top(); 451 st.pop(); 452 switch(op){ 453 case '+': 454 st.push(f1+f2); 455 break; 456 case '-': 457 st.push(f1-f2); 458 break; 459 case '*': 460 st.push(f1*f2); 461 break; 462 case '/': 463 if(f2.fz==0) 464 return ERROR_ZERO; //除0错误 465 st.push(f1/f2); 466 break; 467 } 468 } 469 else 470 return ERROR_STRING; //算式非法 471 } 472 fresult=st.top(); 473 return ERROR_NO; 474 } 475 476 }; 477 478 int main(int argc, char** argv) { 479 ifstream in("equation.txt"); //打开算式所在文件 480 Calculator cal("1+1"); //创建计算器类 481 string s; 482 string answer; 483 int i=0,j; 484 bool b; 485 int zq=0,cw=0; 486 MyError temperror; 487 if(!in){ 488 cout<<"打开文件出错"<<endl; 489 return -1; 490 } 491 while(in>>s){ 492 b=true; 493 cal.recalculator(s); //重启计算器,并传入算式参数 494 cout<<"第"<<++i<<"题:"<<endl; //在屏幕上打印题号 495 temperror=cal.run(); //让计算器计算结果 496 if(temperror!=ERROR_NO){ //算式非法 497 printError(temperror); 498 continue; 499 } 500 cout<<s<<"="; //在屏幕上打印题目 501 cin>>answer; //获得用户输入的结果 502 if(answer==cal.getMyResult()) //判断正误 503 b=true; 504 else 505 b=false; 506 if(b){ //判断正误后输出交互结果 507 cout<<"答案正确"<<endl; 508 zq++; 509 } 510 else{ 511 cout<<"答案错误"<<endl; 512 cout<<"正确答案是:"<<cal.getMyResult()<<endl; 513 cw++; 514 } 515 cout<<endl; 516 } 517 cout<<"总共"<<zq+cw<<"道题,答对"<<zq<<"道,答错"<<cw<<"道"; //最后输出此次作业的结果 518 in.close(); 519 return 0; 520 }