1. 程式人生 > >C++ 字串轉換為浮點數時的精度問題

C++ 字串轉換為浮點數時的精度問題

#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");

}