您的位置:首页 > 其它

算法竞赛入门经典(第2版)习题3-12 浮点数 Floating-Point Numbers UVa11809

2014-07-21 09:41 405 查看
这题有点逼近我的智商上限了,看了好几遍才明白大概意思。编程的时候脑子里一直有点乱,卡了我将近一周,代码整体重写了三次。每次都可以实现样例,但是一直WA。

本来都打算跳过去了,但总是有点不甘心。

决定尝试最后一次:把所有可能情况的输入数据都算出来当做测试数据,最终发现WA是由于浮点数转换成整数时的系统误差导致的。

印象里书中样例曾经在浮点数转换整数时+0.5,我这里没有这样做

结果在某个测试样例中double 1.0000000*1000000000转换为整数的结果成了999999999,最终导致WA。

修改了这个bug后,顺利ac。

思路如下:

1.利用10^1=1.25*2^3逐级推算出1<=n<=10时10^n与2^m的换算公式组

2.推算出0<=M<=9各值时所有的十进制小数尾数,得到M表

3.推算出1<=E<=30各值时所有的2的十进制阶数,得到E表

4.读入s串并分割,把输入尾数存在double ap中,阶码存在int B中

5.利用第一步中求出的公式把10^int B转换为中转十进制浮点数double zz*(2^int E)其中1<=zz<2

6.计算出中转十进制浮点数zz* ap 结果存入 double apzz,其中0.5<=apzz<1,并修正E值

7.用apzz在M表中查询,得到M值

8.用E在E表中查询,得到E值

//#define LOCAL
//#define TESTING
#include<stdio.h>
#include<math.h>
#include<string.h>
#define MAXN 1000

char s[25];
long DM[10];

int main()
{
#ifdef LOCAL
freopen("xt3-12.in","r",stdin);
freopen("xt3-12-1.out","w",stdout);
#endif
//计算10^(10^n)=double zw[]*2^long long zj[]公式组
#ifdef TESTING
printf("计算10^(10^n)=double zw[]*2^long long zj[]公式组\n");
#endif
long long zj[10];
double zw[10] ;
int tempz=1;
memset(zj,0,sizeof(zj));
memset(zw,0,sizeof(zw));
zj[0]=3;
zw[0]=1.25;
for(int i = 1; i<=9; i++)
{
zj[i] = 10*zj[i-1];
zw[i] = pow(zw[i-1],10);
for(int j = 0; j < 10; j++)
{
if(zw[i]>2)
{
zw[i]/=2;
zj[i]++;
}
else break;
}
tempz *= 10;
}
for(int i = 1; i<=9; i++)
{
#ifdef TESTING
printf("10^(10^%d)=zw[%d]%.15lf*2^zj[%d]%lld\n", i,i,zw[i],i, zj[i]);
#endif
}
//计算结束

//求M表
#ifdef TESTING
printf("可能的十进制m值\n");
#endif
double m[15];
memset(m,0,sizeof(m));
for(int i = 0; i <= 9; i++)
{
m[i]=(pow(2,i+1)-1.0)/pow(2,i+1);
#ifdef TESTING
printf("m[%d]=%.15lf\n", i, m[i]);
#endif
}
//求M表结束
//求e表
long long e[35];
e[0]=0;
e[1]=1;
for(int i = 2; i<=30	;i++)
{
e[i]=e[i-1]+pow(2,i-1);
}
#ifdef TESTING
printf("e表,2^E\n");
for(int i = 0; i<=30;i++) printf("2^E[%d]=2^%ld\n", i, e[i]);
#endif
//求e表结束
#ifdef TESTING
int T = 1;
#endif
while(scanf("%s",s)!=EOF)
{
int A,a[15],C,c[15],len;
long long E,B=0;
double ap = 0,zz;
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
//将s串分割,把尾数存在double ap中,阶码存在int B中
len = strlen(s);
if((s[0]=='0')&&(s[1]=='e')&&(s[2]=='0')) break;
A = s[0]-'0';
for(int i = 0; i<15; i++)
{
a[i] = s[16-i]-'0';
ap = (ap+a[i])/10.0;
}
ap += A;
for(int i = 0; i<(len-18); i++)
{
B *= 10;
B += s[i+18]-'0';
}
//分割保存结束

//把10^B转换为中转十进制浮点数D:zz*(2^E)
#ifdef TESTING
printf("\nCase:%d\n把10^B转换为中转十进制浮点数D:zz*(2^E)\n",T++);
#endif
E = 0;
zz = 1.0;
int tempB,ij = 0;
tempB = B;
while(tempB!=0)
{

E+=zj[ij]*(tempB%10);
zz *= pow(zw[ij],tempB%10);
while(zz>2)
{
zz /= 2;
E++;
}
#ifdef TESTING
printf("E=%lld zz=%.15lf tempB=%d tempB%10=%d\n", E, zz,tempB,tempB%10);
#endif
tempB=tempB/10;
ij++;
}
#ifdef TESTING
printf("E=%lld zz=%.15lf B=%lld\n", E, zz,B);
#endif
//转换结束

//计算 中转十进制浮点数D:zz* ap 结果存入 0.double apzz
//(intC.int c[ ]*(2^E)=A.a[]*(10^B))
double zz2,apzz;
if(zz>0)
{
apzz = ap * zz;
int tempapzz=apzz*10000000+0.5;
while(tempapzz>=10000000)
{
apzz /= 2;
tempapzz /=2;
E++;
#ifdef TESTING
printf("tempapzz=%d apzz=%.15lf\n", tempapzz,apzz);
printf("\n");
#endif
}
}
#ifdef TESTING
printf("apzz:%.15lf E:%lld\n", apzz,E);
printf("len=%d s=%s\n", len, s);
printf("s=%.15lfe%lld\n", ap,B);
printf("\n");
#endif
//计算结束

//根据apzz查M表 确认M值 输出
long long tempm,M;
tempm = apzz*10000000;
for(int i = 0; i < 10; i++)
{
#ifdef TESTING
printf("tempm=%lld m[%d]=%.15lf\n",tempm,i,m[i]);
#endif
int tempmi = m[i]*10000000;
if(tempm == tempmi)
{
M = i;
break;
}
}
printf("%d ", M);
//根据apzz查M表 确认M值 输出 结束

//根据E查e表 确认e值 输出
for(int i = 0; i <= 30; i++)
{
if(E==e[i])
{
printf("%d\n",i);
break;
}
}
//根据E查e表 确认e值 输出 结束
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: