atof函数,可以处理科学计数法

    技术2022-05-20  38

         源自《The C Programming Language》P62 pr4-2:

        

         对atof函数进行扩充,使它能够处理形如:123.45e-6的科学表示法,其中浮点数后面可能会紧跟一个e或E以及一个指数

     

         代码:

         #include <stdio.h> #include <ctype.h> #define MAXLINE 100 int getLine(char s[], int lim); double atof(char s[]); int pow(int base, int expn); int main() { char line[MAXLINE]; int len; while((len = getLine(line, MAXLINE)) > 0) printf("%f/n", atof(line)); //printf("the size of double: %d/n", sizeof(double)); //printf("the size of float: %d/n", sizeof(float)); return 0; } int getLine(char s[], int lim) //从终端获取一行字符 { int i; int c; for(i = 0; --lim > 0 && (c = getchar()) != EOF && c != '/n'; ++i) s[i] = c; if(c == '/n') s[i++] = c; s[i] = '/0'; return i; } int pow(int base, int expn) //底数为base,指数为expn的指数求值 { int i; int sum; sum = 1; for(i = 0; i < expn; ++i) sum = sum * base; return sum; } double atof(char s[]) //将字符串s转换成double型的浮点数 { int i; int sign; int flag; int expn; double val; double power; sign = 1; flag = 0; power = 1.0; expn = 0; for(i = 0; isspace(s[i]); ++i) ; if(s[i] == '-') sign = -1; if(s[i] == '+' || s[i] == '-') ++i; for(val = 0.0; isdigit(s[i]); ++i) val = val * 10.0 + (s[i] - '0'); if(s[i] == '.') ++i; for(; isdigit(s[i]); ++i) { val = val * 10.0 + (s[i] - '0'); //power = power * 10.0; ++flag; } if(s[i] == 'e' || s[i] == 'E') //如果写成s[i++] == 'e' || s[i++] == 'E',if(s[i] == '-') //则当输入的字符串带有E时,不能正确得到结果,这是因为在一 //个语句中使用两次自增操作,引起歧义 if(s[++i] == '-') { ++i; for(; isdigit(s[i]); ++i) expn = expn * 10 + (s[i] - '0'); expn = expn + flag; power = pow(10, expn); return sign * val / power; } else { for(; isdigit(s[i]); ++i) expn = expn * 10 + (s[i] - '0'); expn = expn - flag; power = pow(10, expn); return sign * val * power; } power = pow(10, flag); return sign * val / power; } /************************************************************************* 参考代码:atof *************************************************************************/ /*double atof(char s[]) { int i; int sign; //int flag; int expn; double val; double power; sign = 1; //flag = 0; power = 1.0; expn = 0; for(i = 0; isspace(s[i]); ++i) ; if(s[i] == '-') sign = -1; if(s[i] == '+' || s[i] == '-') ++i; for(val = 0.0; isdigit(s[i]); ++i) val = val * 10.0 + (s[i] - '0'); if(s[i] == '.') ++i; for(; isdigit(s[i]); ++i) { val = val * 10.0 + (s[i] - '0'); power = power * 10.0; //++flag; } val = sign * val / power; if(s[i] == 'e' || s[i] == 'E') { sign = (s[++i] == '-') ? -1 : 1; if(s[i] == '+' || s[i] == '-') ++i; for(expn = 0; isdigit(s[i]); ++i) expn = expn * 10.0 + (s[i] - '0'); if(sign == 1) while(expn-- > 0) val = val * 10.0; else while(expn-- > 0) val = val / 10.0; } return val; }*/

         分析:

         1,  if(s[i] == 'e' || s[i] == 'E')中,如果写成s[i++] == 'e' || s[i++] == 'E',if(s[i] == '-')

              则当输入的字符串带有E时,不能正确得到结果,这是因为在一个语句中使用两次自增操作,引起歧义

     

         2,  当处理含有e或E情况时,参考的atof函数代码比自定义的atof函数的代码要简洁,直观

     

         3,  在参考的atof函数中,用val去除10而不是用val乘以0.1的原因:0.1无法用二进制数精确地表示出来,大多数机器上

              0.1的二进制表示法都要比0.1稍微小一点,用10.0乘以0.1并不能精确地得到1.0,虽然两种做法都有误差,但是

              连续的“除以10”比连续的“乘以0.1”更精确

     

     


    最新回复(0)