感悟!
0、本题有一个勘误(并且恰好包含15位有效数字),更正为 小数点后恰好有15位数字,附上原文(英文)
and will have exactly 15 digits after the decimal point.
1、学习double越界处理,采用log10降级处理。
2、认识到计算机处理double、float数据存在误差,(失之毫厘,谬以千里)。
double,float对于逻辑运算符==基本无用。两数是否相等,应采用如fabs(a-b)<1e-6的方式。
int数据的逻辑处理十分简便,故逻辑运算时,我们大量看到的是int数据的处理。
3、第一次看到了,有限结果的建表查询方式。
4、学习了,字符串转数字的读取技巧。
5、编写程序,不能等到全部写完,再来排错,应该写一小段,printf跟踪一段,能极大提高编码成功率与效率。
6、阅读他人代码,有一些心得,解决同一个问题,行数较少的代码比行数较多的代码更容易读懂。
展示给读者的代码越短越好(在容易理解的基础上),建议删除其中的测试代码,增加其中的注释代码。
7、编码尽可能的会写注释了,保证遗忘后,又能很快的把程序拾起。
8、编码水平又提高了一步。
以下是编码,参考了许多作者,在此一并感谢。
环境Dev-cpp4.9.9.2
#include <stdio.h>
#include <math.h>
#include <string.h>
struct mykey{
double a;
int b;
};
struct mykey table[10][31];
char s[100];
const double EPS=1e-6;
int main(){
int i,j,b,flag;
double a1,b1,t,a;
//i对应尾数为1的个数,j对应阶码为1的个数
for(i=0;i<=9;i++){
for(j=1;j<=30;j++){//以0.998046875*2^63转化为9.205357638345294*10^18为例,对应的i=8,j=6
a1=1-pow(2,-i-1);//十进制的尾数 0.998046875
b1=pow(2,j)-1;//十进制的阶码 63
t=log10(a1)+b1*log10(2);// log10(0.998046875*2^63)=log10(0.998046875)+63*log10(2)
table[i][j].b=(int)t;//18
table[i][j].a=pow(10,(t-table[i][j].b));//9.205357638345294
}
}
while(scanf("%s",s)==1){//将字符串读取,处理成相应数字
if(strcmp("0e0",s)==0)//Uva11809对跳出while无判断,即有无判断0e0,程序都能AC,感兴趣的读者可以试一试.
break;
a=s[0]-'0';//该数为个位数
for(i=2;i<=16;i++){//i=1是小数点,故从i=2开始
a+=(s[i]-'0')*pow(10,-i+1);//如十分位为*10^-1,百分位为*10^-2
}
b=0;
for(i=18;i<strlen(s);i++){
b+=(int)((s[i]-'0')*pow(10,strlen(s)-1-i));//如个位为*10^0,十位为*10^1,百位为*10^2
}
flag=0;
for(i=0;i<=9;i++){
for(j=1;j<=30;j++){
if(fabs(a-table[i][j].a)<EPS&&b==table[i][j].b){//查表,注意double数据比较方式,int数据比较方式
printf("%d %d\n",i,j);
flag=1;
break;//跳出内层的for(j=1......
}
}
if(flag)
break;//跳出外层的for(i=0......
}
}
return 0;
}