【应用】浮点数四则运算器 Part3:运算模块的编写
已知:后缀表达式已经按规则排在一个栈中。
计算后缀表达式的过程主要按下面的思路进行:
1.保存数据的栈为fx1,创建一个新的栈ans;
2.每次读取时,若fx1不空:
1)若为数据,直接入栈。
2)若为操作符:
(1)若不为'/':读取ans栈顶两次,取出数据运算后放回栈中。
(2)若为'/':读取ans栈顶一次,若为0,输出error code 10:'0' under '/',否则取出数据运算后放回栈中。
3.输出ans的栈顶元素。
注意!若ans的元素个数不为1,则出现了问题,输出extra code 11:BUG SHOWED!DAMN!!!
还可以以1000倍为精度判断输出的数是否为浮点数后再输出。
1 stack<double> ans; 2 3 void Out(double i){ 4 double a; 5 int a0,a1; 6 a=i; 7 a0=1000*a; 8 if (a0%1000==0){ 9 a1=a; 10 printf("out>>%d\n",a1); 11 } 12 else{ 13 printf("out>>%.2lf\n",a); 14 } 15 }
下面是代码实现。
1 void cal(){ 2 Error=0; 3 if (ans.empty()==0){ 4 ans.pop(); 5 } 6 double a=0.0,b=0.0; 7 char tmp[300]; 8 while (fx1.empty()==0){ 9 if (fx1.top()=="+"|| 10 fx1.top()=="-"|| 11 fx1.top()=="*"){ 12 a=ans.top(); 13 ans.pop(); 14 b=ans.top(); 15 ans.pop(); 16 if (fx1.top()=="+"){ans.push(b+a);} 17 if (fx1.top()=="-"){ans.push(b-a);} 18 if (fx1.top()=="*"){ans.push(b*a);} 19 fx1.pop(); 20 continue; 21 } 22 if (fx1.top()=="/"){ 23 if (ans.top()==0){ 24 Error=1; 25 printf("out>>error code 10: '0' under '/'\n"); 26 return ; 27 } 28 a=ans.top(); 29 ans.pop(); 30 b=ans.top(); 31 ans.pop(); 32 ans.push(b/a); 33 fx1.pop(); 34 continue; 35 } 36 for (int i=0;i<300;i++){ 37 tmp[i]=0; 38 } 39 strcpy(tmp,fx1.top().c_str()); 40 ans.push(atof(tmp)); 41 fx1.pop(); 42 } 43 if (ans.size()!=1){ 44 printf("out>>error code 11: BUG SHOWED!DAMN!!!\n"); 45 } 46 else{ 47 Out(ans.top()); 48 ans.pop(); 49 } 50 }
将之前三篇文章中的模块拼合在一起就可以得到完整的程序了。
但是还需要对程序的使用者提供一定的帮助,因此有了下面的指导模块:
1 void guide(){ 2 printf("浮点数四则运算器:\n"); 3 printf("每输入一个数据或操作符,你需要使用一个空格来表示输入完成。\n"); 4 printf("输入完成一行表达式后,输入回车来表示输入结束。\n"); 5 printf("若输入了错误的表达式,请参照程序的报错类型修正表达式。\n"); 6 printf("你可以为多个变量或单个变量赋值,下面是一个事例:\n"); 7 printf("in>>x y = 3.1\n"); 8 printf("out>>3.1\n"); 9 printf("in>>( x + y ) * -3\n"); 10 printf("out>>-18.60\n"); 11 printf("保留两位小数。"); 12 printf("输入exit可以退出程序。\n"); 13 printf("===============================================\n"); 14 }
完整的程序折叠在下方。
1 #include<iostream> 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 #include<map> 6 #include<stack> 7 #include<queue> 8 9 using namespace std; 10 11 string dat; 12 string all[100]; 13 map<string,string> cnt; 14 map<string,string>::iterator iter; 15 int flag=0; 16 int x=0; 17 18 void Getdata(){ 19 x=0; 20 flag=0; 21 dat=""; 22 for (int i=0;i<100;i++){ 23 all[i]=""; 24 } 25 int code=0; 26 char a=0; 27 cout<<"in>>"; 28 while (1){ 29 a=getchar(); 30 if (a=='('){ 31 code++; 32 } 33 if (a==')'){ 34 code--; 35 } 36 if (code<0){ 37 flag=1; 38 } 39 if (a==' '){ 40 all[x]=dat; 41 x++; 42 dat=""; 43 continue; 44 } 45 if (a=='\n'){ 46 all[x]=dat; 47 dat=""; 48 if (flag==3){ 49 for (int i=0;i<x;i++){ 50 cnt[all[i]]=all[x]; 51 } 52 } 53 if (all[x]=="exit"&&x==0){ 54 flag=4; 55 } 56 if (code>0){ 57 flag=2; 58 } 59 return ; 60 } 61 if (a=='='){ 62 flag=3; 63 all[x]=dat; 64 x++; 65 dat=""; 66 continue; 67 } 68 dat+=a; 69 } 70 } 71 72 int Error=0; 73 74 void givenum(){ 75 Error=0; 76 for (int i=0;i<=x;i++){ 77 if ((all[i][0]>='0'&&all[i][0]<='9')|| 78 all[i]=="("|| 79 all[i]==")"|| 80 all[i][0]=='+'|| 81 all[i][0]=='-'|| 82 all[i]=="*"|| 83 all[i]=="/"){ 84 continue; 85 } 86 if (cnt.find(all[i])!=cnt.end()){ 87 all[i]=cnt[all[i]]; 88 } 89 else{ 90 printf("out>>error code 3: undefined '%s'\n",all[i].c_str()); 91 Error=1; 92 break; 93 } 94 } 95 } 96 97 void check(){ 98 Error=0; 99 int code[x+10]; 100 for (int i=0;i<=x;i++){ 101 if (all[i]=="+"|| 102 all[i]=="-"|| 103 all[i]=="*"|| 104 all[i]=="/"){ 105 code[i]=4; 106 continue; 107 } 108 if (all[i][0]=='('){ 109 code[i]=2; 110 continue; 111 } 112 if (all[i][0]==')'){ 113 code[i]=3; 114 continue; 115 } 116 code[i]=1; 117 } 118 if (code[0]==4){ 119 printf("out>>error code 9: extra start operation '%s'\n",all[0].c_str()); 120 Error=1; 121 } 122 for (int i=0;i<=x;i++){ 123 if (i>0&& 124 code[i]==1&& 125 code[i-1]==3){ 126 printf("out>>error code 4: operation after ')' needed\n"); 127 Error=1; 128 } 129 if (i<x&& 130 code[i]==1&& 131 code[i+1]==2){ 132 printf("out>>error code 5: operation before '(' needed\n"); 133 Error=1; 134 } 135 if (i<x&& 136 code[i]==1&& 137 code[i+1]==1){ 138 printf("out>>error code 6: operation after '%s' needed\n",all[i].c_str()); 139 Error=1; 140 } 141 if (i<x&& 142 code[i]==4&& 143 code[i+1]==4){ 144 printf("out>>error code 7: double operation '%s' '%s'\n",all[i].c_str(),all[i+1].c_str()); 145 Error=1; 146 } 147 } 148 if (code[x]==4){ 149 printf("out>>error code 8: extra end operation '%s'\n",all[x].c_str()); 150 Error=1; 151 } 152 } 153 154 stack<string> fx1; 155 stack<string> fx2; 156 157 int level(string buffer){ 158 switch (buffer[0]){ 159 case '+': return 1; 160 case '-': return 1; 161 case '*': return 2; 162 case '/': return 2; 163 default: return 0; 164 } 165 } 166 167 void change(){ 168 while (fx1.empty()!=1){ 169 fx1.pop(); 170 } 171 while (fx2.empty()!=1){ 172 fx2.pop(); 173 } 174 int m=0; 175 while (m<=x){ 176 if (all[m]=="+"|| 177 all[m]=="-"|| 178 all[m]=="*"|| 179 all[m]=="/"){ 180 if (fx1.empty()==1|| 181 fx1.top()=="("){ 182 fx1.push(all[m]); 183 m++; 184 continue; 185 } 186 else{ 187 if (level(fx1.top())<=level(all[m])){ 188 fx1.push(all[m]); 189 m++; 190 continue; 191 } 192 else{ 193 while (fx1.empty()!=1&& 194 fx1.top()!="("&& 195 level(fx1.top())>level(all[m])){ 196 fx2.push(fx1.top()); 197 fx1.pop(); 198 } 199 fx1.push(all[m]); 200 m++; 201 continue; 202 } 203 } 204 } 205 if (all[m][0]=='('|| 206 all[m][0]==')'){ 207 if (all[m][0]=='('){ 208 fx1.push(all[m]); 209 m++; 210 continue; 211 } 212 if (all[m][0]==')'){ 213 while (fx1.empty()!=1&& 214 fx1.top()!="("){ 215 fx2.push(fx1.top()); 216 fx1.pop(); 217 } 218 fx1.pop(); 219 m++; 220 continue; 221 } 222 } 223 fx2.push(all[m]); 224 m++; 225 } 226 while (fx1.empty()!=1){ 227 fx2.push(fx1.top()); 228 fx1.pop(); 229 } 230 while (fx2.empty()!=1){ 231 fx1.push(fx2.top()); 232 fx2.pop(); 233 } 234 } 235 236 stack<double> ans; 237 238 void Out(double i){ 239 double a; 240 int a0,a1; 241 a=i; 242 a0=1000*a; 243 if (a0%1000==0){ 244 a1=a; 245 printf("out>>%d\n",a1); 246 } 247 else{ 248 printf("out>>%.2lf\n",a); 249 } 250 } 251 252 void cal(){ 253 Error=0; 254 if (ans.empty()==0){ 255 ans.pop(); 256 } 257 double a=0.0,b=0.0; 258 char tmp[300]; 259 while (fx1.empty()==0){ 260 if (fx1.top()=="+"|| 261 fx1.top()=="-"|| 262 fx1.top()=="*"){ 263 a=ans.top(); 264 ans.pop(); 265 b=ans.top(); 266 ans.pop(); 267 if (fx1.top()=="+"){ans.push(b+a);} 268 if (fx1.top()=="-"){ans.push(b-a);} 269 if (fx1.top()=="*"){ans.push(b*a);} 270 fx1.pop(); 271 continue; 272 } 273 if (fx1.top()=="/"){ 274 if (ans.top()==0){ 275 Error=1; 276 printf("out>>error code 10: '0' under '/'\n"); 277 return ; 278 } 279 a=ans.top(); 280 ans.pop(); 281 b=ans.top(); 282 ans.pop(); 283 ans.push(b/a); 284 fx1.pop(); 285 continue; 286 } 287 for (int i=0;i<300;i++){ 288 tmp[i]=0; 289 } 290 strcpy(tmp,fx1.top().c_str()); 291 ans.push(atof(tmp)); 292 fx1.pop(); 293 } 294 if (ans.size()!=1){ 295 printf("out>>error code 11: BUG SHOWED!DAMN!!!\n"); 296 } 297 else{ 298 Out(ans.top()); 299 ans.pop(); 300 } 301 } 302 303 void guide(){ 304 printf("浮点数四则运算器:\n"); 305 printf("每输入一个数据或操作符,你需要使用一个空格来表示输入完成。\n"); 306 printf("输入完成一行表达式后,输入回车来表示输入结束。\n"); 307 printf("若输入了错误的表达式,请参照程序的报错类型修正表达式。\n"); 308 printf("你可以为多个变量或单个变量赋值,下面是一个事例:\n"); 309 printf("in>>x y = 3.1\n"); 310 printf("out>>3.1\n"); 311 printf("in>>( x + y ) * -3\n"); 312 printf("out>>-18.60\n"); 313 printf("保留两位小数。"); 314 printf("输入exit可以退出程序。\n"); 315 printf("===============================================\n"); 316 } 317 318 int main(){ 319 guide(); 320 while (1){ 321 Getdata(); 322 if (flag==1){ 323 printf("out>>error code 1: extra ')'\n"); 324 continue; 325 } 326 if (flag==2){ 327 printf("out>>error code 2: extra '('\n"); 328 continue; 329 } 330 if (flag==3){ 331 printf("out>>%s\n",cnt[all[x-1]].c_str()); 332 continue; 333 } 334 if (flag==4){ 335 break; 336 } 337 if (flag==0){ 338 givenum(); 339 if (Error==1){ 340 continue; 341 } 342 check(); 343 if (Error==1){ 344 continue; 345 } 346 change(); 347 cal(); 348 continue; 349 } 350 } 351 return 0; 352 }
作业结束后助教君给出的参考用标准程序也折叠在下方。
1 #include <cstdio> 2 #include <stack> 3 #include <cstring> 4 #include <cmath> 5 #include <string> 6 #include <map> 7 using namespace std; 8 9 // debug flag 10 #define $ if(0) 11 12 const int MAX_VAR_LENGTH=107; 13 const char POSITIVE=1,NEGATIVE=2,END=3; // special operators 14 int precedence[256]; // char -> precedence 15 16 struct Number { // to deal with auto float/int recognition 17 double val; 18 bool is_integer; 19 }; 20 21 // variable stuffs 22 string var_name; 23 inline bool valid_var_char(char c) { 24 return (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') || c=='_'; 25 } 26 inline int read_var_name(char *s) { 27 char var_name_tmp[MAX_VAR_LENGTH]; 28 29 if(!valid_var_char(s[0]) || (s[0]>='0'&&s[0]<='9')) 30 return 0; 31 var_name_tmp[0]=s[0]; 32 int i=1; 33 for(;valid_var_char(s[i]);i++) 34 var_name_tmp[i]=s[i]; 35 var_name_tmp[i]='\0'; 36 var_name=var_name_tmp; 37 return i; 38 } 39 map<string,Number> var_store; 40 41 // apply `op` to `val`s 42 inline void apply(stack<Number> &val,char op) { 43 if(op=='(' || op==')' || op==END) return; 44 45 if(val.empty()) throw "no sufficient operand"; 46 Number v2=val.top(); val.pop(); 47 48 // unary operators 49 if(op==POSITIVE) { 50 val.push(v2); 51 return; 52 } else if(op==NEGATIVE) { 53 val.push(Number{-v2.val,v2.is_integer}); 54 return; 55 } 56 57 if(val.empty()) throw "no sufficient operand"; 58 Number v1=val.top(); val.pop(); 59 60 // binary operators 61 Number res; 62 res.is_integer=v1.is_integer&&v2.is_integer; 63 64 if(op=='+') res.val=v1.val+v2.val; 65 else if(op=='-') res.val=v1.val-v2.val; 66 else if(op=='*') res.val=v1.val*v2.val; 67 else if(op=='/') { 68 if(fabs(v2.val)<1e-6) throw "division by zero"; 69 res.val=v1.val/v2.val; 70 } 71 else throw "invalid operator"; 72 73 // round the result if is integer 74 if(res.is_integer) res.val=double(int(res.val)); 75 76 $ printf("[APPLY] %lf %c %lf = %lf\n",v1.val,op,v2.val,res.val); 77 val.push(res); 78 } 79 80 // calc a pure expression 81 inline Number calc(char *s) { 82 int len=(int)strlen(s); 83 s[len++]=END; 84 stack<char> op; 85 op.push(END); 86 stack<Number> val; 87 bool last_is_operand=false; 88 89 for(int i=0;i<len;) { 90 if(s[i]==' ') { 91 $ printf("[SPACE] at %d\n",i); 92 i++; 93 } else if(int var_len=read_var_name(s+i)) { // variable 94 if(last_is_operand) throw "continuous operand"; 95 96 if(var_store.find(var_name)==var_store.end()) throw "uninitialized variable"; 97 $ printf("[VAR] at %d: %s\n",i,var_name.c_str()); 98 val.push(var_store[var_name]); 99 100 last_is_operand=true; 101 i+=var_len; 102 } else if((s[i]>='0'&&s[i]<='9')||s[i]=='.') { // number literal 103 if(last_is_operand) throw "continuous operand";; 104 double curval; 105 int curlen; 106 107 sscanf(s+i,"%lf%n",&curval,&curlen); 108 $ printf("[VAL] at %d+%d: %lf\n",i,curlen,curval); 109 110 bool is_integer=true; 111 for(int j=i;j<i+curlen;j++) 112 if(s[j]=='.') 113 is_integer=false; 114 115 if(curlen==0 || (!is_integer && curlen==1)) // '.' 116 throw "invalid number"; 117 118 val.push(Number{curval,is_integer}); 119 last_is_operand=true; 120 i+=curlen; 121 } else { // operator 122 char o=s[i]; 123 124 // detect unary POSITIVE & NEGATIVE 125 int prev=i-1; 126 while(prev>=0 && s[prev]==' ') prev--; 127 if((o=='+' || o=='-') && ( // we use s[prev] instead of s[i-1] here because of possible whitespaces 128 prev==-1 || (s[prev]=='(' || s[prev]=='+' || s[prev]=='-' || s[prev]=='*' || s[prev]=='/') 129 )) { 130 o=(o=='+')?POSITIVE:NEGATIVE; 131 } 132 133 $ printf("[OP] at %d: %c\n",i,o); 134 if(!precedence[(int)o]) { 135 throw "unknown operator"; 136 } 137 138 if(o=='(') { 139 if(last_is_operand) throw "invalid usage of bracket"; 140 op.push(o); 141 } else if(o==')') { 142 if(!last_is_operand) throw "invalid usage of bracket"; 143 while(!op.empty() && op.top()!='(') { 144 char top=op.top(); 145 $ printf("[APPLY] %c : %c\n",o,top); 146 apply(val,top); op.pop(); 147 } 148 if(op.empty()) throw "invalid usage of bracket"; 149 $ printf("[APPLY] %c : (\n",o); 150 op.pop(); //'(' 151 } else { // normal arithmetic operator 152 if(o!=POSITIVE && o!=NEGATIVE) // unary operator should not apply right now, or -+2 will cause an error 153 while(!op.empty() && precedence[(int)o]<=precedence[(int)op.top()]) { 154 char top=op.top(); 155 $ printf("[APPLY] %c : %c\n",o,top); 156 apply(val,top); op.pop(); 157 } 158 159 op.push(o); 160 last_is_operand=false; 161 } 162 i++; 163 } 164 } 165 // finished 166 167 if(op.size()!=1 || val.size()!=1) 168 throw "bad expression"; 169 return val.top(); 170 } 171 172 int main() { 173 char s[10007]; 174 175 precedence[(int)'(']=1, precedence[(int)')']=1, 176 precedence[(int)END]=2, // precedence of END is higher than ( and ) so we can check bracket errors correctly 177 precedence[(int)'+']=3, precedence[(int)'-']=3, 178 precedence[(int)'*']=4, precedence[(int)'/']=4, 179 precedence[(int)POSITIVE]=5, precedence[(int)NEGATIVE]=5; 180 181 while(true) { 182 Number res; 183 scanf("%*[ ]"); // ignore leading spaces 184 185 gets(s); 186 if(strcmp(s,"exit")==0) 187 return 0; 188 189 int len=(int)strlen(s),eqpos=-1; 190 for(int i=len-1;i>0;i--) // eqpos: position of the last `=` 191 if(s[i]=='=') { 192 eqpos=i; 193 break; 194 } 195 196 try { 197 if(eqpos==-1) // pure EXPRESSION 198 res=calc(s); 199 else { // VAR = EXPRESSION 200 res=calc(s+eqpos+1); // the EXPRESSION part 201 202 int name_len=read_var_name(s); 203 for(int i=name_len;i<eqpos;i++) // tackle with trailing spaces after variable name 204 if(s[i]!=' ') 205 throw "bad variable name"; 206 207 // finally store it 208 $ printf("STORE TO %s\n",var_name.c_str()); 209 var_store[var_name]=res; 210 } 211 } catch(const char *e) { 212 printf("error: %s\n",e); 213 //printf("error\n"); 214 continue; 215 } 216 // no error 217 printf(res.is_integer ? "%.0lf\n" : "%.2lf\n", res.val); 218 } 219 }

浙公网安备 33010602011771号