软件工程个人作业04
一:详细要求:
1、 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2。
2、生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
3、每道题目中出现的运算符个数不超过3个,括号不限。
4、程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。
5、把程序变成一个网页程序, 用户通过设定参数,就可以得到各种题目,并可实现在线答题并评判。
二:设计思想
1,用一个网页获取一些程序需要的参数,如题目的个数等等,利用jsp动作将参数传到一个新网页,在新的jsp网页里生成题目并获取用户的答案,在第二个jsp网页统计结果。
2,将C++改成java做后台。。。
源程序代码:
1 #include<iostream> 2 #include<string> 3 #include<time.h> 4 #include <stdio.h> 5 #include<fstream> 6 7 #include<cmath> 8 #include<sstream> 9 #include<strstream> 10 #include<math.h> 11 #include<iomanip> 12 #define MAX 100 13 #define False 0 14 #define True 1 15 using namespace std; 16 typedef string SelemType; 17 using namespace std; 18 string str1[4]={"+","-","*","/"}; //运算符数组,存储+ - * / 19 int n,m; 20 int num[6]; //随机生成的操作数 21 char str2[25]; //整数转化为的字符数组 22 char str3[25]; //整数转化为的字符数组 23 string str4[100]; 24 int OperatorNum[1000]; //运算符数组,每生成一个运算符存进数组 25 typedef struct{ 26 SelemType *base; 27 SelemType *top; 28 int stacksize; 29 }Sqstack; 30 void InitStack(Sqstack &s) //栈的初始化 31 { 32 s.base=new SelemType[MAX]; 33 if(!s.base)exit(1); 34 s.top=s.base; 35 s.stacksize =MAX; 36 } 37 void Push(Sqstack &s,SelemType e) //压入 38 { 39 if(s.top-s.base==s.stacksize) 40 exit(1); 41 *s.top++=e; 42 } 43 void Pop(Sqstack &s,SelemType &e) //弹出 44 { 45 if(s.top==s.base) 46 exit(1); 47 e=*--s.top; 48 } 49 SelemType GetTop(Sqstack &s) //取顶 50 { 51 if(s.top==s.base) 52 exit(1); 53 return *(s.top-1); 54 } 55 int In(SelemType ch) //判断是否为运算符 56 { 57 if(ch=="+"||ch=="-"||ch=="*"||ch=="/"||ch=="("||ch==")"||ch=="#") 58 return True; 59 else 60 return False; 61 } 62 SelemType Operate(SelemType a1,SelemType theta,SelemType b1) //计算 63 { 64 stringstream ss; 65 SelemType c1; 66 double m1,m2; 67 double m3,m4; 68 m1=atof(a1.c_str()); 69 m2=atof(b1.c_str()); 70 if(theta=="+") 71 m3=m1+m2; 72 else if(theta=="-") 73 m3=m1-m2; 74 else if(theta=="*") 75 m3=m1*m2; 76 else if(theta=="/") 77 m3=m1/m2; 78 m4=double((int)(m3*100))/100.0; 79 ss<<m4; 80 ss>>c1; 81 return c1; 82 } 83 char Precede(string theta1,string theta2) //运算符的计算顺序判断 84 { 85 char chx; 86 if(theta1=="+") 87 { 88 if(theta2=="*"||theta2=="/"||theta2=="(") 89 chx = '<'; 90 else 91 chx = '>'; 92 } 93 else if(theta1=="-") 94 { 95 if(theta2=="*"||theta2=="/"||theta2=="(") 96 chx = '<'; 97 else 98 chx = '>'; 99 } 100 else if(theta1=="*") 101 { 102 if(theta2=="(") 103 chx = '<'; 104 else 105 chx = '>'; 106 } 107 else if(theta1=="/") 108 { 109 if(theta2=="(") 110 chx = '<'; 111 else 112 chx = '>'; 113 } 114 else if(theta1=="(") 115 { 116 if(theta2==")") 117 chx = '='; 118 else if(theta2=="#") 119 chx='$'; 120 else 121 chx = '<'; 122 } 123 else if(theta1==")") 124 { 125 if(theta2=="(") 126 chx = '$'; 127 else 128 chx = '>'; 129 } 130 else if(theta1=="#") 131 { 132 if(theta2=="#") 133 chx = '='; 134 else if(theta2==")") 135 chx='$'; 136 else 137 chx = '<'; 138 } 139 return chx; 140 } 141 string TiQuString(string str,int &i) 142 { 143 string ch; 144 char *q; 145 string p; 146 p=str; 147 q=&p[i]; 148 ch=ch+*q; 149 if((*q>='0')&&(*q<='9')) 150 { 151 i++; 152 int j=1; 153 while((*(q+j)>='0')&&(*(q+j)<='9')) 154 { 155 ch=ch+*(q+j); 156 j++; 157 } 158 i=i+j-1; 159 } 160 else 161 { 162 ch=*q; 163 i++; 164 } 165 return ch; 166 } 167 string OPeration(string str) 168 { 169 170 string str1; 171 str1=str+"#"; 172 int i=0; 173 string ch; 174 ch=TiQuString(str1,i); 175 SelemType theta,x1,a1,b1; 176 Sqstack OPND,OPTR; 177 InitStack(OPTR); 178 InitStack(OPND); 179 Push(OPTR,"#"); 180 while(ch!="#"||GetTop(OPTR)!="#") 181 { 182 int f; 183 f=In(ch); 184 if(f!=True) 185 { 186 Push(OPND,ch); 187 ch=TiQuString(str1,i); 188 } 189 else 190 { 191 switch(Precede(GetTop(OPTR),ch)) 192 { 193 case '<': 194 { 195 Push(OPTR,ch); 196 ch=TiQuString(str1,i); 197 break; 198 } 199 case '>': 200 { 201 Pop(OPTR,theta); 202 Pop(OPND,b1);Pop(OPND,a1); 203 Push(OPND,Operate(a1,theta,b1)); 204 break; 205 } 206 case '=': 207 { 208 Pop(OPTR,x1); 209 ch=TiQuString(str1,i); 210 break; 211 } 212 case '$': 213 { 214 cout<<"该表达式有错"; 215 break; 216 } 217 default:break; 218 } 219 } 220 } 221 return GetTop(OPND); 222 223 } 224 void Input(int n,int p,int min,int max,int &j,int &q) 225 { 226 int num1,num2,num3,num4,num5; //随机数 227 int c=0; //指向第一个运算符数组的下标 228 int s=0; //括号的个数 229 string str; 230 ofstream outfile; 231 outfile.open("a.txt",ios::app); 232 if(!outfile) 233 { 234 cerr<<"OPEN ERROR!"<<endl; 235 exit(0); 236 } 237 num1=rand()%(max-min+1)+min; 238 num2=rand()%(max-min+1)+min; 239 num3=rand()%4; //随机数指向运算符数组的下标 240 itoa(num1,str2,10); //整数转化为字符数组 241 itoa(num2,str3,10); //整数转化为字符数组 242 str=str2+str1[num3]+str3; //生成表达式 243 OperatorNum[c]=num3; //当前生成的符号存入OperatorNum数组里 244 c++; 245 n=n-2; //消耗了两个操作数 246 while(n!=0) //当n不等于0时,循环生成str,即表达式+符号+表达式的形式 247 { 248 num4=rand()%2; 249 if(num4==0) //上一个str放在符号的左边 250 { 251 num5=rand()%2; 252 if(s<=3) 253 { 254 if(num5==0) //上一个str不加括号 255 { 256 num3=rand()%4; 257 OperatorNum[c]=num3; 258 c++; 259 num1=rand()%(max-min+1)+min; 260 itoa(num1,str2,10); 261 if((num3==3)&&(OperatorNum[c-2]==3)) //避免生成6/3/2的形式 262 str="("+str+")"+str1[num3]+str2; 263 else 264 str=str+str1[num3]+str2; 265 } 266 else //上一个str加括号 267 { 268 num3=rand()%4; 269 num1=rand()%(max-min+1)+min; 270 itoa(num1,str2,10); 271 str="("+str+")"+str1[num3]+str2; 272 s++; 273 } 274 } 275 else 276 { 277 num3=rand()%4; 278 OperatorNum[c]=num3; 279 c++; 280 num1=rand()%(max-min+1)+min; 281 itoa(num1,str2,10); 282 if((num3==3)&&(OperatorNum[c-2]==3)) //避免生成6/3/2的形式 283 str="("+str+")"+str1[num3]+str2; 284 else 285 str=str+str1[num3]+str2; 286 } 287 } 288 else //上一个str放在符号的右边 289 { 290 num5=rand()%2; 291 if(s<=3) 292 { 293 if(num5==0) // 上一个str不加括 294 { 295 num3=rand()%4; 296 OperatorNum[c]=num3; 297 c++; 298 num1=rand()%(max-min+1)+min; 299 itoa(num1,str2,10); 300 if((num3==3)&&(OperatorNum[c-2]==3)) 301 str=str2+str1[num3]+"("+str+")"; 302 else 303 str=str2+str1[num3]+str; 304 } 305 else //上一个str加括号 306 { 307 num3=rand()%4; 308 num1=rand()%(max-min+1)+min; 309 itoa(num1,str2,10); 310 str=str2+str1[num3]+"("+str+")"; 311 s++; 312 } 313 } 314 else 315 { 316 num3=rand()%4; 317 OperatorNum[c]=num3; 318 c++; 319 num1=rand()%(max-min+1)+min; 320 itoa(num1,str2,10); 321 if((num3==3)&&(OperatorNum[c-2]==3)) 322 str=str2+str1[num3]+"("+str+")"; 323 else 324 str=str2+str1[num3]+str; 325 } 326 } 327 n--; //消耗一个操作数 328 } 329 string result1,result2; //result1表示用户输入的答案,result2表示程序计算的结果 330 str4[p]=str; //把str存入字符串数组str4中 331 for(int i=0;i<p;i++) //查询四则运算式是否有重复 332 if(str4[i]==str4[p]) 333 Input(m,p,min,max,j,q); 334 cout<<str4[p]<<"="; 335 result2=OPeration(str); //计算四则表达式 336 cin>>result1; 337 if(result1==result2) //判断结果是否正确 338 { 339 cout<<"计算正确"; 340 j++; 341 } 342 else 343 { 344 cout<<"计算错误,答案是"<<setprecision(2)<<fixed<<result2; 345 q++; 346 } 347 outfile<<str4[p]<<endl; 348 cout<<endl; 349 } 350 void Input1(int n,int p,int min,int max,int &j,int &q) 351 { 352 int num1,num2,num3,num4; 353 int c=0; 354 int s=0; 355 string str; 356 ofstream outfile; 357 outfile.open("a.txt",ios::app); 358 if(!outfile) 359 { 360 cerr<<"OPEN ERROR!"<<endl; 361 exit(0); 362 } 363 num1=rand()%(max-min+1)+min; 364 num2=rand()%(max-min+1)+min; 365 num3=rand()%4; 366 itoa(num1,str2,10); 367 itoa(num2,str3,10); 368 str=str2+str1[num3]+str3; 369 OperatorNum[c]=num3; 370 c++; 371 n=n-2; 372 while(n!=0) //当n不等于0时,循环生成str,即表达式+符号+表达式的形式 373 { 374 num4=rand()%2; 375 if(num4==0) //上一个str放在符号的左边 376 { 377 num3=rand()%4; 378 OperatorNum[c]=num3; 379 c++; 380 num1=rand()%(max-min+1)+min; 381 itoa(num1,str2,10); 382 if((num3==3)&&(OperatorNum[c-2]==3)) //避免生成6/3/2的形式 383 str="("+str+")"+str1[num3]+str2; 384 else 385 str=str+str1[num3]+str2; 386 } 387 else //上一个str放在符号的右边 388 { 389 num3=rand()%4; 390 OperatorNum[c]=num3; 391 c++; 392 num1=rand()%(max-min+1)+min; 393 itoa(num1,str2,10); 394 if((num3==3)&&(OperatorNum[c-2]==3)) 395 str=str2+str1[num3]+"("+str+")"; 396 else 397 str=str2+str1[num3]+str; 398 } 399 n--; 400 } 401 string result1,result2; 402 str4[p]=str; //把str存入字符串数组str4中 403 for(int i=0;i<p;i++) //查询四则运算式是否有重复 404 if(str4[i]==str4[p]) 405 Input(m,p,min,max,j,q); 406 cout<<str4[p]<<"="; 407 result2=OPeration(str); 408 cin>>result1; 409 if(result1==result2) 410 { 411 cout<<"计算正确"; 412 j++; 413 } 414 else 415 { 416 cout<<"计算错误,答案是"<<setprecision(2)<<fixed<<result2; 417 q++; 418 } 419 outfile<<str4[p]<<endl; 420 cout<<endl; 421 } 422 void sort(int min,int max){ //生成四个随机数并排序 423 num[0]=rand()%(max-min+1)+min; 424 num[1]=rand()%(max-min+1)+min; 425 num[2]=rand()%(max-min+1)+min; 426 num[3]=rand()%(max-min+1)+min; 427 for(int i=0;i<4;i++){ 428 for(int j=0;j<i;j++){ 429 if(num[i]>num[j]) 430 { 431 int temp=0; 432 temp=num[i]; 433 num[i]=num[j]; 434 num[j]=temp; 435 } 436 } 437 } 438 } 439 void sort1(int min,int max) //生成两个随机数,并排序 440 { 441 num[4]=rand()%(max-min+1)+min; 442 num[5]=rand()%(max-min+1)+min; 443 for(int i=4;i<6;i++){ 444 for(int j=4;j<i;j++){ 445 if(num[i]>num[j]) 446 { 447 int temp=0; 448 temp=num[i]; 449 num[i]=num[j]; 450 num[j]=temp; 451 } 452 } 453 } 454 } 455 void Simplification(int &m,int &n) //真分数化简 456 { 457 int x,y,i,p; //公约数p 458 if(m>=n) 459 { 460 x=n; 461 y=m; 462 } 463 if(m<n) 464 { 465 x=m; 466 y=n; 467 } 468 for(i=x;i>0;i--) 469 { 470 if(x%i==0&&y%i==0) 471 { 472 p=i; 473 break; 474 } 475 } 476 m=m/p; 477 n=n/p; 478 } 479 void Input2(int n,int p,int min,int max,int &j,int &q) 480 { 481 int num3,num4,s=0; 482 string str,strr2,strr3,str5,str6,str7,str8,str9; 483 stringstream ss1,ss2,ss3,ss4,ss5,ss6,ss7,ss8; 484 ofstream outfile; 485 outfile.open("a.txt",ios::app); 486 if(!outfile) 487 { 488 cerr<<"OPEN ERROR!"<<endl; 489 exit(0); 490 } 491 num3=rand()%4; 492 sort(min,max); 493 Simplification(num[0],num[3]); 494 Simplification(num[1],num[2]); 495 ss1<<num[0]; 496 ss1>>strr2; 497 ss2<<num[1]; 498 ss2>>strr3; 499 ss3<<num[2]; 500 ss3>>str5; 501 ss4<<num[3]; 502 ss4>>str6; 503 if((str5!=strr3)&&(str6!=strr2)) //避免生成分子分母相等的表达式 504 str="("+str5+"/"+strr3+")"+str1[num3]+"("+str6+"/"+strr2+")"; 505 else if(str5==strr3) 506 str=str5+str1[num3]+"("+str6+"/"+strr2+")"; 507 else if(str6==strr2) 508 str="("+str5+"/"+strr3+")"+str1[num3]+str6; 509 n=n-4; 510 while(n!=0) //当n不等于0时,循环生成str,即表达式+符号+表达式的形式 511 { 512 num4=rand()%2; 513 if(num4==0) //上一个str放在符号的左边 514 { 515 sort1(min,max); 516 Simplification(num[4],num[5]); 517 num3=rand()%4; 518 ss5<<num[4]; 519 ss5>>str7; 520 ss6<<num[5]; 521 ss6>>str8; 522 if(str7!=str8) //避免生成分子分母相等的表达式 523 str9="("+str8+"/"+str7+")"; 524 else 525 str9=str8; 526 str=str+str1[num3]+str9; 527 } 528 else //上一个str放在符号的右边 529 { 530 sort1(min,max); 531 Simplification(num[4],num[5]); 532 num3=rand()%4; 533 ss7<<num[4]; 534 ss7>>str7; 535 ss8<<num[5]; 536 ss8>>str8; 537 if(str7!=str8) //避免生成分子分母相等的表达式 538 str9="("+str8+"/"+str7+")"; 539 else 540 str9=str8; 541 str=str9+str1[num3]+str; 542 } 543 n=n-2; 544 } 545 string result1,result2; 546 str4[p]=str; //把str存入字符串数组str4中 547 for(int i=0;i<p;i++) //查询四则运算式是否有重复 548 if(str4[i]==str4[p]) 549 Input2(m,p,min,max,j,q); 550 cout<<str4[p]<<"="; 551 result2=OPeration(str); 552 cin>>result1; 553 if(result1==result2) 554 { 555 cout<<"计算正确"; 556 j++; 557 } 558 else 559 { 560 cout<<"计算错误,答案是"<<setprecision(2)<<fixed<<result2; 561 q++; 562 } 563 outfile<<str4[p]<<endl; 564 cout<<endl; 565 } 566 void changeNum(int n,int y,int min,int max) 567 { 568 int j=0,q=0,num6; 569 if(y==1) 570 { 571 for(int i=0;i<n;i++) 572 { 573 num6=rand()%9+2; 574 switch(num6) 575 { 576 case 2:Input(2,i,min,max,j,q);break; 577 case 3:Input(3,i,min,max,j,q);break; 578 case 4:Input(4,i,min,max,j,q);break; 579 case 5:Input(5,i,min,max,j,q);break; 580 case 6:Input(6,i,min,max,j,q);break; 581 case 7:Input(7,i,min,max,j,q);break; 582 case 8:Input(8,i,min,max,j,q);break; 583 case 9:Input(9,i,min,max,j,q);break; 584 case 10:Input(10,i,min,max,j,q);break; 585 } 586 } 587 cout<<"本次测试结束"<<endl; 588 cout<<"正确----"<<j<<"道题,错误----"<<q<<"道题"<<endl; 589 cout<<"***************************************"<<endl; 590 } 591 else 592 { 593 for(int i=0;i<n;i++) 594 { 595 num6=rand()%9+2; 596 switch(num6) 597 { 598 case 2:Input1(2,i,min,max,j,q);break; 599 case 3:Input1(3,i,min,max,j,q);break; 600 case 4:Input1(4,i,min,max,j,q);break; 601 case 5:Input1(5,i,min,max,j,q);break; 602 case 6:Input1(6,i,min,max,j,q);break; 603 case 7:Input1(7,i,min,max,j,q);break; 604 case 8:Input1(8,i,min,max,j,q);break; 605 case 9:Input1(9,i,min,max,j,q);break; 606 case 10:Input1(10,i,min,max,j,q);break; 607 } 608 } 609 cout<<"本次测试结束"<<endl; 610 cout<<"正确----"<<j<<"道题,错误----"<<q<<"道题"<<endl; 611 cout<<"***************************************"<<endl; 612 613 } 614 } 615 void changeNum1(int n,int min,int max) 616 { 617 int j=0,q=0,p,num6; 618 for(int i=0;i<n;i++) 619 { 620 num6=rand()%4; 621 p=4+2*i; //表示生成的操作数的个数 622 switch(p) 623 { 624 case 4:Input2(4,i,min,max,j,q);break; 625 case 6:Input2(6,i,min,max,j,q);break; 626 case 8:Input2(8,i,min,max,j,q);break; 627 case 10:Input2(10,i,min,max,j,q);break; 628 } 629 } 630 cout<<"本次测试结束"<<endl; 631 cout<<"正确----"<<j<<"道题,错误----"<<q<<"道题"<<endl; 632 cout<<"***************************************"<<endl; 633 } 634 int main() 635 { 636 int x,y,max,min; 637 srand((unsigned)time(NULL)); 638 ofstream outfile1; 639 outfile1.open("a.txt"); 640 if(!outfile1) 641 { 642 cerr<<"OPEN ERROR!"<<endl; 643 exit(0); 644 } 645 cout<<"------------自动出题做题系统---------------"<<endl; 646 cout<<" 1.整数的四则运算 "<<endl; 647 cout<<" 2.真分数的四则运算 "<<endl; 648 cout<<" 3.退出 "<<endl; 649 for(;;) 650 { 651 cout<<"请选择:"; 652 cin>>x; 653 switch(x) 654 { 655 case 1: 656 { 657 cout<<"取值范围最小值(大于等于1):"; 658 cin>>min; 659 cout<<"取值范围最大值:"; 660 cin>>max; 661 cout<<"有(无)括号运算(注释:真分数必须加括号,以防形成6/3/2的形式)---有(1),无(0):"; 662 cin>>y; 663 cout<<"题目数量:"; 664 cin>>n; 665 cout<<" 测试开始 "<<endl; 666 changeNum(n,y,min,max); 667 break; 668 } 669 case 2: 670 { 671 cout<<"取值分子分母范围最小值(大于等于1):"; 672 cin>>min; 673 cout<<"取值分子分母范围最大值(大于等于1):"; 674 cin>>max; 675 cout<<"题目数量:"; 676 cin>>n; 677 cout<<" 测试开始 "<<endl; 678 changeNum1(n,min,max); 679 break; 680 } 681 case 3: 682 { 683 exit(0); 684 break; 685 } 686 } 687 } 688 return 0; 689 }
HTML/jsp文件代码: