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

     源自《The C Programming Language》P62 pr4-2,代码位于ex4.2中:

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

   代码:

main.c
1 #include <stdio.h>
2 #include <ctype.h>
3
4 #define MAXLINE 100
5
6 int getLine(char s[], int lim);
7 double atof(char s[]);
8 int pow(int base, int expn);
9
10 int main()
11 {
12
13 char line[MAXLINE];
14 int len;
15 while((len = getLine(line, MAXLINE)) > 0)
16 printf("%f\n", atof(line));
17 //printf("the size of double: %d\n", sizeof(double));
18 //printf("the size of float: %d\n", sizeof(float));
19
20 return 0;
21 }
22
23 int getLine(char s[], int lim) //从终端获取一行字符
24 {
25
26 int i;
27 int c;
28
29 for(i = 0; --lim > 0 && (c = getchar()) != EOF && c != '\n'; ++i)
30 s[i] = c;
31 if(c == '\n')
32 s[i++] = c;
33 s[i] = '\0';
34
35 return i;
36
37 }
38
39 int pow(int base, int expn) //底数为base,指数为expn的指数求值
40 {
41
42 int i;
43 int sum;
44
45 sum = 1;
46 for(i = 0; i < expn; ++i)
47 sum = sum * base;
48
49 return sum;
50
51 }
52
53 double atof(char s[]) //将字符串s转换成double型的浮点数
54 {
55
56 int i;
57 int sign;
58 int flag;
59 int expn;
60 double val;
61 double power;
62
63 sign = 1;
64 flag = 0;
65 power = 1.0;
66 expn = 0;
67 for(i = 0; isspace(s[i]); ++i)
68 ;
69 if(s[i] == '-')
70 sign = -1;
71 if(s[i] == '+' || s[i] == '-')
72 ++i;
73 for(val = 0.0; isdigit(s[i]); ++i)
74 val = val * 10.0 + (s[i] - '0');
75 if(s[i] == '.')
76 ++i;
77 for(; isdigit(s[i]); ++i)
78 {
79 val = val * 10.0 + (s[i] - '0');
80 //power = power * 10.0;
81 ++flag;
82 }
83 if(s[i] == 'e' || s[i] == 'E') //如果写成s[i++] == 'e' || s[i++] == 'E',if(s[i] == '-')
84 //则当输入的字符串带有E时,不能正确得到结果,这是因为在一
85 //个语句中使用两次自增操作,引起歧义
86 if(s[++i] == '-')
87 {
88 ++i;
89 for(; isdigit(s[i]); ++i)
90 expn = expn * 10 + (s[i] - '0');
91 expn = expn + flag;
92 power = pow(10, expn);
93 return sign * val / power;
94 }
95 else
96 {
97 for(; isdigit(s[i]); ++i)
98 expn = expn * 10 + (s[i] - '0');
99 expn = expn - flag;
100 power = pow(10, expn);
101 return sign * val * power;
102 }
103
104 power = pow(10, flag);
105 return sign * val / power;
106
107 }
108
109
110
111 /*************************************************************************
112 参考代码:atof
113 *************************************************************************/
114 /*double atof(char s[])
115 {
116
117 int i;
118 int sign;
119 //int flag;
120 int expn;
121 double val;
122 double power;
123
124 sign = 1;
125 //flag = 0;
126 power = 1.0;
127 expn = 0;
128 for(i = 0; isspace(s[i]); ++i)
129 ;
130 if(s[i] == '-')
131 sign = -1;
132 if(s[i] == '+' || s[i] == '-')
133 ++i;
134 for(val = 0.0; isdigit(s[i]); ++i)
135 val = val * 10.0 + (s[i] - '0');
136 if(s[i] == '.')
137 ++i;
138 for(; isdigit(s[i]); ++i)
139 {
140 val = val * 10.0 + (s[i] - '0');
141 power = power * 10.0;
142 //++flag;
143 }
144 val = sign * val / power;
145
146 if(s[i] == 'e' || s[i] == 'E')
147 {
148 sign = (s[++i] == '-') ? -1 : 1;
149 if(s[i] == '+' || s[i] == '-')
150 ++i;
151 for(expn = 0; isdigit(s[i]); ++i)
152 expn = expn * 10.0 + (s[i] - '0');
153 if(sign == 1)
154 while(expn-- > 0)
155 val = val * 10.0;
156 else
157 while(expn-- > 0)
158 val = val / 10.0;
159 }
160
161 return val;
162 }*/

   分析:

     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”更精确

posted on 2011-06-01 19:43  将军之盾  阅读(1428)  评论(0编辑  收藏  举报