C++ 字串轉換為浮點數時的精度問題
阿新 • • 發佈:2019-02-19
#include<stdio.h> /*庫檔案包含*/ #include<string.h> /*用於字串操作*/ #include<stdlib.h> /*用於exit函式*/ /************************************************************************** int check(char *c) 輸入引數: char *c: 輸入的字串 返回引數: 0:字串中有不符合規定的字元 1: 字串字元符合規定,沒有不符合規定的字元. 功能: 檢查字串中有否除了 0-9, +,-,*,/,(,),之外的其他字元, 如果有,則返回0, 表示出現錯誤。 若沒有,則返回1,表式字串符合規定。 **************************************************************************/ int check(char *c) { int k=0; while(*c!='\0') { if((*c>='0' && *c<='9') || *c=='+' || *c=='-' || *c=='*' || *c=='/' || *c=='.' || *c=='(' || *c==')' ) { } else { printf("input error, there have the char not the math expression char!\n"); return 0; } if(*c=='(') k++; else if(*c==')') k--; c++; } if(k!=0) { printf("input error, there is not have correct bracket '()'!\n"); return 0; } return 1; } /************************************************************************** void move(char *f, double *s,int p) 輸入引數: char *f : 運算子陣列 double *s: 數值陣列 int p: 當前運算子陣列位置。 返回引數: 無 功能: 將當前已經完成運算的運算子消去,同時將數值陣列的位置調整以進行下一次運算。 傳入值p若為3 則當前符號的陣列位置為3. f[3]=f[3+1].......f[len-2]=f[len-1] f[len-1]='\0'; s[i]=s[i+1].......s[len-1]=s[len] 因為數值比運算子多一個。 ***************************************************************************/ void move(char *f, double *s,int p) { int i=0,len=strlen(f); for(i=p; i<len; i++) /*將已經運算過的符號,空出來的位置用後面的符號來填充,*/ { /*即把乘和除號的位置用後面的加和減號填充*/ f[i]=f[i+1]; s[i]=s[i+1]; } s[i]=s[i+1]; f[len-1]='\0'; } /************************************************************************** double convnum(char *c) 輸入引數: char *c :由數字和小數點組成的字元,用以轉換成double型的數值。 返回引數: num:返回轉換好的值。 功能: 將輸入的字串先將其小數點以前的部分複製到temp[]陣列中, 若有小數點,則將小數點之後的數值,也就是小數部分先進行計算,值存入num中 計算完成後,再對整數部分進行計算,值加上小數部分的值,存入num中。 ***************************************************************************/ double convnum(char *c) { double num=0.0; double a=1.0; int i=0,p=0,len=0; char temp[100]; int tempi=0; int start=0; int f=1; /*正負符號指示器,若為1則為正數,為-1,此數為負數*/ len=strlen©; if(c[0]=='-') { start=1; f=-1; } for(i=start; i<len; i++) { if(c[i]=='.') { p=i; break; } temp[tempi++]=c[i]; /*將整數部分複製到temp[]中*/ } temp[tempi]='\0'; if(p!=0) { for(i=p+1;i<len;i++) /*將小數部分計算出來*/ { if(c[i]=='.') /*如果有多餘的小數點,則表示輸入錯誤*/ { printf("there is more that one dot '.' in number!error!\n"); exit(0); } a=a*0.1; num+=(a*(c[i]-48)); } } a=1.0; len=strlen(temp); /*計算整數部分*/ for(i=len-1;i>=0; i--) { num=num+(a*(temp[i]-48)); a*=10; } num=num*f; return num; } /************************************************************************** double good(char *c) 輸入引數: char *c :即將進行運算的字串型數學表示式。如3.5+(2*3/5) 返回引數: s[0]:計算結果將放入s[0]中 功能: 將輸入的字串中的數字分別呼叫convnum(char *c)函式進行數值變換,再將其依 次存入doulbe s[i]中,將加減乘除運算子依次存入字串符號陣列 char f[i]中, 然後如果遇到括號,則將括號內的字串存入另一字元陣列中,然後用此 good(char *c) 遞迴函式進行遞迴運算。 然後根據先乘除,後加減的順序對已 存入陣列的數值根 據存入字串符號陣列的運算子進行運算。結果存入s[0]中。 返回最終結果。 ***************************************************************************/ double good(char *c) /*可遞迴函式*/ { /*取得數值字串,並呼叫convnum轉換成double*/ char g[100],number[30]; /*g,儲存當前的表示式串,number儲存一個數的所有字元*/ char f[80]; /*儲存所有的符號的堆疊*/ int fi=0; /*儲存符號的位置指標*/ double s[80]; /*儲存當前所有的數的一個堆疊*/ int si=0; /*儲存數字位置指標*/ int k=0; /* 若k=1則表示有一對括號*/ int num=0,i=0; /*num儲存新括號內的字元數,i 儲存number裡的字元位置*/ int cc=0; /*乘除符號數量*/ int jj=0; /*加減符號數量*/ while(*c!='\0')/*當p==1 和k==0時,表示已經把括號裡的內容全部複製到g[100]中了*/ { k=0; num=0; switch(*c) { case '+': /*當前字元為+-乘除時則表示*/ case '-': case '*': case'/': f[fi++]=*c; if(*c=='*' || *c=='/') cc++; else jj++; if(*(c-1)!=')') { number[i]='\0'; i=0;/*完成一個數字的複製,其位置指標i=0*/ s[si++]=convnum(number); } break; case'(': /*有括號,則將當前括號作用範圍內的全部字元儲存,作為*/ k++; /*一個新的字元表示式進行遞迴呼叫good函式計算。*/ while(k>0) { c++; g[num]=*c; num++; if(*c==')') { k--; } else if(*c=='(') { k++; } } g[num-1]='\0'; num=0;/*完成一個括號內容的複製,其位置指標num=0*/ s[si++]=good(g); break; default: number[i++]=*c; if(*(c+1)=='\0') { number[i]='\0'; s[si++]=convnum(number); } break; } c++; } f[fi]='\0'; i=0; while(cc>0) { switch(f[i]) { case '*': cc--; s[i+1]=s[i]*s[i+1]; move(f,s,i); break; case '/': cc--; s[i+1]=s[i]/(float)s[i+1]; move(f,s,i); break; default: i++; break; } } i=0; while(jj>0) { switch(f[i]) { case '+': s[i+1]=s[i]+s[i+1]; jj--; move(f,s,i); break; case '-': s[i+1]=s[i]-s[i+1]; jj--; move(f,s,i); break; default: printf("operator error!"); break; } } return s[0]; } void main() { char str[100]; double sum=0; int p=1; while(1) { printf("enter expression: enter 'exit' end of program\n"); scanf("%s",str); p=strcmp(str,"exit"); if(p==0) break; p=check(str); if(p==0) continue; sum=good(str); printf("%s=%f",str,sum); printf("\n"); } printf("good bye!\n");
}